C# 调用C++ DLL 总结

 1 方法一:
 C#项目中,“引用”右键,添加引用,在浏览里面添加C++ DLL库,如果添加成功,你是幸运的,但是成功概率为98%,或者根本不可能。
 如果失败会提示:未能添加对“E:\HuangTao\dll\avcodec-tl.dll”的引用。请确保此文件可访问并且是一个有效的程序集或 COM 组件。
 网上的解决方法是在CMD中使用 ”regsvr32 E:\HuangTao\dll\avcodec-tl.dll“ 命令,成功概率也很小。如果是C#写的DLL那就没问题了。

 2 方法二: 使用DllImport加载DLL
 1 项目属性--引用路径--添加DLL路径,即添加存放DLL目录
 2 使用DllImport时要添加 using System.Runtime.InteropServices 域名空间;
 3 使用DllImport关键字时,不要在函数里使用,有时候你定义了域名空间,但是没有这个关键字,是因为Dlli放的位置错了。
 4 使用方法:
 [DllImport("TLHDEXFSDK_APP.dll", EntryPoint = "TLHDEXFSDK_APP_Init",CharSet = CharSet.Unicode,CallingConvention = CallingConvention.StdCall)]
 public static extern int TLHDEXFSDK_APP_Init();
 说明:EntryPoint 要调用的函数 CallingConvention 函数,CharSet 表示DLL的字符编码 TLHDEXFSDK_APP_Init()函数,注意是函数原型,但是要使得C#与C++中定义一致。

 3 实例:
 场景:在C++ TLHDEXFSDK_APP.dll 中有2个函数,一个初始化设备,一个是连接设备的
 C++ 原型:[厂家给的DLL,技术文档,*.h 文件,可能有些误差,使用eXeScope.exe查看DLL文件内的实际函数名]
 LRESULT TLHDEXFSDK_APP_Init();// LRESULT 为long类型
 TLHDEXFSDK_APP_API LRESULT __stdcall TLHDEXFSDK_APP_Login(char *pchAryDeviceIP, DWORD dwPort, char *pchAryUserName, char *pchAryPassword, STLEncodeDeviceInfo &struDeviceInfo,BOOL bDeviceMode = FALSE);
 (TLHDEXFSDK_APP_API LRESULT __stdcall实际上就是LRESULT)

 C# 使用
 // 设备初始化
 [DllImport("TLHDEXFSDK_APP.dll", EntryPoint = "TLHDEXFSDK_APP_Init",CharSet = CharSet.Unicode,CallingConvention = CallingConvention.StdCall)]
 public static extern int TLHDEXFSDK_APP_Init();

 // 登录设备
 [DllImport("TLHDEXFSDK_APP.dll", EntryPoint = "TLHDEXFSDK_APP_Login",CharSet = CharSet.Unicode,CallingConvention = CallingConvention.StdCall)]
 public static extern int TLHDEXFSDK_APP_Login(char[] strDeviceIP, int dwPort, char[] strUserName, char[] strPassword, ref STLEncodeDeviceInfo devInfo, bool devModel);

 当然在C#这样定义之前要定义结构体,结构体的变量,函数要一样。
 C++中的结构体是这样的
 struct STLEncodeDeviceInfo
 {
   HANDLE hDeviceID; //设备唯一标识
   char chAryIPAddress[TLENCODEHD_LEN_IPADDRESS];//IP地址
   char chArySerialNumber[TLENCODEHD_MAX_STRING]; //序列号
   char chAryAdditional[TLENCODEHD_MAX_STRING];  //附加标识串
   char chAryDeviceName[TLENCODEHD_MAX_STRING]; //设备名称
   E_TLENCODE_DEVICEMODEL eDeviceType; //设备类型
   E_TL_USERLEVEL eUserLevel;//当前用户级别

   STLEncodeDeviceInfo():hDeviceID(NULL),eDeviceType(HDEX1000F) //C#中可以不要,这个是初始化的
   {
     memset(chArySerialNumber, 0, sizeof(char) * TLENCODEHD_MAX_STRING);
     memset(chAryAdditional, 0, sizeof(char) * TLENCODEHD_MAX_STRING);
     memset(chAryDeviceName, 0, sizeof(char) * TLENCODEHD_MAX_STRING);
   }
 };

 C#中的定义
 [StructLayout(LayoutKind.Sequential,CharSet = CharSet.Unicode)]
 public  struct STLEncodeDeviceInfo
 {
  public IntPtr hDeviceID; //设备唯一标识

  [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
  public char[] chAryIPAddress;//IP地址

  [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
  public char[] chArySerialNumber; //序列号

  [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
  public char[] chAryAdditional;  //附加标识串

  [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
  public char[] chAryDeviceName; //设备名称

  public E_TLENCODE_DEVICEMODEL eDeviceType; //设备类型
  public  E_TL_USERLEVEL eUserLevel;//当前用户级别
 };

 值得注意的是:引用要用ref关键字
 准备工作做好之后开始调用了

 public STLEncodeDeviceInfo devInfo = new STLEncodeDeviceInfo();//设备信息

 int retInit = TLHDEXFSDK_APP_Init();//初始化设备 成功返回0 失败返回-1

 char[] ipAdd = new char[32];
 char[] uName = new char[32];
 char[] uPwd = new char[16];

 ipAdd = ipAddress.Text.ToArray();//界面控件值
 uName = userName.Text.ToCharArray();
 uPwd = Passworld.Text.ToCharArray();
 int portNumber = Convert.ToInt32(port.Text);

 int retLogin = TLHDEXFSDK_APP_Login(ipAdd, portNumber, uName, uPwd, ref devInfo, false);//成功返回 0 失败返回-1

 这样做了之后,运行程序,只有TLHDEXFSDK_APP_Login函数 返回-1,这个时候有点麻烦了,因为TLHDEXFSDK_APP_Login函数只给了原型,在DLL中看不到TLHDEXFSDK_APP_Login是怎样工作的。
 厂家没有给TLHDEXFSDK_APP_Login函数源码。这是个大问题啊,后来这里试一下那一试一下就弄好了。代码就这么多,没有报错,很多都不知道,只有试试了。
 最后发现,这样加载 [DllImport("TLHDEXFSDK_APP.dll")]奇迹般好了。在试一下发现去掉CharSet = CharSet.Unicode就可以了,估计厂家给的DLL编码不是用Unicode写吧!就这些搞了2天,看了好多帖子,总算弄好了。
 现在总结下:
 1 结构体定义要一致,C#读取DLL时,会将结构体与DLL的结构体匹配,变量名都要一样
 2 PInvoke签名的调用约定和参数与非托管的目标签名是否匹配,改CallingConvention的属性为CallingConvention.StdCall 或者 CallingConvention.Cdecl
 3 C++中函数有引用时,C#要加ref关键字
 4 结构体的调用要看C++ 与C#数据对应类型 可参考博客:

http://blog.csdn.net/taoerit/article/details/42215373

http://www.cnblogs.com/chuncn/archive/2011/12/20/2294096.html

 效果图:

C# 调用C++ DLL 总结_第1张图片

 

你可能感兴趣的:(C++,C#,dll,dllimport)