静态库
当程序与静态库连接时,库中目标文件所含的所有将被程序使用的函数的机器码被 copy 到最终的可执行文件中。这就会导致最终生成的可执行代码量相对变多,相当于编译器将代码补充完整了,优点,这样运行起来相对就快些。不过会有个缺点: 占用磁盘和内存空间. 静态库会被添加到和它连接的每个程序中, 而且这些程序运行时, 都会被加载到内存中. 无形中又多消耗了更多的内存空间。
动态库
与共享库连接的可执行文件只包含它需要的函数的引用表,而不是所有的函数代码,只有在程序执行时, 那些需要的函数代码才被拷贝到内存中。优点,这样就使可执行文件比较小, 节省磁盘空间,更进一步,操作系统使用虚拟内存,使得一份共享库驻留在内存中被多个程序使用,也同时节约了内存。缺点,不过由于运行时要去链接库会花费一定的时间,执行速度相对会慢一些,总的来说静态库是牺牲了空间效率,换取了时间效率,共享库是牺牲了时间效率换取了空间效率
下面用两个接口分别实现动态库的调用及回调
- dll实现加法运行,应用程序调用dll,将加法结果计算出;
- dll实现加法运行,应用程序调用dll,将加法结果计算出;并且将计算过程通过回调返回给应用程序(实际应用中是比加法更加复杂,这里只是)
DllAPI.h
#ifndef __DLLAPI_DEF__
#define __DLLAPI_DEF__
typedef void (CALLBACK* CallBackFun)(bool bRet);
extern "C" int _declspec(dllexport) add(int x, int y);
extern "C" int _declspec(dllexport) addEx(int x, int y, CallBackFun fun);
#endif
DllAPI.cpp
#include "stdafx.h"
#include "DllAPI.h"
int add(int x, int y)
{
return x + y;
}
int addEx(int x, int y, CallBackFun fun)
{
int a = x + y;
//处理流程...
//处理完成,返回状态传给应用程序
bool bRet = true;
fun(bRet);
return a;
}
3 创建动态库,dll中定义和实现接口
MyDLL.h
#ifndef __MYDLL_DEF__
#define __MYDLL_DEF__
#include <Windows.h>
#include <atlstr.h>
#include <string>
using namespace std;
//回调定义
typedef void (CALLBACK* CallBackAdd)(bool bRet);
//宏定义函数指针类型
typedef int(*lpAddFun)(int, int);
typedef int(*lpAddFunEx)(int, int, CallBackAdd);
//函数指针声明
extern lpAddFun addFun;
extern lpAddFunEx addFunEx;
bool LoadCtrl(CString strPath);
void FreeCtrl();
#endif
MyDLL.cpp
#include "stdafx.h"
#include "MyDLL.h"
HINSTANCE g_hCtrlInstance = NULL;
//函数指针
lpAddFun addFun = NULL;
lpAddFunEx addFunEx = NULL;
bool LoadCtrl(CString strPath)
{
g_hCtrlInstance = LoadLibrary(strPath);
if (!g_hCtrlInstance)
{
return false;
}
addFun = (lpAddFun)GetProcAddress(g_hCtrlInstance, "add");/*用addFun取代dll库中的add函数*/
addFunEx = (lpAddFunEx)GetProcAddress(g_hCtrlInstance, "addEx");
return true;
}
void FreeCtrl()
{
FreeLibrary(g_hCtrlInstance);
}
4 应用程序调用DLL
#include "stdafx.h"
#include "MyDLL.h"
#include <stdio.h>
void CALLBACK CallBackAddFunRet(bool bRet)
{
if (bRet)
{
printf("回调成功,bRet=true");
}
else
{
printf("回调成功,bRet=false");
}
}
int _tmain(int argc, _TCHAR* argv[])
{
if (!LoadCtrl(_T("DLL.dll")))
{
return -1;
}
int nSum = addFun(1, 2);
int nSumEx = addFunEx(3, 4, CallBackAddFunRet);
FreeCtrl();
return 0;
}
5 例子下载
上述代码已经实现并且编译通过,有兴趣可以通过如下链接进行下载
(61条消息) C++,动态调用dll,dll也是由c++实现,且实现了回调功能,即应用程序将函数传入到dll,由dll接口调用函数,以实现回调-C++文档类资源-CSDN文库
6 相应接口参考
Dynamic-Link Library Functions - Win32 apps | Microsoft Docs
The following functions are used in dynamic linking.
Function | Description |
Adds a directory to the process DLL search path. | |
Disables thread attach and thread detach notifications for the specified DLL. | |
An optional entry point into a DLL. | |
Decrements the reference count of the loaded DLL. When the reference count reaches zero, the module is unmapped from the address space of the calling process. | |
Decrements the reference count of a loaded DLL by one, and then calls ExitThread to terminate the calling thread. | |
Retrieves the application-specific portion of the search path used to locate DLLs for the application. | |
Retrieves the fully qualified path for the file containing the specified module. | |
Retrieves the fully qualified path for the file containing the specified module. | |
Retrieves a module handle for the specified module. | |
Retrieves a module handle for the specified module. | |
Retrieves the address of an exported function or variable from the specified DLL. | |
Maps the specified executable module into the address space of the calling process. | |
Maps the specified executable module into the address space of the calling process. | |
Maps the specified packaged module and its dependencies into the address space of the calling process. Only Windows Store apps can call this function. | |
Removes a directory that was added to the process DLL search path by using AddDllDirectory. | |
Specifies a default set of directories to search when the calling process loads a DLL. | |
Modifies the search path used to locate DLLs for the application. |