调用C函数内部C#通过函数指针 [英] Call C function inside C# via function pointer
问题描述
我有一个静态函数在我的C程序的地址被发送到一个C#.NET程序。地址是正确的,但用户能够在C#中调用这个函数?
有一些code:
静态无效test_callback()
{
的printf(test_callback所谓的\ n);
}
无效callCSharpFunction()
{
HRESULT状态;
BOOL启动;
DWORD结果;
炭ptr的[5];
INT P1;
入门= FALSE;
状态= CorBindToRuntimeEx的(
空值,
空值,
0,
&功放; CLSID_CLRRuntimeHost,
&功放; IID_ICLRRuntimeHost,
(PVOID *)及主机
);
如果(失败(状态)){}
状态= ICLRRuntimeHost_Start(主机);
如果(失败(状态)){}
入门= 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是为0x%X \ N,(INT)及test_callback);
状态= ICLRRuntimeHost_ExecuteInDefaultAppDomain(
主办,
LC:\\ pathtodll \\ MYDLL.DLL
LMyClass的,
LMyFunction的,
(LPCWSTR)PTR,
&放大器;结果
);
的printf(结果是0X%X \ N,结果);
}
在我的C#.NET项目,我有
公共静态不安全无效callCallback(INT PTR)
{
无效(*回调)();
//我希望我能做到这一点,但不安全似乎并没有让函数指针..
回调=(无效(*)())PTR;
回电话();
}
公共静态INT测试(字符串参数)
{
的char [] ptrChar = param.ToCharArray();
INT ptrInt = 0;
ptrInt =(((int)的(为0xFF00及(INT)ptrChar [1])|处(00FFH及(INT)ptrChar [1]))≤;&所述; 16)|
(中间体)(为0xFF00及(INT)ptrChar [0])|处(00FFH及(INT)ptrChar [0]);
callCallback(ptrInt);
}
您需要使用元帅。<一个href="http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.getdelegateforfunctionpointer%28v=vs.110%29.aspx"相对=nofollow> GetDelegateForFunctionPointer 。你甚至不需要使用不安全code。
委托无效TestCallbackDelegate(); //必须test_callback的签名匹配()
公共静态无效callCallback(INT PTR)
{
IntPtr的nativePtr =新的IntPtr(PTR);
VAR回调= Marshal.GetDelegateForFunctionPointer&LT; TestCallbackDelegate&GT;(nativePtr);
回电话();
}
公共静态INT测试(字符串参数)
{
的char [] ptrChar = param.ToCharArray();
INT ptrInt = 0;
ptrInt =(((int)的(为0xFF00及(INT)ptrChar [1])|处(00FFH及(INT)ptrChar [1]))≤;&所述; 16)|
(中间体)(为0xFF00及(INT)ptrChar [0])|处(00FFH及(INT)ptrChar [0]);
callCallback(ptrInt);
}
虽然一个更简单的方法是只通过一个无效*
的C#方法,它会自动得到整理,以的IntPtr
。下面是一个小例子:
C ++
// invoke.cpp
//编译:CL / EHSC / LD / NOLOGO invoke.cpp
#包括&LT; stdio.h中&GT;
静态无效test_callback()
{
的printf(test_callback所谓的\ n);
}
外部的C__declspec(dllexport)的无效 getPointer()
{
回报(无效*)及test_callback; //返回原始指针test_callback功能。
}
C#
// invoke.cs
//编译:CSC / NOLOGO invoke.cs
使用系统;
使用了System.Runtime.InteropServices;
类节目
{
[的DllImport(invoke.dll)]
私人静态外部的IntPtr getPointer();
私人委托无效TestCallbackDelegate(); //代表说test_callback的签名相匹配
静态无效的主要()
{
IntPtr的PTR = getPointer(); //获取本机空指针。
TestCallbackDelegate test_callback = Marshal.GetDelegateForFunctionPointer&LT; TestCallbackDelegate&GT;(PTR); //元帅void指针,以委托。
test_callback(); //调用本机C函数。
}
}
我用的DllImport
属性来避免调用,你正在做的CLR,但它同样的想法。
修改:因为我意识到了上述不适什么的任择议定书问,我就包括更新的正确的样本。上述仍将留给后人。
C
的#define COBJMACROS
#包括&LT; stdio.h中&GT;
#包括&LT; WINDOWS.H&GT;
#包括&LT; mscoree.h&GT;
静态无效test_callback()
{
的printf(test_callback被称为\ñ。);
}
INT主要(无效)
{
HRESULT状态;
ICLRRuntimeHost *主机;
BOOL启动;
DWORD结果;
主机= NULL;
入门= FALSE;
状态= CorBindToRuntimeEx的(NULL,NULL,0,CLSID_CLRRuntimeHost,IID_ICLRRuntimeHost,(无效**)及主机);
如果(失败(状态))
转到清理;
状态= ICLRRuntimeHost_Start(主机);
如果(失败(状态))
转到清理;
入门= TRUE;
INT PTR =(int)的&安培; test_callback;
的printf(test_callback是为0x%X \ N,PTR);
炭参数[5];
参数[0] = 0xFF的&安培; (PTR&GT;&0);
参数[1] = 0xFF的&安培; (PTR&GT;→8);
参数[2] = 0xFF的&安培; (PTR&GT;&GT; 16);
参数[3] = 0xFF的&安培; (PTR&GT;&GT; 24);
参数[4] ='\ 0';
状态= ICLRRuntimeHost_ExecuteInDefaultAppDomain(主机,Linvoke.dllLInteropTesting.InvokerLInvokeCallback,(LPCWSTR)参数,及放大器;结果);
如果(失败(状态))
转到清理;
清理:
如果(入门)
ICLRRuntimeHost_Stop(主机);
如果(主机!= NULL)
ICLRRuntimeHost_Release(主机);
返回成功(状态)? 0:1;
}
C#
使用系统;
使用了System.Runtime.InteropServices;
命名空间InteropTesting
{
公共静态类祈求
{
私人委托无效TestCallbackDelegate();
公共静态INT InvokeCallback(字符串参数)
{
// C#有转字节数组转换为整数的内置手段
//所以我们将使用而不是使用位运算符BitConverter。
的char []字符= param.ToCharArray();
INT PTR = BitConverter.ToInt32(Array.ConvertAll(字符,C =&GT;(字节)C),0);
VAR test_callback =(TestCallbackDelegate)Marshal.GetDelegateForFunctionPointer(新的IntPtr(PTR)的typeof(TestCallbackDelegate));
test_callback();
返回0;
}
}
}
I have a static function in my C program which address is transmitted to a C# .NET program. The address is correct, but is it possible to call this function within C#?
Have some Code:
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);
}
And in my C# .NET project I have
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);
}
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\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<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.\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;
}
}
}
这篇关于调用C函数内部C#通过函数指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!