一。DLL的创建
// DLLTest.h
#ifdef __cplusplus
#define EXPORT extern "C" __declspec (dllexport)
#else
#define EXPORT __declspec (dllexport)
#endif
EXPORT int fun(int a,int b);
//#ifdef DLLTest_EXPORTS //导出方法二
//#define DLLTest_API __declspec(dllexport)
//#else
//#define DLLTest_API __declspec(dllexport)
//#endif
//extern "C" DLLTest_API int fun(int a,int b); //自己写的 extern "C" 不可少
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"
#include "DLLTest.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
int fun(int a,int b) //自己写的函数
{
int d = a*b;
return d;
}
//DLLTest_API int fun(int a,int b) //自己写的函数
//{
// int d = a*b*2;
// return d;
//}
二。DLL的两种链接方式:隐式链接和显式链接
共有两种库:
一种是LIB包含了函数所在的DLL文件和文件中函数位置的信息(入口),代码由运行时加载在进程空间中的DLL提供,称为动态链接库dynamic link library。
一种是LIB包含函数代码本身,在编译时直接将代码加入程序当中,称为静态链接库static link library。
关于lib和dll的区别如下:
(1)lib是编译时用到的,dll是运行时用到的。如果要完成源代码的编译,只需要lib;如果要使动态链接的程序运行起来,只需要dll。
(2)如果有dll文件,那么lib一般是一些索引信息,记录了dll中函数的入口和位置,dll中是函数的具体内容;如果只有lib文件,那么这个lib文件是静态编译出来的,索引和实现都在其中。使用静态编译的lib文件,在运行程序时不需要再挂动态库,缺点是导致应用程序比较大,而且失去了动态库的灵活性,发布新版本时要发布新的应用程序才行。
(3)动态链接的情况下,有两个文件:一个是LIB文件,一个是DLL文件。LIB包含被DLL导出的函数名称和位置,DLL包含实际的函数和数据,应用程序使用LIB文件链接到DLL文件。在应用程序的可执行文件中,存放的不是被调用的函数代码,而是DLL中相应函数代码的地址,从而节省了内存资源。DLL和LIB文件必须随应用程序一起发行,否则应用程序会产生错误。如果不想用lib文件或者没有lib文件,可以用WIN32 API函数LoadLibrary、GetProcAddress装载。
(1)隐式链接
第一种方法是:添加lib附加依赖项: 项目-》属性-》链接器-》输入-》附加依赖项 -》添加Lib.lib文件(或者在源代码中加入指令#pragma comment(lib, “Lib.lib”)),并将.dll文件置入工程所在目录,然后添加对应的.h头文件。
// TestDLLX.cpp : 定义控制台应用程序的入口点。采用隐式链接DLL
#include "stdafx.h"
#include <stdio.h>
#include <Windows.h>
#include "DLLTest.h" //加入头文件
#pragma comment(lib,"../Debug/DLLTest.lib")
int _tmain(int argc, _TCHAR* argv[])
{
printf("输入:");
int b,c;
scanf("%d %d",&b, &c);
int d = fun(b,c);
printf("the result is: %d \n",d);
system("pause");
return 0;
}
(2)显式链接
需要函数指针和WIN32 API函数LoadLibrary、GetProcAddress装载,使用这种载入方法,不需要.lib文件和.h头文件,只需要.dll文件即可(将.dll文件置入工程目录中)。
// TestDLL.cpp : 定义控制台应用程序的入口点。 显式链接DLL
#include "stdafx.h"
#include <stdio.h>
#include <Windows.h>
typedef int (*DLLFUN)(int,int); //声明函数原型
int _tmain(int argc, _TCHAR* argv[])
{
HMODULE hModule = ::LoadLibrary("../Debug/DLLTest.dll");//加载DLL库
if (hModule == NULL)
{
FreeLibrary(hModule);
}
DLLFUN newfun = (DLLFUN)::GetProcAddress(hModule,"fun");//取得fun函数的地址
if (newfun == NULL)
{
FreeLibrary(hModule);
}
printf("输入:");
int b,c;
scanf("%d %d",&b, &c);
int d = newfun(b,c);
printf("the result is: %d \n",d);
::FreeLibrary(hModule);//释放指定多态链接库
system("pause");
return 0;
}
使用LoadLibrary显式链接,那么在函数的参数中可以指定DLL文件的完整路径;如果不指定路径,或者进行隐式链接,Windows将遵循下面的搜索顺序来定位DLL:
(1)包含EXE文件的目录
(2)工程目录
(3)Windows系统目录
(4)Windows目录
(5)列在Path环境变量中的一系列目录