通过函数指针在C#中调用C函数

我的C程序中有一个静态函数,该地址被传送到C#.NET程序。 地址是正确的,但可以在C#中调用此函数吗?

有一些代码:

static void test_callback() { printf("test_callback called\n"); } void callCSharpFunction () { HRESULT status; BOOL Started; DWORD result; char ptr[5]; int p1; Started = FALSE; status = CorBindToRuntimeEx( NULL, NULL, 0, &CLSID_CLRRuntimeHost, &IID_ICLRRuntimeHost, (PVOID *)&Host ); if (FAILED(status)) {} status = ICLRRuntimeHost_Start(Host); if (FAILED(status)) {} Started = TRUE; p1 = (int)(&test_callback); ptr[0] = 0xFF & ((int)&test_callback >> 0); ptr[1] = 0xFF & ((int)&test_callback >> 8); ptr[2] = 0xFF & ((int)&test_callback >> 16); ptr[3] = 0xFF & ((int)&test_callback >> 24); printf("test_callback is at 0x%X\n", (int)&test_callback); status = ICLRRuntimeHost_ExecuteInDefaultAppDomain( Host, L"C:\\pathtodll\\mydll.dll", L"myclass", L"myfunction", (LPCWSTR)ptr, &result ); printf("Result is 0x%X\n", result); } 

在我的C#.NET项目中

 public static unsafe void callCallback(int ptr) { void (*callback)(); // I wish I could do that but "unsafe" seems not to allow function pointers .. callback = (void(*)())ptr; callback(); } public static int test(string param) { char[] ptrChar = param.ToCharArray(); int ptrInt = 0; ptrInt = ( ((int)(0xFF00 & (int)ptrChar[1]) | (0x00FF & (int)ptrChar[1])) << 16 ) | (int)(0xFF00 & (int)ptrChar[0]) | (0x00FF & (int)ptrChar[0]); callCallback(ptrInt); } 

你会想要使用Marshal。 GetDelegateForFunctionPointer 。 您甚至不需要使用不安全的代码。

 delegate void TestCallbackDelegate(); //must match the signature of test_callback() public static void callCallback(int ptr) { IntPtr nativePtr = new IntPtr( ptr ); var callback = Marshal.GetDelegateForFunctionPointer( nativePtr ); callback(); } public static int test(string param) { char[] ptrChar = param.ToCharArray(); int ptrInt = 0; ptrInt = ( ((int)(0xFF00 & (int)ptrChar[1]) | (0x00FF & (int)ptrChar[1])) << 16 ) | (int)(0xFF00 & (int)ptrChar[0]) | (0x00FF & (int)ptrChar[0]); callCallback(ptrInt); } 

虽然更简单的方法是将void*传递给C#方法,但它会自动编组到IntPtr 。 这是一个最小的例子:

C ++

 //invoke.cpp //compile with: cl /EHsc /LD /nologo invoke.cpp #include  static void test_callback() { printf("test_callback called\n"); } extern "C" __declspec( dllexport ) void* getPointer() { return (void*)&test_callback; //Return a raw pointer to the test_callback function. } 

C#

 //invoke.cs //compile with: csc /nologo invoke.cs using System; using System.Runtime.InteropServices; class Program { [DllImport( "invoke.dll" )] private static extern IntPtr getPointer(); private delegate void TestCallbackDelegate(); //Delegate that matches the signature of test_callback static void main() { IntPtr ptr = getPointer(); //Fetch the native void pointer. TestCallbackDelegate test_callback = Marshal.GetDelegateForFunctionPointer( ptr ); //Marshal the void pointer to a delegate. test_callback(); //Invoke the native C function. } } 

我使用DllImport属性来避免在你做的时候调用CLR,但这是同样的想法。


编辑 :因为我意识到上述内容不适用于OP所要求的内容,所以我将包含更新且适当的样本。 后者将留给子孙后代。

C

 #define COBJMACROS #include  #include  #include  static void test_callback() { printf( "test_callback has been called.\n" ); } int main( void ) { HRESULT status; ICLRRuntimeHost *Host; BOOL Started; DWORD Result; Host = NULL; Started = FALSE; status = CorBindToRuntimeEx( NULL, NULL, 0, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (void**)&Host ); if( FAILED( status ) ) goto cleanup; status = ICLRRuntimeHost_Start( Host ); if( FAILED( status ) ) goto cleanup; Started = TRUE; int ptr = (int)&test_callback; printf( "test_callback is at 0x%X\n", ptr ); char param[5]; param[0] = 0xFF & ( ptr >> 0 ); param[1] = 0xFF & ( ptr >> 8 ); param[2] = 0xFF & ( ptr >> 16 ); param[3] = 0xFF & ( ptr >> 24 ); param[4] = '\0'; status = ICLRRuntimeHost_ExecuteInDefaultAppDomain( Host, L"invoke.dll", L"InteropTesting.Invoker", L"InvokeCallback", (LPCWSTR)param, &Result ); if( FAILED( status ) ) goto cleanup; cleanup: if( Started ) ICLRRuntimeHost_Stop( Host ); if( Host != NULL ) ICLRRuntimeHost_Release( Host ); return SUCCEEDED( status ) ? 0 : 1; } 

C#

 using System; using System.Runtime.InteropServices; namespace InteropTesting { public static class Invoker { private delegate void TestCallbackDelegate(); public static int InvokeCallback( string param ) { //C# has a built-in means of turning byte arrays into integers //so we'll use BitConverter instead of using the bitwise operators. char[] chars = param.ToCharArray(); int ptr = BitConverter.ToInt32( Array.ConvertAll( chars, c => (byte)c ), 0 ); var test_callback = (TestCallbackDelegate)Marshal.GetDelegateForFunctionPointer( new IntPtr( ptr ), typeof( TestCallbackDelegate ) ); test_callback(); return 0; } } }