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
效果图: