静态链接库(lib)与动态链接库(dll)的比较:
首先,静态链接库与动态链接库都是共享代码的方式,也可称为程序模块化的方式;
静态链接库:
lib中的指令都被直接包含在最终的EXE中,因此exe运行时不再需要lib文件;
不能再包含其他的动态链接库或者静态库;
动态链接库:
dll与EXE文件独立存在,所以发布EXE时需要同时发布dll文件;
可以再包含其他的动态链接库或者静态库;
建议:
请最好使用动态链接库(dll)进行程序的模块化,静态链接库(lib)过时了(应用程序升级上就能看出其劣势);
常用DLL查看工具 :
Dumpbin命令 或 VC++ 自带的Depends工具,可以查看某个[dll档的导出信息]或某个[exe调用的dll信息]。
DLL注意事项:
对于DLL的生成:
请谨慎使用exetern “C”;//这种方式可读性虽高,但不支持重载等;【优劣并存】
请不要使用模块定义(.def) 文件;//因为这种方式不够灵活;【目前def过时了】
不要忘了使用__declspec(dllexport) 与 __declspec(dllimport);
对于编译、运行:
请拷贝dll文件,.lib文件,.h文件到exe主目录(只要保证编译时exe能看到dll相关
的信息即可);【通常做法是组织好源代码的层次并设置好project->setting】
对于发布:
dll文件需与exe文件一起发布。
显示(动态)调用方式与隐式(静态)调用方式的比较:
显示(动态)调用方式的特点是完全由编程者用 API 函数加载和卸载 DLL,程序员可以决定 DLL 文件何时加载或不加载,调用方式灵活。
隐式(静态)方式的特点是由编译系统完成对DLL的加载和应用程序结束时 DLL 的卸载。静态调用方式简单易用,但不如动态调用方式灵活。
建议:
所谓的显、隐就是针对LoadLibrary (“.dll”)而言的;
请最好使用隐式(静态)方式,因为dll导出接口没用extern “C” 修饰的情况下,显示
(动态)调用可读性极差;而不论是否使用过extern “C”,隐式调用的接口名都与dll接口定义相同。
静态链接库、动态链接库、MFC的联系与区别:
使用静态链接库 还是 动态链接库 是一回事,用不用MFC又是另一回事!换句话说就是lib和dll都能使用MFC。
三类动态链接库的比较:
Non-MFC:
不采用MFC类库编写,而是采用标准C风格,导出的dll接口与标准C函数类似;
可被MFC或非MFC程序调用;
总结:(一般规则是:当程序不涉及MFC时创建该类型的dll)
Regular-MFC:
与下面的Extension-MFC类似,采用MFC类库编写,最明显的特点就是包含有一个
CwinApp的派生;
在导出的dll接口中可以使用MFC的类库,但接口本身不能是MFC类或其派生类;
它又可分为静态链接到MFC的规则dll(using MFC in static library)与动态链接(共享)到
MFC的规则dll(using MFC in shared dll);
可被任何支持DLL的语言调用(前提是要采用_stdcall约定);【我不想关心调用约定】
总结:(好处是可以在dll接口中使用MFC类库)【可使用但不可导出MFC】
Extension-MFC:
采用MFC类库编写;
不仅dll接口中可以使用MFC的类库,导出的接口本身也可以是MFC类或其派生类,常用其来增强MFC的现有功能;
只能被MFC程序调用;
总结:(好处是可以用来增强MFC类库的现有功能)
两种规则DLL(Regular-MFC DLL)的比较:
静态链接到MFC的规则dll(using MFC in static library):
DLL接口中默认就使用DLL自己的资源,因此不需要进行模块的资源句柄切换;
使用这种方法生成的规则DLL较大,因为代码可能会重复包含;
总结:(好处是不需模块的资源句柄切换,但dll通常较大)
动态链接(共享)到MFC的规则dll(using MFC in shared dll):
DLL接口中默认使用的是exe的资源,所以,在DLL 接口中为了使用DLL它自己的资源或是为了解决资源重复问题(当DLL和主应用程序中存在相同ID的资源时),必须进行模块的资源句柄切换。
总结:(好处是dll通常较小,但必须进行模块的资源句柄切换)
动态链接(共享)到MFC的规则dll(using MFC in shared dll)时进行模块资源句柄切换的两种方法:
1. dll接口函数中完成资源模块的切换工作:
//dll接口函数中切换
extern CSharedDllApp theApp;
void ShowDlg(void)
{
//状态变更
HINSTANCE save_hInstance = AfxGetResourceHandle();
AfxSetResourceHandle(theApp.m_hInstance);
CDialog dlg(IDD_DLL_DIALOG);//dll资源
dlg.DoModal();
//状态还原
AfxSetResourceHandle(save_hInstance);
//在此处再进行操作针对的将是应用程序的资源
CDialog dlg1(IDD_DLL_DIALOG);// 应用程序的资源
dlg1.DoModal();
}
在应用程序需要的地方完成切换工作:
//应用程序中切换
void CSharedDllCallDlg::OnCalldllButton()
{
//获取EXE模块句柄
HINSTANCE exe_hInstance = GetModuleHandle(NULL);
//获取DLL模块句柄
HINSTANCE dll_hInstance = GetModuleHandle("SharedDll.dll");
AfxSetResourceHandle(dll_hInstance); //切换状态
ShowDlg(); //此时显示的是DLL的对话框
AfxSetResourceHandle(exe_hInstance); //恢复状态
ShowDlg(); //此时显示的是exe的对话框
}
关于DllMain的说明:
对于No-Mfc的dll及 Extension-Mfc的dll,由MFC自动提供一个;
对于Regular-Mfc,没有定义DllMain时编程环境会自动调用一个默认版本;
总结:(也不是没有用处,在DllMain中可以作一些初始化或者是资源回收等工作)
关于lib库文件的说明:
->>何时用到lib库文件
如果程序中采用隐式(静态)调用dll的话,编译时会需要lib库文件。
动态链接库或静态链接库在exe最终发布时都不需要.lib,.lib只可能在编译期用到。
->>关于将.lib文件导出到特定目录:
"project"-> "settings"-> general-> output files 里面设置;
还可以在Pre-link step和Post-build step属性页里增加命令将文件拷贝到相应的目录,如:
copy debug\my.lib (特定目录)\my.lib
copy debug\my.dll (特定目录)\my.dll
参考:http://topic.csdn.net/t/20041222/15/3667256.html
我采用的Post-build step。编辑copy命令行时要注意,它不支持/而只能用\;
另外还要保证指定的copy目录是存在的,否则编译会出错,它不会给你自动创建。
->>怎样指明lib库文件的位置给linker
若采用隐式调用,链接时需要指明lib的位置,有两种方法:
1) 使用 #pragma comment(lib,"XX.lib");
2) project->setting->LINK选项卡中的Object/Library modules:填写lib文件的路径;或tools->Options->Directories内设置inc和lib的路径;
//比如dll文件为DllClass.dll,则填写 Release/DllClass.lib(此处仅是示例,请注意目录)
前者比后者好的原因是当源文件搬迁给其他用户时,人家不用再去设置Project->setting...
关于纯资源dll:
编写“纯资源dll”:http://hi.baidu.com/pop1210/blog/item/144192b5c6d867da36d3caa5.html
编写“纯资源dll”之二:http://hi.baidu.com/pop1210/blog/item/39a76acc5b1cf10400e92830.html
调用约定, Def文件:
一些调用约定对dll的影响,用Def导出(过时)什么的,不想搞了,否则搞复杂了都。