tags:

views:

1133

answers:

2

I am having difficulty using a thirdparty library registration function to register a callback. I am writing in C++ CLI, and accessing a library written in C or C++.

What does the above compiler error mean?

this is the registration function as defined by the vendor:

MYCO int WINAPI MyCo_Device_Register_CallbackFunc(LPVOID func, LPVOID lpParam, DWORD mask);

this is the callback as defined by the vendor:

typedef void (CALLBACK* MyCo_Device_CallbackProc)(DWORD ddStatus, LPVOID lpParam);

My callback function:

public ref class Device 
{
    void CallBackFunc(DWORD ddStatus, LPVOID lpParam) {};
}

My call (which fails):

MyCo_Device_Register_CallbackFunc((LPVOID) Device::CallBackFunc, nullptr, 0xFFFF);
+6  A: 

If I had to wager a guess, you're trying to taken the address of a MANAGED function and pass it as a NATIVE function pointer. That won't work at all. Either write a native bridge (harder and probably no advantage), or (and this is the easier approach), create a delegate and use Marshal.GetFunctionPointerForDelegate. Don't forget that the delegate has to stay alive for the duration that the native code expects to call back, so you most likely need to store it somewhere.

Oh, and all functions inside a ref class or value class are managed functions, in case that wasn't clear.

[EDIT] Expanding answer to cover questions in comments. The first step is to create a matching delegate. For the function you provided, it's going to look like this:

public delegate void CallbackFuncDelegate(DWORD ddStatus, LPVOID lpParam);

Then, you'll need to create one:

CallbackFuncDelegate del = gcnew CallbackFuncDelegate(CallbackFunc);

And as noted previously, you should store that IN your class as a member in order to make sure it doesn't vanish. Lastly, you need to get the function pointer and pass it down:

MyCo_Device_Register_CallbackFunc((MyCo_Device_CallbackProc) Marshal::GetFunctionPointerForDelegate(del).ToPointer(), 0, 0);

I think that covers everything. All you need is using namespace System; and you should be fine.

Promit
I think you hit the nail on the head. how does the code that you suggest look like, and what includes do I need?
MedicineMan
and how do I ensure that I am keeping the delegate alive so that it doesn't get collected (lifetime management)
MedicineMan
I made the following changes: 1. ^ missing in delegate creation 2.
MedicineMan
one more problem that I cannot solve: void Device:CallbackFunc(DWORD, LPVOID): the specified function does not match the delegate type 'void (DWORD,LPVOID)' Alexy suggested making this a static (which allows it compile), but with a static, I don't have access to any of the class's data.
MedicineMan
As the example for this error on msdn shows http://msdn.microsoft.com/en-us/library/5408cs95(VS.80).aspx , you can pass in a reference to your device when creating the delegate: CallbackFuncDelegate ^ del = gcnew CallbackFuncDelegate(device, Then it doesn't need to be a static method.
Logan Capaldo
A: 

your callback func is a member -- pointer to members and pointers to functions are different things.

Even in Promit's solution:

CallbackFuncDelegate(CallbackFunc)

CallbackFunc should not be class member

You can write simply

public ref class Device 
{
    static void CallBackFunc(DWORD ddStatus, LPVOID lpParam) {};
}

and then use

Device::CallBackFunc
your suggestion did fix the compile issue, but it seems strange that I now have a static method that has no access to private data (can't do anything). I wonder if this will work
MedicineMan
Thanks for the suggestion. Changing my class to be a singleton in order to use callbacks somehow doesn't feel quite right.
MedicineMan
Singleton solution is for the case when you can have only one device.Just in case -- anyway, since you need static pointer -- you can have only one Device getting callbacks (until you can pass user-data which will be passed back to your callback)
Just looked again through the codeMYCO int WINAPI MyCo_Device_Register_CallbackFunc(LPVOID func, LPVOID lpParam, DWORD mask);lpParam can be just the thing you need. Look in documentation -- if this is the same lpParam that is passed to your callback, you can insert pointer to needed Device ;-)