C#调用C/C++的DLL问题若干

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试试。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值