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
__gc class classA1 {
public: static void func1(int nArg) {
Console::WriteLine(nArg.ToString());
}
};
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.
__gc class classA1 {
public : void func2(int nArg) {
Console::WriteLine(nArg.ToString());
}
};
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 function classB1:: func2(�)]
. Maybe classB1:: func2(�)
calls other object�s member function, and the function calls others, at last pClassA1->func2(�)
is called sadly. You must hold pClassA1
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 managed struct
to unmanaged memory block. What it does is to wrap the delegate in the managed struct
, then convert the struct
to an unmanaged block. At the beginning I used an unmanaged struct
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 unmanaged struct
. At the field of PFUNC thepfunc
I got the function pointer. Ooh I got it! But soon I found I could also convert the unmanaged struct
to a function pointer instead of accessing the member field of PFUNC thepfunc
. Like this: *(PFUNC*)(&theUnmanagedStruct)
. Here you must have seen that the unmanaged struct
is useless. So I just use a PFUNC
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;
};
int _tmain(void)
{
Console::WriteLine(S"Hello World");
classA1* theA1 = new classA1();
Delegate_Wrapper* theWrapper = new Delegate_Wrapper();
theWrapper->_theDelegate = new MyDelegate(theA1,&classA1::func2);
PFUNC pFnc;
Marshal::StructureToPtr(theWrapper,&pFnc,false);
classB1 theB1(3);
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