Convert a Delegate to a Function pointer to Implement Callback function






4.71/5 (13 votes)
Feb 3, 2003
2 min read

153533

978
Convert a delegate to a function pointer to implement callback function, for mixed Managed C++ and unmanaged C++ coding, and for DLL call.
Introduction
These days, I've read the article Implementing Callback functions using IJW (avoiding DllImport), by Nishant S. From which I benefited much. And I wonder if there is some way to convert a delegate to a function pointer, I've got it at last.
When you are calling a function which is in a DLL, and that function requires a callback function pointer. First you can use DllImport (if you like to do so), which is a simple solution. But I don’t like DllImport. What's more, some times the function I want to call is not in a DLL. That is if I am coding mixed Managed C++ and Unmanaged C++. Even DllImport will not work. There are several ways to call a Managed C++ function in unmanaged C++ code.
- Use static function
//managed class __gc class classA1 { public: static void func1(int nArg) { Console::WriteLine(nArg.ToString()); } }; //unmanaged class class classB1 { public: classB1(int nArg) { m_nCount = nArg; } public: void func1() { classA1::func1(m_nCount); } protected: int m_nCount; };
When I need a non-static function to be called, there is the second solution.
- Use a managed object as a parameter.
//managed class __gc class classA1 { public : void func2(int nArg) { Console::WriteLine(nArg.ToString()); } }; //unmanaged class class classB1 { public: classB1(int nArg) { m_nCount = nArg; } public : void func2(classA1* pClassA1) { pClassA1->func2(m_nCount); } protected: int m_nCount; };
It seems to work well, but when the one which call
pClassA1->func2(…)
is not the functionclassB1:: func2(…)]
. MaybeclassB1:: func2(…)
calls other object’s member function, and the function calls others, at lastpClassA1->func2(…)
is called sadly. You must holdpClassA1
as a parameter to run for a long way, blessing there is no virtual function. Virtual functions can’t have managed object as parameter. And an unmanaged object can’t have a member variable to hold managed object. - Make a function pointer which points to an instance member function.
I have not found any method in .NET framework SDK to convert a delegate to a function pointer straightly yet, but I noticed
Marshal::StructToPtr()
which announced to be able to convert a managedstruct
to unmanaged memory block. What it does is to wrap the delegate in the managedstruct
, then convert thestruct
to an unmanaged block. At the beginning I used an unmanagedstruct
that has a field of a function pointer act as the unmanaged memory block, like this:typedef void (*PFUNC)(int) Struct PFUNC_Wrapper { PFUNC thepfunc; };
Use the managed
struct
like this:__delegate void MyDelegate(int nArg); [StructLayoutAttribute( LayoutKind::Sequential, CharSet = CharSet::Ansi )] __gc struct Delegate_Wrapper { [MarshalAsAttribute(UnmanagedType::FunctionPtr)] MyDelegate* _theDelegate; };
Then I convert the managed
struct
to an unmanagedstruct
. At the field ofPFUNC thepfunc
I got the function pointer. Ooh I got it! But soon I found I could also convert the unmanagedstruct
to a function pointer instead of accessing the member field ofPFUNC thepfunc
. Like this:*(PFUNC*)(&theUnmanagedStruct)
. Here you must have seen that the unmanagedstruct
is useless. So I just use aPFUNC
to receive the data as an unmanaged memory block.
The source code
__gc class classA1 { public : void func2(int nArg) { Console::WriteLine(nArg.ToString()); } }; typedef void (*PFUNC)(int); class classB1 { public: classB1(int nArg) { m_nCount = nArg; } public: virtual void func3(PFUNC pCallback){ if(pCallback != NULL) { pCallback(m_nCount); } } protected: int m_nCount; }; __delegate void MyDelegate(int nArg); [StructLayoutAttribute( LayoutKind::Sequential, CharSet = CharSet::Ansi )] __gc struct Delegate_Wrapper { [MarshalAsAttribute(UnmanagedType::FunctionPtr)] MyDelegate* _theDelegate; }; // This is the entry point for this application int _tmain(void) { // TODO: Please replace the sample code below with your own. Console::WriteLine(S"Hello World"); //create instance of managed classA1 classA1* theA1 = new classA1(); //create instance of Delegate_Wrapper Delegate_Wrapper* theWrapper = new Delegate_Wrapper(); theWrapper->_theDelegate = new MyDelegate(theA1,&classA1::func2); //Convert the Delegate to Function Pointer. PFUNC pFnc; Marshal::StructureToPtr(theWrapper,&pFnc,false); //create instance of unmaged classB1 classB1 theB1(3); //use the function pointer as a callback function theB1.func3(pFnc); Console::ReadLine(); return 0; }
Ensure that the garbage collector does not reclaim the delegate before the callback function completes its work.
Conclusion
A managed class’s member function can be used through a function pointer. Even if it is a non-static function!!
E-mail:peiweny@hotmail.com