gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 16:07:34 24 4
gpt4 key购买 nike

我的 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<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);
}

尽管更简单的方法是将 void* 传递给 C# 方法,它会自动编码为 IntPtr。这是一个最小的例子:

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.
}
}

我使用了 DllImport 属性来避免必须像您正在做的那样调用 CLR,但这是相同的想法。


编辑:因为我意识到上述内容不适用于 OP 的要求,所以我将包含一个更新的正确示例。以上内容将留给后代。

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# 中调用 C 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21540335/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com