1. C/C++封送为C#代码
辅助工具:操作系统API可以访问PINVOKE.NET站点查询;若有C/C++的头文件声明,使用P/Invoke Interop Assistant工具,它不仅能获得操作系统API的封送代码,还能将C/C++的头文件代码转换为C#封送代码,但可能需要进一步手动调整些结构体的声明。
技术文章:阅读《CLR 完成介绍:托管代码与非托管代码之间的封送处理》、《CLR 全面透彻解析:托管和本机代码互操作性最佳实践》。
2. PInvokeStackImbalance异常
当C/C++的库的入口点调用约定(CallingConvention)未正确指定,导致调用堆栈的参数类型与原生代码不平衡时,会出现此异常,但不影响操作。
例如:
C/C++:
_declspec(dllexport) int OnReceiveFile(char* strIP, int nPort, char* strPath, BYTE *data, long &ldataLen);
封送的C#:/// Return Type: int ///strIP: char* ///nPort: int ///strPath: char* ///data: BYTE* ///ldataLen: &ldataLen [DllImport("TransferDataClintDll.dll", EntryPoint = "?OnReceiveFile@@YAHPADH0PAEAAJ@Z", CharSet = CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] public static extern int OnReceiveFile(string strIP, int nPort, string strPath, byte[] data, ref long ldataLen);
注意:C++的"_declspec"和C#的“CallingConvention=CallingConvention.Cdecl”另外,可以通过VS的异常窗口,取消掉对 PInvokeStackImbalance异常的检测:
点击VS的“调试 - 异常”,打开异常窗口,展开选择“Managed Debugging Assistants\PInvokeStackImbalance”,去掉对应的“引发”可选框。
3. 找不到入口点
如果是C++写的库,但没有标记为C接口方式,需要利用VS命令提示符的dumpbin和undname命令,得到导出的入口函数名(EntryPoint):
Setting environment for using Microsoft Visual Studio 2010 x86 tools. C:\Program Files\Microsoft Visual Studio 10.0\VC>cd d:\demo C:\Program Files\Microsoft Visual Studio 10.0\VC>d: d:\demo>dumpbin /exports TransferDataClintDll.dll Microsoft (R) COFF/PE Dumper Version 10.00.40219.01 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file TransferDataClintDll.dll File Type: DLL Section contains the following exports for TransferDataClintDll.dll 00000000 characteristics 4DEF3826 time date stamp Wed Jun 08 16:51:50 2011 0.00 version 1 ordinal base 8 number of functions 8 number of names ordinal hint RVA name 1 0 000023F0 ?CopyFileFromServerToLocal@@YAHPADH00@Z 2 1 00002540 ?CopyFolderFromServerToLocal@@YAHPADH00@Z 3 2 000024A0 ?DeleteFileA@@YAHPADH0@Z 4 3 000025F0 ?GetDiskInfo@@YAHPADH0AAH1@Z 5 4 000023E0 ?OnCloseDll@@YAHXZ 6 5 00002250 ?OnInit@@YAHXZ 7 6 00002340 ?OnReceiveFile@@YAHPADH0PAEAAJ@Z 8 7 00002290 ?OnSendFile@@YAHPADH0PAEJ@Z Summary 1000 .data 2000 .rdata 1000 .reloc 1000 .rsrc 3000 .text d:\demo>undname ?OnReceiveFile@@YAHPADH0PAEAAJ@Z Microsoft (R) C++ Name Undecorator Copyright (C) Microsoft Corporation. All rights reserved. Undecoration of :- "?OnReceiveFile@@YAHPADH0PAEAAJ@Z" is :- "int __cdecl OnReceiveFile(char *,int,char *,unsigned char *,long &)" d:\demo>
通过dumpbin /exports TransferDataClintDll.dll命令,获得TransferDataClintDll.dll的全部导出函数入口点名称,比如“?OnReceiveFile@@YAHPADH0PAEAAJ@Z”——它就是用来封送成C#代码中DllImport特性的EntryPoint值。然后还可以通过undname ?OnReceiveFile@@YAHPADH0PAEAAJ@Z命令,将它还原声明信息。
4. 找不到函数库
如果C/C++函数库不在应用程序目录里,那么它可以在的位置由系统环境变量Path指定的位置里检索,若都没找到,则找不到函数库。
需要注意一点,重新配置系统的环境变量Path后,需要重启动.NET Framework运行环境,也就是说,最好重新启动下电脑,.NET Framework运行环境会重新读取Path环境变量。
另外,还可以用Environment.SetEnvironmentVariable方法,使当前进程附加PATH环境变量信息,如:
Environment.SetEnvironmentVariable("PATH", @"D:\Demo", EnvironmentVariableTarget.Process);
5. 乱码
在DllImport特性里,设置属性CharSet=CharSet.Ansi试试。