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
bobsinclare666Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

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
Cloud Class® Course: Microsoft Windows 7 Basic

This introductory course to Windows 7 environment will teach you about working with the Windows operating system. You will learn about basic functions including start menu; the desktop; managing files, folders, and libraries.

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

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
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
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
.NET Programming

From novice to tech pro — start learning today.