.NET使用System.Runtime.InteropServices.Marshal实现委托与函数指针互转

函数介绍

摘自MSDN

命名空间: System.Runtime.InteropServices

函数:Marshal.GetDelegateForFunctionPointer

(将非托管函数指针转换为委托)

publicstatic Delegate GetDelegateForFunctionPointer(
    IntPtr ptr,
    Type t
)
参数
ptr

类型:System.IntPtr

要转换的非托管函数指针。
t
类型: System.Type
要返回的委托的类型。
返回值
类型: System.Delegate
委托实例,可强制转换为适当的委托类型。
异常
异常条件
ArgumentException

t 参数不是委托或泛型。

ArgumentNullException

ptr 参数为 nullNothingnullptrnull 引用(在 Visual Basic 中为 Nothing)

- 或 -

t 参数为 nullNothingnullptrnull 引用(在 Visual Basic 中为 Nothing)

备注

在 .NET Framework 1.0 或 1.1 版中,可以将表示托管方法的委托作为函数指针传递给非托管代码,因此,非托管代码可以通过函数指针调用托管方法。非托管代码也可以将该函数指针传递回托管代码,指针可以正确解析为基础托管方法。

在 .NET Framework 2.0 及更高版本中,可以使用 GetDelegateForFunctionPointer 方法和GetFunctionPointerForDelegate 方法双向封送委托。 用 GetDelegateForFunctionPointerptr 将导入为System.IntPtr。 通过调用 GetFunctionPointerForDelegate 可以为托管委托获得 System.IntPtr,然后作为参数传递;此后可以从非托管方法中调用。 注意,在 .NET Framework 2.0 及更高版本中,参数封送拆收器还可将函数指针封送到委托。

GetDelegateForFunctionPointer 方法具有下列限制:

  • 在互操作方案中不支持泛型。

  • 不能将无效的函数指针传递给此方法。

  • 此方法只能用于纯非托管函数指针。

  • 不能将此方法用于通过 C++ 或从 GetFunctionPointer 方法获取的函数指针。

  • 此方法不能用于由指向另一托管委托的函数指针创建委托。

.NET Framework 安全性
  • SecurityCriticalAttribute 

    需要完全信任直接调用方。此成员不能由部分受信任或透明的代码使用。

函数:Marshal.GetFunctionPointerForDelegate

(将委托转换为可从非托管代码调用的函数指针)

publicstatic IntPtr GetFunctionPointerForDelegate(
    Delegate d
)
参数
d
类型: System.Delegate
要传递给非托管代码的委托。
返回值
类型: System.IntPtr
一个可传递给非托管代码的值,非托管代码使用该值来调用基础托管委托。
异常
异常条件
ArgumentException

d 参数是泛型类型。

ArgumentNullException

d 参数为 nullNothingnullptrnull 引用(在 Visual Basic 中为 Nothing)

备注

委托 d 转换为可使用 __stdcall 调用约定传递给非托管代码的函数指针。

必须以手动方式阻止垃圾回收器从托管代码中回收该委托。垃圾回收器不跟踪对非托管代码的引用。

例如一个函数指针定义为:

typedef int (*FUN)(int iType,void *pvArgs);

而一个委托定义为:

public delegate int TEST_DLGT(int iType, IntPtr pvArgs);

则可以通过如下方法完成他们之间的互相转换
        public delegate int TEST_DLGT(int iType, IntPtr pvArgs);

        public Form1()
        {
            TEST_DLGT funCallBack1 = new TEST_DLGT(this.testfun);
            IntPtr pvFun = Marshal.GetFunctionPointerForDelegate(funCallBack1);//可将pvFun强制转化为void*,再强制转化为FUN类型
            TEST_DLGT funCallBack12 = (TEST_DLGT)Marshal.GetDelegateForFunctionPointer(pvFun, typeof(TEST_DLGT));
        }

在托管C++中,则应写为:

int ClassName::Start(TEST_DLGT ^funCallBack1)//委托通常在托管代码(C#)中创建,传入由托管C++封装的类库。这里假设ClassName是一个CLR类库的接口类。
{
	FUN pfun1=(FUN)(void*)Marshal::GetFunctionPointerForDelegate(funCallBack1);
	TEST_DLGT ^funCallBack2=(TEST_DLGT^)Marshal::GetDelegateForFunctionPointer((IntPtr)(void*)pfun1, TEST_DLGT::typeid);
	return 0;
}

----------------------------EOB--------------------------------

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C语言中,无法直接调用C#的System.IO读取文件。但是可以使用C#开发一个DLL动态链接库,然后在C语言中通过调用该DLL中的函数来实现读取文件的功能。 以下是一个示例代码: 首先,在C#中创建一个类库项目,将以下代码添加到类文件中: ``` using System.IO; using System.Runtime.InteropServices; namespace MyFileReader { public class FileReader { [DllImport("kernel32.dll")] private static extern bool SetDllDirectory(string lpPathName); [DllImport("kernel32.dll")] private static extern IntPtr LoadLibrary(string lpFileName); [DllImport("kernel32.dll")] private static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName); [DllImport("kernel32.dll")] private static extern bool FreeLibrary(IntPtr hModule); public static string ReadFile(string filePath) { // 将DLL所在目录添加到系统路径中 SetDllDirectory(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)); // 加载DLL IntPtr hModule = LoadLibrary("MyFileReader.dll"); // 获取函数指针 IntPtr pReadFile = GetProcAddress(hModule, "ReadFile"); // 转换函数指针委托 ReadFileDelegate readFile = (ReadFileDelegate)Marshal.GetDelegateForFunctionPointer(pReadFile, typeof(ReadFileDelegate)); // 调用函数 string result = readFile(filePath); // 释放DLL FreeLibrary(hModule); return result; } [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate string ReadFileDelegate(string filePath); } } ``` 这里定义了一个名为FileReader的类,其中包含一个名为ReadFile的静态方法,用于读取指定文件的内容。在ReadFile方法中,首先通过DllImport来引入kernel32.dll,然后使用LoadLibrary函数加载MyFileReader.dll,再使用GetProcAddress函数获取MyFileReader.dll中的ReadFile函数的指针,最后将该指针转换为委托并调用该委托。注意,ReadFile函数的调用约定必须是Cdecl。这里使用了UnmanagedFunctionPointer属性来指定。 接下来,在C#中创建另一个控制台应用程序项目,将以下代码添加到Main方法中: ``` string filePath = @"C:\file.txt"; string fileContent = FileReader.ReadFile(filePath); Console.WriteLine(fileContent); ``` 这里调用了FileReader类的ReadFile方法读取名为file.txt的文件的所有内容,并将其输出到控制台。 最后,在C语言中,可以使用LoadLibrary函数加载MyFileReader.dll,然后使用GetProcAddress函数获取MyFileReader.dll中的ReadFile函数的指针,并将该指针转换为函数指针,最后调用该函数指针即可。 以下是一个示例代码: ``` #include <stdio.h> #include <Windows.h> typedef char*(*ReadFileFunc)(char*); int main() { HMODULE hModule = LoadLibrary("MyFileReader.dll"); if (hModule == NULL) { printf("无法加载DLL\n"); return 1; } ReadFileFunc pReadFile = (ReadFileFunc)GetProcAddress(hModule, "ReadFile"); if (pReadFile == NULL) { printf("无法获取函数指针\n"); FreeLibrary(hModule); return 1; } char* filePath = "C:\\file.txt"; char* fileContent = pReadFile(filePath); printf("%s", fileContent); FreeLibrary(hModule); return 0; } ``` 这里使用LoadLibrary函数加载MyFileReader.dll,然后使用GetProcAddress函数获取MyFileReader.dll中的ReadFile函数的指针,并将该指针转换为函数指针。最后调用该函数指针读取名为file.txt的文件,并将其输出到控制台。注意,这里需要使用双反斜杠("\\")来表示文件路径中的单个反斜杠。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值