最近在项目中碰到需要调用非托管C++生成的dll,下面将自己遇到的问题,以及解决的办法总结如下:
1.
问题:
我们通常去映射dll的方法是使用
解决方案:
LoadLibrary(string lpFileName)是加载指定的dll文件,参数lpFileName为dll文件的路径,返回的为该dll的实例(指针)
GetProcAddress(IntPtr hModule,string lpProcName)是获取dll中指定的方法委托,参数hModule为LoadLibrary()方法返回的值,lpProcName方法名,返回值为指定方法的委托,注意要强制转换.
FreeLibrary(InPtr hModule)是释放加载的dll文件,参数hModule为LoadLibrary()返回值.
有了这些方法就能很容易的实现动态加载dll。
代码:
1.
问题:
我们通常去映射dll的方法是使用
public
const
string
dllPath
=
path;
[DllImport(dllPath + " test.dll " , EntryPoint = " test() " , SetLastError = true ,
CharSet = CharSet.Ansi, ExactSpelling = true , CallingConvention = CallingConvention.Cdecl)]
public static extern int test();
这种方式有一个致命的缺陷,dll文件路径dllPath必须为const,而const是编译时常量,也就是说dllPath赋值必须是字符串常量,如果你想动态指定dll文件路径用这种方式基本上没办法实现,下面是一种解决方案。[DllImport(dllPath + " test.dll " , EntryPoint = " test() " , SetLastError = true ,
CharSet = CharSet.Ansi, ExactSpelling = true , CallingConvention = CallingConvention.Cdecl)]
public static extern int test();
解决方案:
[DllImport(
"
Kernel32.dll
"
)]
public static extern IntPtr LoadLibrary( string lpFileName);
[DllImport( " kernel32.dll " , SetLastError = true )]
public static extern int GetProcAddress(
IntPtr hModule, string lpProcName);
[DllImport( " kernel32.dll " , EntryPoint = " FreeLibrary " , SetLastError = true )]
public static extern bool FreeLibrary(IntPtr hModule);
这种方式有点像C#的反射,先引入这3个API 函数:public static extern IntPtr LoadLibrary( string lpFileName);
[DllImport( " kernel32.dll " , SetLastError = true )]
public static extern int GetProcAddress(
IntPtr hModule, string lpProcName);
[DllImport( " kernel32.dll " , EntryPoint = " FreeLibrary " , SetLastError = true )]
public static extern bool FreeLibrary(IntPtr hModule);
LoadLibrary(string lpFileName)是加载指定的dll文件,参数lpFileName为dll文件的路径,返回的为该dll的实例(指针)
GetProcAddress(IntPtr hModule,string lpProcName)是获取dll中指定的方法委托,参数hModule为LoadLibrary()方法返回的值,lpProcName方法名,返回值为指定方法的委托,注意要强制转换.
FreeLibrary(InPtr hModule)是释放加载的dll文件,参数hModule为LoadLibrary()返回值.
有了这些方法就能很容易的实现动态加载dll。
代码:
//
dll实例
static private IntPtr instance;
// 要加载方法的委托
delegate void Test();
// 导入引擎dll
[DllImport( " Kernel32.dll " )]
public static extern IntPtr LoadLibrary( string lpFileName);
[DllImport( " kernel32.dll " , SetLastError = true )]
public static extern int GetProcAddress(
IntPtr hModule, string lpProcName);
[DllImport(" kernel32.dll " , EntryPoint = " FreeLibrary " , SetLastError = true)]
public static extern bool FreeLibrary(IntPtr hModule);
// 获取方法指针
static private Delegate GetAddress(IntPtr dllModule, string functionname, Type t)
{
int addr = GetProcAddress(instance, functionname);
if (addr == 0)
return null;
else
return Marshal.GetDelegateForFunctionPointer(new IntPtr(addr), t);
}
// 加载DLL
static public void LoadLib()
{
string dllPath;
dllPath = ConfigurationSettings.AppSettings["dllPath"].ToString();
instance = LoadLibrary(dllPath);
if (instance.ToInt32() == 0)
{
throw new LoadLibraryException("请在App.Config中配置引擎DLL的路径!");
}
}
/// <summary>
/// 卸载DLL
/// </summary>
static public void FreeLib()
{
FreeLibrary(instance);
}
/// <summary>
/// 实例
/// </summary>
/// <param name="iptr"></param>
/// <returns></returns>
static public void test()
{
try
{
Test temp = (Test)GetAddress(instance, "test", typeof(Test));
return temp();
}
catch (Exception ex)
{
throw new LoadLibraryException("");
}
static private IntPtr instance;
// 要加载方法的委托
delegate void Test();
// 导入引擎dll
[DllImport( " Kernel32.dll " )]
public static extern IntPtr LoadLibrary( string lpFileName);
[DllImport( " kernel32.dll " , SetLastError = true )]
public static extern int GetProcAddress(
IntPtr hModule, string lpProcName);
[DllImport(" kernel32.dll " , EntryPoint = " FreeLibrary " , SetLastError = true)]
public static extern bool FreeLibrary(IntPtr hModule);
// 获取方法指针
static private Delegate GetAddress(IntPtr dllModule, string functionname, Type t)
{
int addr = GetProcAddress(instance, functionname);
if (addr == 0)
return null;
else
return Marshal.GetDelegateForFunctionPointer(new IntPtr(addr), t);
}
// 加载DLL
static public void LoadLib()
{
string dllPath;
dllPath = ConfigurationSettings.AppSettings["dllPath"].ToString();
instance = LoadLibrary(dllPath);
if (instance.ToInt32() == 0)
{
throw new LoadLibraryException("请在App.Config中配置引擎DLL的路径!");
}
}
/// <summary>
/// 卸载DLL
/// </summary>
static public void FreeLib()
{
FreeLibrary(instance);
}
/// <summary>
/// 实例
/// </summary>
/// <param name="iptr"></param>
/// <returns></returns>
static public void test()
{
try
{
Test temp = (Test)GetAddress(instance, "test", typeof(Test));
return temp();
}
catch (Exception ex)
{
throw new LoadLibraryException("");
}
}
//mydll.cpp
int f(int a, char* b, int* c)
{
return(10);
}
//mydll.def
LIBRARY MyDll
EXPORTS
f @1
//c#
[DllImport("mydll.dll")]
public static extern int f(int a,StringBuilder b,ref int c);
static void Main(string[] args)
{
StringBuilder b=new StringBuilder(10);
int c=0;
Console.WriteLine("{0}",f(10,b,ref c));
}