使用Signature Tool自动生成P/Invoke调用Windows API的C#函数声明

本文深入探讨了在.NET环境中调用C/C++ API及自定义DLL函数时,结构体在C#中的正确声明与转换问题。详细列举了结构体定义常见挑战及解决方案,包括ANSI和Unicode DLL处理、数组与联合体的正确表示、结构体在不同平台的兼容性、优化问题等。此外,介绍了一款辅助工具P/InvokeInteropAssistant,帮助开发者简化互操作过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://blog.youkuaiyun.com/Donjuan/article/details/3865026 

 

在网上看到很多网友在.NET程序中调用Win32 API,或者调用自己的VC DLL里面提供的函数的时候,总是被生成正确的C函数在C#中的正确声明而困扰,而生成C++中结构体在C#中的声明 - 天,没有什么比这个更让人恶心的事情了。因为:

1.         如果你的结构体里面包含 TCHAR字符串成员的话,需要考虑ANSI和Unicode DLL的情形。

2.         如果你的结构体里面包含数组成员,需要考虑定长的数组,而不是对应C#数据类型。

3.         如果你的结构体里面包含联合体(UNION),需要使用Explict选项,如果联合体里面又包含结构体。

4.         你还要考虑你的结构体可以同时在32位和64位机上运行。

5.         你还要考虑C编译器对结构体所作的PADDING的优化。

6.         你还要考虑在.NET里面对结构体的优化,例如CLR会将一些.NET struct的成员的次序变换—以便更有效地利用内存。

7.         如果你的结构里面还包含了其他的结构体。

8.         如果你的结构体里面还包含函数指针……

9.         如果你的结构体里面包含函数指针数组。

10.     如果你的结构体里面包含了指针……

11.     如果你的结构体里面有一些成员是被所调用的C函数所设置的。

12.     CLR提供了几种结构体的布局选项,什么Auto,什么Explicit,什么Sequential

13.     有的结构体的情况是上面说的情形的综合,想想我们的VARIANT结构吧。

 

如果结构体定义错误的话,在使用的时候,CLR只是简简单单地抛出一个AccessViolationException,真是叫天天不应,叫地地不灵。

 

另外还有一种情形就是在C中定义.NET的结构体对应的声明,这样C或者C++程序可以使用这个结构,调用.NET的类库提供的一些函数,这个转换也是一个痛苦的过程。

 

看起来微软自己也是深受.NET蹩脚的P/Invoke支持的毒害,因此无奈之余发布了P/Invoke Interop Assistant工具,你可以去下面这个链接来下载这个工具:

http://download.microsoft.com/download/f/2/7/f279e71e-efb0-4155-873d-5554a0608523/CLRInsideOut2008_01.exe

 

实际上这个工具已经开源了,你可以从这里

http://www.codeplex.com/clrinterop/

下载到它的源代码。

 

简单介绍一下它的用法

自动生成Native函数或者结构在.NET程序中的声明,切换到“SigImp Translate Snippet”标签,然后将Native函数或者结构的声明拷贝到“Native Code Snippet”文本框里面,然后选中“Auto Generate”对话框,点击“Generate”就可以获取对应的.NET声明,如下图所示:

 

查找Win32 API中在.NET中的声明,选择“SigImp Search”,并在“Name”文本框里面输入你要查找的函数或者结构名称就可以了,如下图所示:

 

验证或者生成.NET函数(或结构)在C 中的声明,切换到“SigExp”并且打开一个包含P/Invoke函数调用的.NET Assembly就可以了,这个程序会显示对应的C的声明,并且告诉你C#声明编写错误的地方:

.NET应用程序中,经常需要调用Windows API来执行某些系统级别的操作。对于获取系统时间这个需求,我们可以使用P/Invoke机制来调用Win32 API中的GetLocalTime函数。在调用之前,需要导入相应的DLL并声明函数原型。以下是具体的操作步骤和示例代码: 参考资源链接:[深入探索.NET互操作:P/Invoke, C++ Interop与COM Interop](https://wenku.csdn.net/doc/88v0ncwus8?spm=1055.2569.3001.10343) 1. 引入必要的命名空间和使用P/Invoke特性。首先,我们需要在C#代码中引入System.Runtime.InteropServices命名空间,该命名空间提供了与非托管代码交互所需的功能。 2. 声明外部函数原型。我们将使用System.Time结构体来接收返回的系统时间,并声明GetLocalTime函数作为外部调用。 3. 编写调用函数的代码。通过声明的函数原型,我们可以编写一个调用GetLocalTime函数的方法,并将返回的系统时间打印出来。 4. 注意内存管理问题。由于使用了非托管代码,因此需要注意内存管理,确保不会发生内存泄漏。 示例代码如下(代码略)。 在上述代码中,我们通过定义函数原型和调用GetLocalTime函数,成功地在.NET程序中使用P/Invoke调用Windows API获取了系统时间。掌握了如何使用P/Invoke调用Win32 API之后,你将能够扩展你的.NET应用程序的功能,使用更多的系统级操作。 如果你希望深入理解P/Invoke以及.NET互操作的其他方面,比如C++ Interop和COM Interop,并在实际应用中更有效地利用这些技术,建议参阅《深入探索.NET互操作:P/Invoke, C++ Interop与COM Interop》。这本书不仅提供了丰富的示例,还详细介绍了.NET互操作的原理和最佳实践,是.NET开发者必备的参考资料。 参考资源链接:[深入探索.NET互操作:P/Invoke, C++ Interop与COM Interop](https://wenku.csdn.net/doc/88v0ncwus8?spm=1055.2569.3001.10343)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值