You'll want to use Marshal.GetDelegateForFunctionPointer. You won't even need to use unsafe code.
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<TestCallbackDelegate>( 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);
}
Although a much simpler way would be to just pass a void*
to the C# method, and it will automatically get marshalled to IntPtr
. Here's a minimal example of that:
C++
//invoke.cpp
//compile with: cl /EHsc /LD /nologo invoke.cpp
#include <stdio.h>
static void test_callback()
{
printf("test_callback called
");
}
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<TestCallbackDelegate>( ptr ); //Marshal the void pointer to a delegate.
test_callback(); //Invoke the native C function.
}
}
I used the DllImport
attribute to avoid having to invoke the CLR as you're doing, but it's the same idea.
EDIT: Because I realized the above doesn't apply to what the OP was asking, I'll include an updated and proper sample. The above will remain for posterity.
C
#define COBJMACROS
#include <stdio.h>
#include <windows.h>
#include <mscoree.h>
static void test_callback()
{
printf( "test_callback has been called.
" );
}
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
", 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] = '';
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;
}
}
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…