托管DLL和非托管DLL的区别
狭义解释讲,托管DLL就在Dotnet环境生成的DLL文件。非托管DLL不是在Dotnet环境生成的DLL文件。
托管DLL文件,可以在Dotnet环境通过 “添加引用” 的方式,直接把托管DLL文件添加到项目中。然后通过 Using DLL命名空间,来调用相应的DLL对象 。
非托管DLL文件,在Dotnet环境应用时,通过引入 using system.Runtime.InteropServices;再在代码中通过DllImport 调用。
功能:通过c#调用c++编写的DLL。
实现:用delegate申明函数委托进行调用,可进行回调并应用指针.
遇到的问题点:
1、getProcAddress返回的值是0,无法获得NATIVE DLL中的导出函数
检查调用的函数名和c++项目中的是否一致;
2、查看c++ dll的函数名
VIEWDLL可以查看导出dll函数的名称
3、托管调试助手 "PInvokeStackImbalance":“对 PInvoke 函数“**.**+_DLL_Test::Invoke”的调用导致堆栈不对称。原因可能是托管的 PInvoke 签名与非托管的目标签名不匹配。请检查 PInvoke 签名的调用约定和参数与非托管的目标签名是否匹配。”
程序可以执行以及返回正确结果,但仍然报错。
解决方案在我的另一篇博客 https://blog.youkuaiyun.com/u012482453/article/details/102894850
4、exception 值不能为 null。\r\n参数名: ptr System.ArgumentNullException
首先查看c++生成的DLL路径是否正确,以及调用的函数名是否正确
其次dll需要是c++项目生成的才可以,一开始我用c#项目生成了dll,无法用该方式调用
5、System.RuntimeType typeof DeclaringMethod 引发了类型 System.InvalidOperation
一开始觉得是typeof()报错,觉得是委托类型或传进的参数不对,后来发现是因为dll是c#生成导致的。
C#中,先定义将DLL函数地址转换成委托的类,方法以及封装参考: https://www.cnblogs.com/zeroone/p/3681379.html
C#调用C++的函数还有一种方法是用delegate申明函数委托进行调用,这种方法略显麻烦,但是可以进行回调并应用指针.
在C#中,定义一个类,用来把DLL中函数地址转换成委托:
public class DLLWrapper
{
///<summary>
/// API LoadLibrary
///</summary>
[DllImport("Kernel32")]
public static extern int LoadLibrary(String funcname);
///<summary>
/// API GetProcAddress
///</summary>
[DllImport("Kernel32")]
public static extern int GetProcAddress(int handle, String funcname);
///<summary>
/// API FreeLibrary
///</summary>
[DllImport("Kernel32")]
public static extern int FreeLibrary(int handle);
///<summary>
///通过非托管函数名转换为对应的委托, by jingzhongrong
///</summary>
///<param name="dllModule">Get DLL handle by LoadLibrary</param>
///<param name="functionName">Unmanaged function name</param>
///<param name="t">ManageR type对应的委托类型</param>
///<returns>委托实例,可强制转换为适当的委托类型</returns>
public static Delegate GetFunctionAddress(int dllModule, string functionName, Type t)
{
int address = GetProcAddress(dllModule, functionName);
if (address == 0)
return null;
else
return Marshal.GetDelegateForFunctionPointer(new IntPtr(address), t);
}
///<summary>
///将表示函数地址的IntPtr实例转换成对应的委托, by jingzhongrong
///</summary>
public static Delegate GetDelegateFromIntPtr(IntPtr address, Type t)
{
if (address == IntPtr.Zero)
return null;
else
return Marshal.GetDelegateForFunctionPointer(address, t);
}
///<summary>
///将表示函数地址的int转换成对应的委托,by jingzhongrong
///</summary>
public static Delegate GetDelegateFromIntPtr(int address, Type t)
{
if (address == 0)
return null;
else
return Marshal.GetDelegateForFunctionPointer(new IntPtr(address), t);
}
}
//函数封装DLL中的函数, hModule()函数的作用是取得DLL的地址,用在多个输出函数中
private int hModule()
{
int _hModule = DLLWrapper.LoadLibrary(DLLPATH);
if (_hModule == 0)
{
return 0;
}
return _hModule;
}
//用delegate声明函数
delegate void _amDBRInitialize (int mid, ref int errid);
private void amDBRInitialize()
{
try
{
_amDBRInitialize amf = (_amDBRInitialize)DLLWrapper.GetFunctionAddress(hModule(), "amDBRInitialize", typeof(_amDBRInitialize));
amf();
}
catch (Exception e)
{
throw e;
}
}