前面先介绍了静态链接库的方式提供了函数结构的方法,现在就来说下,如果用非MFC的动态链接库要怎么实现,这个过程稍微复杂一点点,但是基本也都是一个套路下来。
1、新建一个工程:
2、编写cpp文件和头文件,这里有两种方式:
(1)、新建工程之后会有相应的cpp文件,可以直接在cpp文件中编写:
(2)、新建新的.h/.cpp文件进行编写:
3、编译生成lib文件和dll文件:
4、新建调用工程:
这里要注意几点:
(1)、typedef int(*lpAddFun)(int, int);宏定义函数指针类型,该定义是与将要调用函数的形式一样的,也就是输入参数和返回值都要一样,函数名称可以不同;
(2)、hDll = LoadLibrary(L"noMFCdllSrc.dll");是加载dll文件进来,一定要注意L"noMFCdllSrc.dll"前面有个大写的L,不加这个的话会报错,涉及到const char*跟LP LPCWSTR数据类型的转换问题,函数返回值的类型如下:
(3)、addFun = (lpAddFun)GetProcAddress(hDll, "add");获取函数add在dll文件中的地址;
(4)、使用完函数之后记得调用FreeLibrary来释放内存;
(5)、使用dll只需要将相关的dll文件放置在工程调用到的位置即可,不需要将.h文件和.lib文件一起拷贝过来;
(6)、如果需要在调用的工程中进入函数调试的话,暂时不知道;
(7)、DLL内的函数分为内部函数和外部函数,内部函数是无法通过调用dll来给外部使用,只能是dll内部使用,因此,要提供给外部使用的话,需要在函数声明处添加__declspec(dllexport),前面是两个下划线,即可声明为导出函数。
5、声明DLL的另一种方式是采用模块定义(.def)文件声明,.def文件为连接器提供了关于被链接程序的导出、属性和其他方面的信息,需要在dll工程中添加.def文件:
(1)、声明def文件:
def文件规则:
a、LIBRARY语句声明了.def文件对应的dll文件;
b、EXPORT语句后面跟随的是导出函数名,导出函数名后面的@数字表示导出函数的序号,在调用函数的时候可以用;
c、def文件中的注释由每个注释行开始处的分号指定,并且注释不可以和代码语句同一行。
(2)、调用,通过def文件定义后,要调用dll的方式跟基本前面一样的但是在获取函数地址的时候要通过下面这种方式来获取:
这一步我应该是没有尝试的,后面有尝试的话再来更新。
6、DLL的调用分为动态调用和静态调用:
(1)、动态调用,前面的方式都属于动态调用,就是三个步骤:“LoadLibrary-GetProcAddress-FreeLibrary”;
(2)、静态调用:编译系统完成对dll的加载,应用程序结束完成对DLL的卸载,也就是说调用dll的应用程序的数量系统中有记录,每结束一个计数减一直到调用dll的所有应用程序都结束了,才释放。静态调用需要将dll文件和lib文件一起使用不需要修改编写dll的程序,只是调用dll的程序需要修改调用方式:
其中,语句含义如下:
#pragma comment(lib, "noMFCdllSrc.lib") //同前面静态链接库的链接方式一样
extern "C" int __declspec(dllimport)add(int, int); //则是声明导入函数;
静态调用的过程:在工程中导入lib文件,在应用程序中,lib文件将作为DLL的替代文件参与编译;然后声明导入函数,调用。
7、dll函数的入口DLLMain函数
提供dll的时候并没有提供DllMain函数,系统会引入一个不做任何操作的缺省DllMain函数,但是在编写dll的时候,DllMain还是必须的;DllMain不能被引用,只能被系统加载和卸载dll、单个线程启动或者终止的时候自动调用;
函数输入:
APIENTRY是宏定义#define APIENTRY WINAPI
而WINAPI则是宏定义#define WINAPIV __cdecl,这表示函数以标准Pascal的方式调用
win32中,HMODULE的值和HINSTANCE一样,进程中每个dll模块都被全局唯一的32字节的HINSTANCE句柄标识,只有在特定的进程内部有效,并且,这个HINSTANCE代表了dll模块在进程虚拟空间中的起始位置。
8、__stdcall声明
VC++编写的程序要被其他语言调用,必须将函数的调用方式声明为__stdcall,WINAPI都采用这种方式;但是C/C++默认是__cdecl,这两种方式生成的符号不同:采用C编译的时候,__stdcall调用约定在函数名前加下划线,后加@数字,如”_add@1”;但是,__cdecl声明的只在前面加下划线,如”_add”;
所以,如果在dll中声明为int __stdcall add(int x, int y);的话,在调用的时候就要声明为typedef int(__stdcall *lpAddFun)(int, int);否则会报错。
大概就写到这里,这里还有导出变量和类的做法,还没有尝试,就先不写了,后面有尝试的话会补上的。
春风动春心,流目瞩山林。
山林多奇采,阳鸟吐清音。
-- 佚名 《子夜四时歌·春风动春心》