1、函数委托 类似于 C++中函数指针(∵我不知道这两货是否真的完全一样,∴用的是"类似于")
2、声明函数委托 方法类似于 声明函数指针
3、我的代码:
3.1、VC的DLL代码:
// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***// 普通导出函数extern "C" __declspec(dllexport) int __stdcall TestZZ(int i, int j, int k, int m, int n){ return (i+j+k+m+n);}// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***// exe中传入回调函数指针,并且调用typedef int (__stdcall * Callback_Test01)(int, int, int, int, int);extern "C" __declspec(dllexport) void __stdcall TestCB(Callback_Test01 _callback){ if (_callback) { int i = _callback(1,2,3,4,5); }}
3.1.1、def文件内容:
LIBRARY DLL_ZEXPORTS TestZZ TestCB
3.2、C#代码:
private void button1_Click(object sender, EventArgs e) { AAA(1, 2, 3); // 用汇编查看 调用普通C#函数时的调用规则 int kk = TestZZ(1, 2, 3, 4 ,5); // 查看调用DLL导出函数时的调用规则 Fhh = 0; TestCB(callback); // ZC: 将函数委托传递给 VC的DLL 并在DLL中调用 -- (1) MessageBox.Show(Fhh.ToString()); Fhh = 0; callback02 = new Callback_Test01(TT01); TestCB(callback02); // ZC: 将函数委托传递给 VC的DLL 并在DLL中调用 -- (2) MessageBox.Show(Fhh.ToString()); } int AAA(int i, int j, int k) { return (i + j + k); } //[DllImport("DLL_Z.dll", EntryPoint="TestZZ", CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall)] [DllImport("DLL_Z.dll", EntryPoint = "TestZZ", CharSet = CharSet.Auto)] public static extern int TestZZ(Int32 i, Int32 j, Int32 k, Int32 m, Int32 n); [DllImport("DLL_Z.dll", EntryPoint = "TestCB", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern void TestCB([MarshalAs(UnmanagedType.FunctionPtr)] Callback_Test01 _callback); // (委托)回调函数指针 [UnmanagedFunctionPointer(CallingConvention.StdCall)] public delegate int Callback_Test01(int _i, int _j, int _k, int _m, int _n); public static int Fhh = 0; // 委托(回调函数) -- 方式(1) // 需要访问类成员变量的回调函数实例 Callback_Test01 callback = (i, j, k, m, n) => { Fhh = (i + j + k + m + n); // 这里可以直接访问 类成员变量 //return (i + j + k + m + n); return Fhh; }; Callback_Test01 callback02 = null;//new Callback_Test01(TT01); // 委托(回调函数) -- 方式(2) int TT01(int i, int j, int k, int m, int n) { Fhh = (i + j + k + m + n); // 这里可以直接访问 类成员变量 //return (i + j + k + m + n); return Fhh; }
ZC: 测试感受:
ZC: (1)、C#调用DLL中的函数,貌似默认的调用约定是 stdcall
ZC: (2)、delegate 貌似它的默认调用约定也是stdcall
4、这里 测试的是 VC的DLL返回接口 让C#使用
4.1、C#代码:
4.1.1、接口声明
namespace WindowsFormsApplication_AAA{ [Guid("FCE9DCF3-9E38-441C-B10F-2BA31B57DCDC")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IntfTest { unsafe Int32 TestZ01(int _i, int _j, int _k, int* _piOut); unsafe Int32 TestZ02(int _i, int _j, int _k, int _m, int* _piOut); unsafe Int32 TestZ03(int _i, int _j, int _k, int _m, int _n, int* _piOut); }}
4.1.2、
[DllImport("DLL_Z.dll", EntryPoint = "IntfTest_Get", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)] public static extern int IntfTest_Get(ref IntfTest _intfTest); private void button2_Click(object sender, EventArgs e) { callback02 = new Callback_Test01(TT01); // 操作/使用 DLL返回的接口 IntfTest intfTest = null; int iRtn = IntfTest_Get(ref intfTest); unsafe { int iOut = 0; intfTest.TestZ01(1, 2, 3, &iOut); } }
4.2、VC的DLL中的代码:
4.2.1、
// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***// 导出 interface,供 exe使用IntfTest *g_pIntfTest;extern "C" __declspec(dllexport) int IntfTest_Get(IntfTest **_ppIntfTest){ (*_ppIntfTest) = NULL; if ( NULL != g_pIntfTest ) { // 当"IntfTest*"为局部变量时,C#会自动销毁接口,使得引用计数-1,∴这里需要+1 // 而 首次获取"IntfTest*"时,由于类构造函数中有增加引用计数的操作,∴不需要+1 g_pIntfTest->AddRef(); (*_ppIntfTest) = g_pIntfTest; return 0; }// *** IntfTest *pObj = new TintfTest(); IUnknown *pIUnknown = NULL; HRESULT hr = pObj->QueryInterface(IID_IUnknown, (void**)&pIUnknown); pObj->Release(); pObj = NULL; if (FAILED(hr)) { return -1; } else { hr = pIUnknown->QueryInterface(IID_IntfTest, (void**)&g_pIntfTest); pIUnknown->Release(); pIUnknown = NULL; if (SUCCEEDED(hr)) { (*_ppIntfTest) = g_pIntfTest; } else { return -2; } } return 0;}
4.2.2、接口信息:
#ifndef __zzz_20160414__#define __zzz_20160414__#include// // {FCE9DCF3-9E38-441C-B10F-2BA31B57DCDC}static const IID IID_IntfTest ={ 0xfce9dcf3, 0x9e38, 0x441c, { 0xb1, 0xf, 0x2b, 0xa3, 0x1b, 0x57, 0xdc, 0xdc } };interface IntfTest : public IUnknown{ virtual HRESULT __stdcall TestZ01(int _i, int _j, int _k, int* _piOut) = 0; virtual HRESULT __stdcall TestZ02(int _i, int _j, int _k, int _m, int* _piOut) = 0; virtual HRESULT __stdcall TestZ03(int _i, int _j, int _k, int _m, int _n, int* _piOut) = 0;};class TintfTest :public IntfTest{public: TintfTest();public: virtual HRESULT __stdcall TestZ01(int _i, int _j, int _k, int* _piOut); virtual HRESULT __stdcall TestZ02(int _i, int _j, int _k, int _m, int* _piOut); virtual HRESULT __stdcall TestZ03(int _i, int _j, int _k, int _m, int _n, int* _piOut);private: long FlCount;public: virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppv) { if (iid == IID_IUnknown) { *ppv = static_cast (this); } else if (iid == IID_IntfTest) { *ppv = static_cast (this); } else { *ppv = NULL; return E_NOINTERFACE; } AddRef(); return S_OK; } virtual ULONG STDMETHODCALLTYPE AddRef() { return ++FlCount; //return InterlockedIncrement(&FlCount); } virtual ULONG STDMETHODCALLTYPE Release() { if (--FlCount == 0) { delete this; return 0; } return FlCount; //if (InterlockedDecrement(&FlCount) == 0) //{ // delete this; // return 0; //} //return FlCount; }};TintfTest::TintfTest(): FlCount(0){ this->AddRef();}HRESULT __stdcall TintfTest::TestZ01(int _i, int _j, int _k, int* _piOut){ *_piOut = (_i + _j + _k); return S_OK;}HRESULT __stdcall TintfTest::TestZ02(int _i, int _j, int _k, int _m, int* _piOut){ return S_OK;}HRESULT __stdcall TintfTest::TestZ03(int _i, int _j, int _k, int _m, int _n, int* _piOut){ return S_OK;}#endif // __zzz_20160414__
5、