c++/clr StructureToPtr Stack buffer overflow - c++-cli

as I have asked in this question c++/clr StructureToPtr exit application without any exception or error
and thanks to the comment, I found out the exit code is -1073740791, which means Stack buffer overflow / overrun. So let me post my two structures,
[StructLayout(LayoutKind::Sequential)]
public ref struct ThostFtdcInputOrderField
{
[MarshalAs(UnmanagedType::ByValTStr, SizeConst = 11)]
String^ BrokerID;
[MarshalAs(UnmanagedType::ByValTStr, SizeConst = 13)]
String^ InvestorID;
[MarshalAs(UnmanagedType::ByValTStr, SizeConst = 31)]
String^ InstrumentID;
[MarshalAs(UnmanagedType::ByValTStr, SizeConst = 13)]
String^ OrderRef;
[MarshalAs(UnmanagedType::ByValTStr, SizeConst = 16)]
String^ UserID;
EnumOrderPriceTypeType OrderPriceType;
EnumDirectionType Direction;
EnumOffsetFlagType CombOffsetFlag;
EnumOffsetFlagType CombHedgeFlag;
double LimitPrice;
int VolumeTotalOriginal;
EnumTimeConditionType TimeCondition;
[MarshalAs(UnmanagedType::ByValTStr, SizeConst = 9)]
String^ GTDDate;
EnumVolumeConditionType VolumeCondition;
int MinVolume;
EnumContingentConditionType ContingentCondition;
double StopPrice;
EnumForceCloseReasonType ForceCloseReason;
int IsAutoSuspend;
[MarshalAs(UnmanagedType::ByValTStr, SizeConst = 21)]
String^ BusinessUnit;
int RequestID;
int UserForceClose;
};
The Enums
public enum struct EnumOrderPriceTypeType
{
AnyPrice = (Byte)'1',
LimitPrice = (Byte)'2',
BestPrice = (Byte)'3',
LastPrice = (Byte)'4',
LastPricePlusOneTicks = (Byte)'5',
LastPricePlusTwoTicks = (Byte)'6',
LastPricePlusThreeTicks = (Byte)'7',
AskPrice1 = (Byte)'8',
AskPrice1PlusOneTicks = (Byte)'9',
AskPrice1PlusTwoTicks = (Byte)'A',
AskPrice1PlusThreeTicks = (Byte)'B',
BidPrice1 = (Byte)'C',
BidPrice1PlusOneTicks = (Byte)'D',
BidPrice1PlusTwoTicks = (Byte)'E',
BidPrice1PlusThreeTicks = (Byte)'F'
};
public enum struct EnumDirectionType
{
Buy = (Byte)'0',
Sell = (Byte)'1'
};
public enum struct EnumOffsetFlagType
{
Open = (Byte)'0',
Close = (Byte)'1',
ForceClose = (Byte)'2',
CloseToday = (Byte)'3',
CloseYesterday = (Byte)'4',
ForceOff = (Byte)'5',
LocalForceClose = (Byte)'6'
};
public enum struct EnumTimeConditionType
{
IOC = (Byte)'1',
GFS = (Byte)'2',
GFD = (Byte)'3',
GTD = (Byte)'4',
GTC = (Byte)'5',
GFA = (Byte)'6'
};
public enum struct EnumVolumeConditionType
{
AV = (Byte)'1',
MV = (Byte)'2',
CV = (Byte)'3'
};
public enum struct EnumContingentConditionType
{
Immediately = (Byte)'1',
Touch = (Byte)'2',
TouchProfit = (Byte)'3',
ParkedOrder = (Byte)'4',
LastPriceGreaterThanStopPrice = (Byte)'5',
LastPriceGreaterEqualStopPrice = (Byte)'6',
LastPriceLesserThanStopPrice = (Byte)'7',
LastPriceLesserEqualStopPrice = (Byte)'8',
AskPriceGreaterThanStopPrice = (Byte)'9',
AskPriceGreaterEqualStopPrice = (Byte)'A',
AskPriceLesserThanStopPrice = (Byte)'B',
AskPriceLesserEqualStopPrice = (Byte)'C',
BidPriceGreaterThanStopPrice = (Byte)'D',
BidPriceGreaterEqualStopPrice = (Byte)'E',
BidPriceLesserThanStopPrice = (Byte)'F',
BidPriceLesserEqualStopPrice = (Byte)'H'
};
public enum struct EnumForceCloseReasonType
{
NotForceClose = (Byte)'0',
LackDeposit = (Byte)'1',
ClientOverPositionLimit = (Byte)'2',
MemberOverPositionLimit = (Byte)'3',
NotMultiple = (Byte)'4',
Violation = (Byte)'5',
Other = (Byte)'6',
PersonDeliv = (Byte)'7'
};
The C++ struct
struct CThostFtdcInputOrderField
{
TThostFtdcBrokerIDType BrokerID;
TThostFtdcInvestorIDType InvestorID;
TThostFtdcInstrumentIDType InstrumentID;
TThostFtdcOrderRefType OrderRef;
TThostFtdcUserIDType UserID;
TThostFtdcOrderPriceTypeType OrderPriceType;
TThostFtdcDirectionType Direction;
TThostFtdcCombOffsetFlagType CombOffsetFlag;
TThostFtdcCombHedgeFlagType CombHedgeFlag;
TThostFtdcPriceType LimitPrice;
TThostFtdcVolumeType VolumeTotalOriginal;
TThostFtdcTimeConditionType TimeCondition;
TThostFtdcDateType GTDDate;
TThostFtdcVolumeConditionType VolumeCondition;
TThostFtdcVolumeType MinVolume;
TThostFtdcContingentConditionType ContingentCondition;
TThostFtdcPriceType StopPrice;
TThostFtdcForceCloseReasonType ForceCloseReason;
TThostFtdcBoolType IsAutoSuspend;
TThostFtdcBusinessUnitType BusinessUnit;
TThostFtdcRequestIDType RequestID;
TThostFtdcBoolType UserForceClose;
};
The types
typedef char TThostFtdcBrokerIDType[11];
typedef char TThostFtdcInvestorIDType[13];
typedef char TThostFtdcInstrumentIDType[31];
typedef char TThostFtdcOrderRefType[13];
typedef char TThostFtdcUserIDType[16];
typedef char TThostFtdcOrderPriceTypeType;
typedef char TThostFtdcDirectionType;
typedef char TThostFtdcCombOffsetFlagType[5];
typedef char TThostFtdcCombHedgeFlagType[5];
typedef double TThostFtdcPriceType;
typedef int TThostFtdcVolumeType;
typedef char TThostFtdcTimeConditionType;
typedef char TThostFtdcDateType[9];
typedef char TThostFtdcVolumeConditionType;
typedef char TThostFtdcContingentConditionType;
typedef char TThostFtdcForceCloseReasonType;.
typedef int TThostFtdcBoolType;
typedef char TThostFtdcBusinessUnitType[21];
typedef int TThostFtdcRequestIDType;
typedef int TThostFtdcBoolType;
As I dont know much of c++, so I have present the whole demo I was given. The demo calls this function to do the transform,
class MNConv
{
public:
/// Native to Managed
static M N2M(N* pNative){
return safe_cast<M>(Marshal::PtrToStructure(IntPtr(pNative), M::typeid));
};
// Managed to Native
static void M2N(M managed, N* pNative){
Marshal::StructureToPtr(managed, IntPtr(pNative), true);
};
};
MNConv<ThostFtdcInputOrderField^, CThostFtdcInputOrderField>::M2N(pInputOrder, &native);
The problem is this exit with exit code is -1073740791, with no exception. I am not sure what went wrong, as the same demo actually convert a few other structure with success.

When you use UnmanagedType::ByValTStr you MUST also specify the encoding.
Because your C++ typedef lines all use char, not wchar_t, you need
[StructLayout(LayoutKind::Sequential, CharSet = CharSet::Ansi)]
If the marshaller incorrectly uses Unicode, it will write twice as much data for each string as it should, overflowing the buffer and corrupting nearby memory.

Related

'cli::interior_ptr<const wchar_t> PtrToStringChars(__const_String_handle)': cannot convert argument 1 from 'SystemString *' to '__const_String_handle'

I am working on an old project, and no developer is available for that project. I have added cstringt.inl file, as it was required and was not present in project folder. Now when I try to build it, I am getting an error, as described in the title and attached image.
In Cstringt.h file below is the constructor:
template<class SystemString>
CStringT( SystemString * pString ) :
CThisSimpleString( StringTraits::GetDefaultManager() )
{
const wchar_t __pin* psz = PtrToStringChars( pString );
*this = psz;
}
And here pString is of type SystemString *. Now, when I use it in PtrToStringChars( pString), it requires a different type.
#ifdef __cplusplus_cli
typedef cli::interior_ptr<const System::Char> __const_Char_ptr;
typedef cli::interior_ptr<const System::Byte> __const_Byte_ptr;
typedef cli::interior_ptr<System::Byte> _Byte_ptr;
typedef const System::String^ __const_String_handle;
#define _NULLPTR nullptr
#else
typedef const System::Char* __const_Char_ptr;
typedef const System::Byte* __const_Byte_ptr;
typedef System::Byte* _Byte_ptr;
typedef const System::String* __const_String_handle;
#define _NULLPTR 0
#endif
inline __const_Char_ptr PtrToStringChars(__const_String_handle s) {
_Byte_ptr bp = const_cast<_Byte_ptr>(reinterpret_cast<__const_Byte_ptr>(s));
if( bp != _NULLPTR ) {
bp += System::Runtime::CompilerServices::RuntimeHelpers::OffsetToStringData;
}
return reinterpret_cast<__const_Char_ptr>(bp);
}
I am not able to understand the type: typedef const System::String^ __const_String_handle;
How to convert the type from SystemString * to typedef const System::String^ __const_String_handle;?

Marshaling a reference to a char** array

I am having trouble marshaling an array of char* by reference. The data is filled in correctly on the C++ unmanaged side. But when its returned by referernce to the managed side, I end up with a single pointer to the first array element.
//The function in C++
extern "C" DATAACCESSLAYERDLL_API void __stdcall DB_SchemaField_GetKeyValues(Schema::TSchemaFieldHandle hField, const char** &keys, const char ** &values)
{
Schema::CSchemaField *pField = CDataObjectFactory::GetObjectTpl<Schema::CSchemaField>(hField);
if (!pField) return;
Schema::TSchemaKeyValuePair::iterator itor = pField->GetKeyValues().begin();
int index = 0;
for (itor; itor != pField->GetKeyValues().end(); ++itor)
{
keys[index] = (*itor).first.c_str();
values[index] = (*itor).second.c_str();
index++;
}
return;
}
The pInvoke declaration
[System.Security.SuppressUnmanagedCodeSecurity()]
[DllImport("DataCore.dll")]
static private extern void DB_SchemaField_GetKeyValues(Int64 pField,
[In, Out] ref IntPtr[] keys, [In, Out] ref IntPtr[] values);
And finally.... the code which marshals
int keyValueCount = DB_SchemaField_GetKeyValuesCount(GetHandle());
if (keyValueCount > 0)
{
IntPtr[] KeysPtr = new IntPtr[keyValueCount];
IntPtr[] ValuesPtr = new IntPtr[keyValueCount];
DB_SchemaField_GetKeyValues(GetHandle(), ref KeysPtr, ref ValuesPtr);
for (int i = 0; i < keyValueCount; i++)
{
string key = Marshal.PtrToStringAnsi(KeysPtr[i]);
string value = Marshal.PtrToStringAnsi(ValuesPtr[i]);
if (!String.IsNullOrEmpty(key))
{
KeyValues.Add(key, value);
}
}
}
It is a mistake to pass the two const char* arrays by reference. That's one level of indirection too far for the marshaller. You need the following:
C++
extern "C" DATAACCESSLAYERDLL_API void __stdcall DB_SchemaField_GetKeyValues(
Schema::TSchemaFieldHandle hField, const char** keys, const char ** values)
C#
[System.Security.SuppressUnmanagedCodeSecurity()]
[DllImport("DataCore.dll")]
static private extern void DB_SchemaField_GetKeyValues(Int64 pField,
[Out] IntPtr[] keys, [Out] IntPtr[] values);
You'd better make sure you use the pointers that are returned immediately, because the C string returned by c_str() is only valid until the next modification of the std::string object.

PInvoke - Issue while calling DJVU function from C# code. Attempted to read or write protected memory

UPDATE 3-4-15:11IS
As recommended by David modified PInvoke as below, this time I am getting different error "Unhandled exception of type System.ExecutionEngineException occurred in mscorlib.dll"
[DllImport("C:\\Program Files\\DJVULIBRE\\LIBDJVULIBRE.dll", CharSet=CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
private unsafe static extern int ddjvu_page_render(IntPtr page, ddjvu_render_mode_t mode, ref ddjvu_rect_t pagerect,
ref ddjvu_rect_t renderrect,
IntPtr pixelformat,
uint rowsize,
[Out][MarshalAs(UnmanagedType.LPArray)]byte[] imagebuffer);
Thanks David for your valuable time, I think is close to a fix.
HISTORY
I know there are many questions in this subject but none of them help to resolve the issue I am currently facing.
Below is the API function in C Language
DDJVUAPI int
ddjvu_page_render(ddjvu_page_t *page,
const ddjvu_render_mode_t mode,
const ddjvu_rect_t *pagerect,
const ddjvu_rect_t *renderrect,
const ddjvu_format_t *pixelformat,
unsigned long rowsize,
char *imagebuffer );
Below is the PInvoke signature of C Function added in .NET code
[DllImport("C:\\Program Files\\DJVULIBRE\\LIBDJVULIBRE.dll", CharSet=CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
private unsafe static extern int ddjvu_page_render(IntPtr page, ddjvu_render_mode_t mode, IntPtr pagerect,
IntPtr renderrect,
IntPtr pixelformat,
ulong rowsize,
[Out][MarshalAs(UnmanagedType.LPArray)]byte[] imagebuffer);
Below is how I am calling this function in the c# code
byte* buffer = (byte *)Memory.Alloc(nSize);
try
{
IntPtr ptr1 = (IntPtr)Memory.Alloc(Marshal.SizeOf(prect));
Marshal.StructureToPtr(prect, ptr1, false);
IntPtr ptr2 = (IntPtr)Memory.Alloc(Marshal.SizeOf(rrect));
Marshal.StructureToPtr(rrect, ptr2, false);
byte[] array = new byte[nSize];
fixed (byte* p = array) Memory.Copy(buffer, p, nSize);
ddjvu_page_render(page, ddjvu_render_mode_t.DDJVU_RENDER_MASKONLY, ptr1, ptr2, fmt, (ulong)stride, array);
}
finally
{
Memory.Free(buffer);
}
call to ddjvu_page_render in above code is throwing "Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
Prior to this post I must have tried all the option could find in various blogs.
Appreciate any help, is almost a day I am clueless, your timely help could save my job
UPDATE 3-4-15:7:44IS
This code is using DJVULibre
UPDATE 3-4-15:8:35IS
Here is the code I have in Form Load
ctx = ddjvu_context_create(System.AppDomain.CurrentDomain.FriendlyName);
if (ctx != null)
{
string djFile = "C:\\Users\\rammohan.chavakula\\Documents\\eiasample.djvu";
doc = ddjvu_document_create_by_filename(ctx, djFile, 100);
if (doc != null)
{
while (ddjvu_job_status(ddjvu_document_job(doc)) >= ddjvu_status_t.DDJVU_JOB_OK)
SpinDdjvuMessageLoop(ctx, true);
int pageCount = ddjvu_document_get_pagenum(doc);
mediaboxes = new Rectangle[pageCount];
for (int i = 0; i < pageCount; i++)
{
ddjvu_status_t status;
ddjvu_pageinfo_t info = new ddjvu_pageinfo_t();
while ((status = ddjvu_document_get_pageinfo_imp(doc, i, ref info, (uint)System.Runtime.InteropServices.Marshal.SizeOf(info))) < ddjvu_status_t.DDJVU_JOB_OK)
SpinDdjvuMessageLoop(ctx, true);
if (status != ddjvu_status_t.DDJVU_JOB_OK)
continue;
mediaboxes[i] = new Rectangle(0, 0, info.width / info.dpi,
info.height / info.dpi);
}
}
ddjvu_context_release(ctx);
}
In OnPaint function I have this below code
if (doc == null)
{
base.OnPaint(e);
return;
}
Rectangle pageRc = PageMediabox(1);
Rectangle screen = Transform(pageRc, 1, zoom, rotation, false);
Rectangle full = Transform(PageMediabox(1), 1, zoom, rotation, false);
full.Intersect(screen);
IntPtr page = ddjvu_page_create_by_pageno(doc, 1);
if (page == null )
{
base.OnPaint(e);
return;
}
int rotation4 = (((-rotation / 90) % 4) + 4) % 4;
ddjvu_page_set_rotation(page, (ddjvu_page_rotation_t)rotation4);
while (ddjvu_job_status(ddjvu_page_job(page)) >= ddjvu_status_t.DDJVU_JOB_OK)
SpinDdjvuMessageLoop(ctx, true);
if (ddjvu_job_status(ddjvu_page_job(page)) >= ddjvu_status_t.DDJVU_JOB_FAILED)
{
base.OnPaint(e);
return;
}
IntPtr fmt = ddjvu_format_create(ddjvu_format_style_t.DDJVU_FORMAT_BGR24, 0, (UIntPtr)null);
ddjvu_format_set_row_order(fmt, /* top_to_bottom */1);
ddjvu_rect_t prect = new ddjvu_rect_t(full.X, full.Y, (uint)full.Width, (uint)full.Height);
ddjvu_rect_t rrect = new ddjvu_rect_t(screen.X, 2 * full.Y + screen.Y + full.Height - screen.Height, (uint)screen.Width, (uint)screen.Height);
int stride = ((screen.Width * 3 + 3) / 4) * 4;
//byte tmp;
////ScopedMem<char> bmpData(SAZA(char, stride * (screen.dy + 5)));
//for (int y = 0; y < rrect.h; y++) {
// int step_y = y * SCREEN_WIDTH;
// for (int x=0; x < rrect.w; x++) {
// tmp = (byte)((imagebuf[x + step_y] >> 5) << 5);
// }
//}
int rowsize = mediaboxes[0].Width * 3;
int nSize = rowsize * (mediaboxes[0].Height) * 10;
unsafe
{
byte* buffer = (byte *)Memory.Alloc(nSize);
try
{
IntPtr ptr1 = (IntPtr)Memory.Alloc(Marshal.SizeOf(prect));
Marshal.StructureToPtr(prect, ptr1, false);
IntPtr ptr2 = (IntPtr)Memory.Alloc(Marshal.SizeOf(rrect));
Marshal.StructureToPtr(rrect, ptr2, false);
byte[] array = new byte[nSize];
fixed (byte* p = array) Memory.Copy(buffer, p, nSize);
ddjvu_page_render(page, ddjvu_render_mode_t.DDJVU_RENDER_MASKONLY, ptr1, ptr2, fmt, (ulong)stride, array);
}
finally
{
Memory.Free(buffer);
}
ddjvu_page_render should return arbitrary data of page which is to be rendered in a given rectangle area. Once after that I should be able to create image from arbitrary data & display in the screen
Here's how I would write the p/invoke:
[DllImport(dllname, CharSet=CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
private static extern int ddjvu_page_render(
[In] IntPtr page,
[In] ddjvu_render_mode_t mode,
[In] ref ddjvu_rect_t pagerect,
[In] ref ddjvu_rect_t renderrect,
[In] ref ddjvu_format_t pixelformat,
[In] uint rowsize,
[Out] byte[] imagebuffer
);
Note that I've stopped using unsafe, and am letting the marshaler handle the structs automatically.
There are quite a few assumptions here that I cannot verify:
The calling convention. It might not be cdecl. The C++ header will would have the definitive answer.
The first parameter is a void* handle type, I presume.
ddjvu_render_mode_t is an enum that you have translated correctly.
The three ref parameters are structs, passed by reference. I cannot check that you have translated them correctly.
Calling this function would be something like this:
byte[] imagebuffer = new byte[nSize];
int retval = ddjvu_page_render(
page,
ddjvu_render_mode_t.DDJVU_RENDER_MASKONLY,
ref prect,
ref rrect,
ref fmt,
(uint)stride,
imagebuffer
);
if (retval != ??)
// handle error
This is quite a broad brush answer. I hope it points you in the right direction. I don't think that all your problems will be solved by this.

Mapping DataType from C (Unmanaged) to C# (Managed)

I need to get Data from a C DLL to a C# Application. Here is the error :
Cannot marshal field 'Counters' of type 'KnittingWago.Common.WAGO_DATA_TO_USER_T': Invalid managed/unmanaged type combination (Array fields must be paired with ByValArray or SafeArray).
Here is the DLL .h
#define WAGO_NB_COUNTERS_C 80
#define WAGO_NB_ENCODERS_C 10
struct WAGO_DATA_TO_USER_T
{
unsigned int Counters[WAGO_NB_COUNTERS_C];
int Encoders[WAGO_NB_ENCODERS_C];
unsigned int Weight;
bool CalibrationValid;
bool LastCalibrationFailed;
};
Here is the C# Struct declaration :
const int WAGO_NB_COUNTERS_C = 80;
const int WAGO_NB_ENCODERS_C = 10;
struct WAGO_DATA_TO_USER_T
{
[MarshalAs(UnmanagedType.U4, SizeConst = GlobalConstant.WAGO_NB_COUNTERS_C)]
UInt32[] Counters;
[MarshalAs(UnmanagedType.I4, SizeConst = GlobalConstant.WAGO_NB_ENCODERS_C)]
Int32[] Encoders;
UInt32 Weight;
Boolean CalibrationValid;
Boolean LastCalibrationFailed;
};
How do I declare the C# struct to get the rigth data without error ?
Thanks
EDIT :
I've rewrite the Struct as :
internal struct WAGO_DATA_TO_USER_T
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = GlobalConstant.WAGO_NB_COUNTERS_C)]
UInt32[] Counters;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = GlobalConstant.WAGO_NB_ENCODERS_C)]
Int32[] Encoders;
UInt32 Weight;
Boolean CalibrationValid;
Boolean LastCalibrationFailed;
};
No more Error, but the Values are not as expected.
Should be like :
Counter[0] = ~ 5000
Counter[1] = ~ 30000
Counter[2-79] = 0
Really are :
Counter[0] = 40
Counter[1] = 1080228
Counter[2] = 82964616
Counter[3-79] = All have a non-zero value
The Marshalling was correct but the Device I was calling was not initialized by the external unmanaged dll. So I was reading uninitialisez memory that lead to that unvalid data

Creating a custom CFType

Is it possible to create opaque types not derived from CFTypeRef which can be retained/released with CFRetain/CFRelease? Or how do I derive a new type from a CFType?
I've never done this, but it is possible using private API. In all likelihood it will be dependent on a specific dot release of OS X, since the CF runtime could change from release to release. In any case, CF is open source so I took a look at what CFRuntime does. I was happy to see Apple included an example:
// ========================= EXAMPLE =========================
// Example: EXRange -- a "range" object, which keeps the starting
// location and length of the range. ("EX" as in "EXample").
// ---- API ----
typedef const struct __EXRange * EXRangeRef;
CFTypeID EXRangeGetTypeID(void);
EXRangeRef EXRangeCreate(CFAllocatorRef allocator, uint32_t location, uint32_t length);
uint32_t EXRangeGetLocation(EXRangeRef rangeref);
uint32_t EXRangeGetLength(EXRangeRef rangeref);
// ---- implementation ----
#include <CoreFoundation/CFBase.h>
#include <CoreFoundation/CFString.h>
struct __EXRange {
CFRuntimeBase _base;
uint32_t _location;
uint32_t _length;
};
static Boolean __EXRangeEqual(CFTypeRef cf1, CFTypeRef cf2) {
EXRangeRef rangeref1 = (EXRangeRef)cf1;
EXRangeRef rangeref2 = (EXRangeRef)cf2;
if (rangeref1->_location != rangeref2->_location) return false;
if (rangeref1->_length != rangeref2->_length) return false;
return true;
}
static CFHashCode __EXRangeHash(CFTypeRef cf) {
EXRangeRef rangeref = (EXRangeRef)cf;
return (CFHashCode)(rangeref->_location + rangeref->_length);
}
static CFStringRef __EXRangeCopyFormattingDesc(CFTypeRef cf, CFDictionaryRef formatOpts) {
EXRangeRef rangeref = (EXRangeRef)cf;
return CFStringCreateWithFormat(CFGetAllocator(rangeref), formatOpts,
CFSTR("[%u, %u)"),
rangeref->_location,
rangeref->_location + rangeref->_length);
}
static CFStringRef __EXRangeCopyDebugDesc(CFTypeRef cf) {
EXRangeRef rangeref = (EXRangeRef)cf;
return CFStringCreateWithFormat(CFGetAllocator(rangeref), NULL,
CFSTR("<EXRange %p [%p]>{loc = %u, len = %u}"),
rangeref,
CFGetAllocator(rangeref),
rangeref->_location,
rangeref->_length);
}
static void __EXRangeEXRangeFinalize(CFTypeRef cf) {
EXRangeRef rangeref = (EXRangeRef)cf;
// nothing to finalize
}
static CFTypeID _kEXRangeID = _kCFRuntimeNotATypeID;
static CFRuntimeClass _kEXRangeClass = {0};
/* Something external to this file is assumed to call this
* before the EXRange class is used.
*/
void __EXRangeClassInitialize(void) {
_kEXRangeClass.version = 0;
_kEXRangeClass.className = "EXRange";
_kEXRangeClass.init = NULL;
_kEXRangeClass.copy = NULL;
_kEXRangeClass.finalize = __EXRangeEXRangeFinalize;
_kEXRangeClass.equal = __EXRangeEqual;
_kEXRangeClass.hash = __EXRangeHash;
_kEXRangeClass.copyFormattingDesc = __EXRangeCopyFormattingDesc;
_kEXRangeClass.copyDebugDesc = __EXRangeCopyDebugDesc;
_kEXRangeID = _CFRuntimeRegisterClass((const CFRuntimeClass * const)&_kEXRangeClass);
}
CFTypeID EXRangeGetTypeID(void) {
return _kEXRangeID;
}
EXRangeRef EXRangeCreate(CFAllocatorRef allocator, uint32_t location, uint32_t length) {
struct __EXRange *newrange;
uint32_t extra = sizeof(struct __EXRange) - sizeof(CFRuntimeBase);
newrange = (struct __EXRange *)_CFRuntimeCreateInstance(allocator, _kEXRangeID, extra, NULL);
if (NULL == newrange) {
return NULL;
}
newrange->_location = location;
newrange->_length = length;
return (EXRangeRef)newrange;
}
uint32_t EXRangeGetLocation(EXRangeRef rangeref) {
return rangeref->_location;
}
uint32_t EXRangeGetLength(EXRangeRef rangeref) {
return rangeref->_length;
}
#endif
CoreFoundation itself does not provide any such mechanism, but all Cocoa objects will work with CFRetain and CFRelease. So the only supported answer is: Create a class based on Foundation and CoreFoundation will recognize it as a CFTypeRef.