dll是windows编程非常常用的技术之一;通过孙鑫教程学习和windows核心编程学习;由浅入深简单总结一下:
隐式链接:
(1)最简单的dll
在vs环境下,新建dll工程,然后新建对应的“dll1.cpp”;编辑最简单一个函数
//dll1.cpp int dllfun(int a,int b) { return a*b; }//运行会生成dll1.dll
//testdll.cpp ..... extern int dllfun(int a,int b); //(引用之前,需要输入dll文件路径,导入在link->object/library modules 加入 dll1.dll) //或者是和 #pragma comment(lib,"dll1.lib") main() { dllfun(1,2); }
(2)使用__declspec(dllexport)
__declspec(dllexport) 表示导出,只要导出还是在dumpbin中可以查看到 改进上面dll1.dll中代码为: __declspec(dllexport) int dllfun(int a,int b) { return a*b; }//运行会生成dll1.dll ,同时多生成dll1.lib
改进 testdll.cpp为:(提前导入dll1.lib和dll1.dll)
__declspec(dllimport) int dllfun(int a,int b); (等价于 extern int dllfun(int a,int b); )
.......//其它相同
我们可以通过“dumpbin -imports dllTest.exe” 查看输入信息 ,也可以通过Dependency工具查看exe和dll;
(3)对dll文件,进一步的优化,dll中包含“.h”文件
在dll 增加“.h”文件;既可以dll自身方便使用,也可以方面外部调用
改进工程dll1; 新建dll1.h //link->object/library modules 加入 dll1.lib
// dll1.h #ifdef DLL1_API #else #define DLL1_API extern "C" _declspec(dllimport) // extern "C" 保证了,编译后在dumpbin查看,函数名称不变; #endif DLL1_API int _stdcall dllfun(int a,int b); //dll1.cpp #define DLL1_API extern "C" _declspec(dllexport) #include "Dll1.h" #include <Windows.h> #include <stdio.h> ............ int dllfun(int a,int b) //int __stdcall dllfun(int a,int b) ; 及时使用extern "C" ,dumpbin下函数名称还是变化“dllfun@8” { return a*b; } ............ 在dlltest工程中,testdll.cpp (拷贝"Dll1.h",“dll1.dll”、“dll1.lib”到dlltest工程下) #include "Dll1.h" ....... dllfun(1,2); ......
(4)dll中导出“类”和“类中的函数”
// dll1.h #ifdef DLL1_API #else #define DLL1_API _declspec(dllimport)//注意不能使用#define DLL1_API extern "C" _declspec(dllimport) #endif class DLL_API classdll // 导出整个类 { public: void fun(); } /* class classdll // 导出类中的某个函数 { public: DLL_API void fun(); } */ //dll1.cpp #include "dll1.h" void classdll::fun() { //your code } dllTest工程中, dlltest.cpp #include "dll1.h" ...... classdll cd; cd.fun(); ......
动态加载:
(1)保持定义的函数名 不被改变,引入模块定义文件
在dll工程中可以,新建文件,引入“dll2.def”(def为模块定义文件,在此作用是在dll动态加载过程中保持dll函数名称不变;即dumpbin下查看dll输出,没有发生函数名转化)
//dll2.def LIBRARY DLL2 EXPORTS //注意单词拼写 add //dll2.cpp int _stdcall add(int a,int b) //或者int add(int a,int b) { return a+b; } int _stdcall subtract(int a,int b) //或者int subtract(int a,int b) { return a-b; }编译生成dll2.dll 通过dumpbin可以看到 导出的函数名没有被改变( 没有发生名字改编)
(2)动态加载:(隐士链接初始化,消耗太大)
直接copy “dll2.dll”到该工程下即可 不需要加载link->object.....
dllTest中:
HINSTANCE hInst; hInst=LoadLibrary("Dll3.dll"); typedef int (/*_stdcall*/ *ADDPROC)(int a,int b); //函数类型 ADDPROC Add=(ADDPROC)GetProcAddress(hInst,"add"); if(!Add) { MessageBox("获取函数地址失败!"); return; }在测试过程中 动态加载dll时候,本人还未在def文件中导出整个类;对类的导出 不能加 extern "C" ; 在隐士加载dll中,可以通过加载“.h”文件,引起类;动态加载中就如何导出呢?进一步解决中..........
dll入口函数DLLMain():(可选函数)
不要做复杂的操作,做一点内存分配等等