使用C#或其他语言时经常会引用到DLL,分享一些学习笔记。
DLL(Dynamic Linkable Library),提供一些可以拿来用的变量,函数或类。 静态与动态链接库都是共享代码的方式,如果采用静态链接库,则无论愿不愿意,lib中的指令都被直接包含在最终生成的EXE文件中了。但是如果使用DLL,该DLL不必被包含在最终EXE文件中,EXE文件执行时可以“动态”引用和卸载这个与EXE独立的DLL文件。
1、DLL的编制与具体的编程语言及编译器无关
只要遵守约定的DLL接口规范和调用方式,用各种语言编写的DLL都可以相互调用,像JAVA,C#调用C++编写的DLL。
在windows下的system32文件夹中可以看到许多.dll windows的大多数API都包含在这些DLL。像MessageBox函数就包含在user32.dll这个动态链接库中.
2、静态库编译
在VS下创建一个win32控制台应用程序,选择静态库,添加C++类,添加代码,完成后右击文件属性页,选择常规-输出目录-….\lib,选择平台工具集xp(保证兼容性)-编译,此时在lib文件夹中会生成文件。
在新的想要引用静态库的程序中,添加以上添加好代码的头文件.h,-右键进入属性页-选择C/C++-附加包含目录-(输入静态库头文件的目录)-链接器-常规-附加库目录….\lib-链接器-输入-附加依赖项-添加刚生成的.lib。
除了以上方法设置路径使用静态库,还可以在主程序中,添加头文件
#pragma comment(lib,"xxx.lib")//xxx代表需要引用的静态库
这样做的话就要把设置路径中的文件删除,防止多重定义。
3、DLL动态链接库编译
在VS下创建一个win32控制台应用程序,选择DLL(可以勾选导出符号,简便),看见新生成的dll.cpp等,dllmain.cpp作为自己用的动态库,可以不用过多关注,如果是多个程序的入口,则需要关注进程线程函数处理。添加代码,完成后右击文件属性页,选择常规-输出目录-….\dll,右键解决方案-属性-项目依赖项-选择主程序依赖于DLL。
右键主程序属性-链接器-常规-附加库目录-…..
常规-输出目录-….\bin;平台工具集xp;dll属性页-链接器-高级-导入库把
$(OutDir)改为..\..\lib;
#pragma comment(lib,"xxx.lib")//xxx代表需要引用的静态库
使用.lib编译,程序不灵活,跨语言不方便,在函数前加extern “C”可以使函数不重载,告诉编译器是C语言,名字不会改动。这样的话把引用的头文件,库文件,引用函数都删掉。
加以下代码:
#include<windows.h>;
typedef int(*DLLFUN)(void);生成一个函数指针
并在主函数main中加
HMODULE hdll = LoadLibrary(L"xx.dll");
if(!hdll){return -1;}
DLLFUN fun = GetProcAddress(hdll,"fndll");
fun();
FreeLibrary(hdll);//释放动态链接库
这种方法比较灵活,在很多项目都有用到,使扩展代码变得非常容易。
另外,看你要引用的dll是托管的还是非托管的。如果是托管的dll直接添加引用就可以,如果是非托管的有一段成熟代码可以拿来用
private object DllInvoke(string strDllFileName, string strNameSpace, string strClassName, string strDllProcName, object[] objArrayParams)
{
try
{
Assembly mAssembly = Assembly.LoadFrom(strDllFileName);
Type[] mTypes = mAssembly.GetTypes();
foreach (Type mType in mTypes)
{
if (mType.Namespace == strNameSpace && mType.Name == strClassName)
{
MethodInfo mMethod = mType.GetMethod(strDllProcName);
if (mMethod != null)
{
object mObject = Activator.CreateInstance(mType);
return mMethod.Invoke(mObject, objArrayParams);
}
else
{
//MessageBox.Show("Load Report Dll File Failed!");
}
}
}
}
catch (Exception mEx)
{
MessageBox.Show(mEx.Message);
}
return null;
}
strDllFileName,你引用的dll文件名
strNameSpace,名称空间,不用说了吧
strClassName,dll的类名
strDllProcName,接口过程名
objArrayParams,接口过程参数表