• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1860
  • Last Modified:

Delegates with Native Function Callbacks in Managed C++

Hi there,

I am trying to integrate a native C++ DLL (used to drive a video camera) into a C++/CLI project.

So I wrote a wrapper class for this DLL in order to have managed-compatible types for my DLL function calls.

Most of the class-content is about importing the functions in the following way:

Code:

[ DllImport("camera.dll") ]
static System::IntPtr CameraOpen(unsigned long index);//C++/CLI
//HANDLE CAM_EXPORT CameraOpen(unsigned long index); //C++


Then I create an instance of that class in my main project class and call the functions. That works fine.

Now I am getting very frustrated trying to import a function from the DLL which takes a pointer to a global callback function (this callback is called when a new video frame is available).

In C++, the prototype of that function is the following:

Code:

static LONG CAM_EXPORT CameraAddStreamingCallback(HANDLE hCamera, VOID (__stdcall *VideoFilter)(VOID *pContext, BYTE *pData, ULONG dataLength), VOID *pCBContext);



and the declaration of the prototype callback function (VideoFilter) is the following:

Code:

// Callback function prototype void __stdcall VideoFilter(VOID *pContext, BYTE *pData, ULONG dataLength);



From spending days browsing the net for a solution I figured that I need to use a delegate function (please refrain from applausing) in order to do this but I miserably failed to implement it.

What I have done so far is the following:

Inside my wrapper class:

Code:

[ DllImport("camera.dll")]
static long CameraAddStreamingCallback(System::IntPtr hCamera, System::Void (*VideoFilter)(System::Void *pContext, System::Byte *pData, unsigned long dataLength), System::Void *pCBContext);



Then I have a global declaration of the delegate:

Code:

delegate System::Void VideoFilter(System::Void *pContext, System::Byte *pData, unsigned long dataLength);



That compiles fine. But then I am stuck on how to use this delegate with the function.

I tried to call it in one function of my wrapper class the following way:

Code:

m_lSnapCallbackRegistration = CameraAddStreamingCallback(m_hCamera, VideoFilter, this);



But I get the following compile error:


error C2275: 'VideoFilter' : illegal use of this type as an expression
see declaration of VideoFilter


Ca anyone point me to the solution....?

Thanks in advance and sorry for the long post.

Bob
0
bobsinclare666
Asked:
bobsinclare666
  • 5
  • 4
1 Solution
 
evilrixSenior Software Engineer (Avast)Commented:
Try looking at these...

Visual C++
How to: Marshal Function Pointers Using PInvoke
http://msdn2.microsoft.com/en-us/library/ektebyzx.aspx

Additional (but more general) info on marshaling...
http://msdn.microsoft.com/msdnmag/issues/08/01/CLRInsideOut/default.aspx
0
 
bobsinclare666Author Commented:
Thanks EvilRix,

This is pointing me to the right direction I think, but somehow I am still a bit lost with the implementation.
Let's get a few things straight:

In my project I have this wrapper class around the native C++ DLL.
In the wrapper.h, I declare my class with some member functions prototypes declared using  the [DLLImport] keyword.
In the wrapper.cpp, I implement these functions.

Now, where am I suppose to declare my delegate? On top of my wrapper.h (outside the class then?)
And then where am I supposed to declare the callback function body? Is it a "global" function or not?
Should it be declared inside my wrapper class as a member function?
Then where do I instantiate the delegate with "gcnew"?

Cheers,

bob



0
 
bobsinclare666Author Commented:
OK ok, I have progressed a bit but I still have one issue, how to cast the pointer I get from the Marshal::GetFunctionPointerForDelegate() function:

Here is the code:

StreamCallback^ fp = gcnew StreamCallback(MyApiWrapper::MyStreamCallback);
pin_ptr<StreamCallback^> pp = &fp;
m_lSnapCallbackRegistration = CameraAddStreamingCallback(m_hCamera, Marshal::GetFunctionPointerForDelegate(fp).ToInt32(), this);

Compiler complains the following:

error C2664: 'MyApiWrapper::CameraAddStreamingCallback' : cannot convert parameter 2 from 'void *' to 'void (__clrcall *)(void *,unsigned char *,unsigned long)'

I tried various options to cast the functio pointer but no success. Any idea....?

Thanks

Bob

0
Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

 
evilrixSenior Software Engineer (Avast)Commented:
Try this.

Unfortunately, I can't test it in .Net but it works fine for normal C++.
NB. Not quite sure where to put the "__clrcall" so you may have to fiddle a little :)
typedef void (__clrcall *func_t)(void *,unsigned char *,unsigned long);
 
 
int main(int argc, char* argv[])
{
	// Create a dummy void pointer just for testing	
	void * vp = 0;
	// Use constructor casting to create a new func_t from void *	
	func_t fp = func_t(vp);
}

Open in new window

0
 
evilrixSenior Software Engineer (Avast)Commented:
So I guess you code would be something like this...
typedef void (__clrcall *func_t)(void *,unsigned char *,unsigned long);
func_t fp = func_t(Marshal::GetFunctionPointerForDelegate(fp).ToInt32());
m_lSnapCallbackRegistration = CameraAddStreamingCallback(m_hCamera, fp, this);

Open in new window

0
 
bobsinclare666Author Commented:
Excellent, that did the trick.
The program runs and then crashes however. I suppose this is likely to be due to the garbage collector and I may have to pin down the function pointer?
I tried this:

pin_ptr<StreamCallback^> pp = &fp;

But it does not work any better. Is this not the way to do it?
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> Is this not the way to do it?
That is my understanding but, to be honest, I'm no managed code guru -- Vanilla C++ is my thing. Sorry, I don't think I can advise on this one :(
0
 
bobsinclare666Author Commented:
Thanks anyways, you have been of great help.
Keeping a reference to the delegate in a managed part of the code seems to be doing the trick, no need in fact to pin it.

Here is the thread that helped on this matter:

http://www.thescripts.com/forum/thread284984.html

Cheers and thanks again,

Bob
0
 
evilrixSenior Software Engineer (Avast)Commented:
Very welcome.
0

Featured Post

The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

  • 5
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now