将委托转换为函数指针以实现回调函数






4.71/5 (13投票s)
2003年2月3日
2分钟阅读

154383

978
将委托转换为函数指针以实现回调函数,用于混合托管 C++ 和非托管 C++ 编码,以及 DLL 调用。
引言
这些天,我读了 Nishant S. 的文章 使用 IJW 实现回调函数(避免 DllImport),从中受益良多。 我想知道是否有某种方法可以将委托转换为函数指针,我终于找到了。
当您调用 DLL 中的一个函数,并且该函数需要一个回调函数指针时。 首先,您可以使用 DllImport(如果您愿意),这是一个简单的解决方案。 但我不喜欢 DllImport。 更重要的是,有时我想要调用的函数不在 DLL 中。 也就是说,如果我正在编写混合的托管 C++ 和非托管 C++。 即使 DllImport 也将无法工作。 有几种方法可以在非托管 C++ 代码中调用托管 C++ 函数。
- 使用静态函数
//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; };
当需要调用非静态函数时,有第二个解决方案。
- 使用托管对象作为参数。
//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; };
它似乎运行良好,但是当调用
pClassA1->func2(…)
的不是函数classB1:: func2(…)]
时。 也许classB1:: func2(…)
调用其他对象的成员函数,并且该函数调用其他函数,最后遗憾的是调用了pClassA1->func2(…)
。 您必须长时间保留pClassA1
作为参数才能运行,幸好没有虚函数。 虚函数不能将托管对象作为参数。 并且一个非托管对象不能有成员变量来保存托管对象。 - 创建一个指向实例成员函数的函数指针。
我还没有在 .NET framework SDK 中找到任何可以直接将委托转换为函数指针的方法,但我注意到
Marshal::StructToPtr()
宣布能够将托管struct
转换为非托管内存块。 它的作用是将委托包装在托管struct
中,然后将struct
转换为非托管块。 起初,我使用了一个非托管struct
,它有一个函数指针作为非托管内存块,像这样typedef void (*PFUNC)(int) Struct PFUNC_Wrapper { PFUNC thepfunc; };
像这样使用托管
struct
__delegate void MyDelegate(int nArg); [StructLayoutAttribute( LayoutKind::Sequential, CharSet = CharSet::Ansi )] __gc struct Delegate_Wrapper { [MarshalAsAttribute(UnmanagedType::FunctionPtr)] MyDelegate* _theDelegate; };
然后我将托管
struct
转换为非托管struct
。 在PFUNC thepfunc
字段中,我得到了函数指针。 喔,我得到了! 但很快我发现我也可以将非托管struct
转换为函数指针,而不是访问PFUNC thepfunc
的成员字段。 像这样:*(PFUNC*)(&theUnmanagedStruct)
。 在这里,您一定已经看到非托管struct
没用了。 所以我只是使用一个PFUNC
来接收数据作为非托管内存块。
源代码
__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; }
确保垃圾回收器在回调函数完成其工作之前不会回收委托。
结论
可以通过函数指针使用托管类的成员函数。 即使它是一个非静态函数!!
电子邮件:peiweny@hotmail.com