DLL(Dynamic Link Library),动态链接库。
1.关于__declspec(dllimport)和__declspec(dllexport)
在一个DLL的编写过程中,如果要使一个变量、一个函数或一个类能够被外部程序调用,在函数声明上加上__declspec(dllimport)关键字。
例:
引出一个变量:
__declspec(dllexport) int iEx;
引出一个函数:
__declspec(dllexport) int fnEx( int i );
引出一个类:
class __declspec(dllexport) CClassEx
{……};
在外部程序引用DLL时,如果采用隐式调用的方法(关于隐式调用稍后讨论),需要包含DLL文件相关的头文件,这个头文件用__declspec(dllimport)关键字指出了DLL导出的内容(实际上就是把原来的__declspec(dllexport)全部替换为__declspec(dllimport))。
例:
引入一个变量:
__declspec(dllimport) int iEx;
引入一个函数:
__declspec(dllimport) int fnEx( int i );
引入一个类:
class __declspec(dllimport) CClassEx
{……};
为了提高程序可读性,可以定义如下宏:
#define DllImport __declspec(dllimport)
#define DllExport __declspec(dllexport)
以便使用。
实际上一般定义如下宏:
#ifdef MYDLL_EXPORTS
#define
MYDLL_API
__declspec
(
dllexport
)
#else
#define
MYDLL_API
__declspec
(
dllimport
)
#endif
这样,在源程序的实现文件中先定义
MYDLL_EXPORTS
,再包含这个头文件;在外程序内,可以直接包含这个头文件。这种方法可以实现一个文件多种用途。
2
.隐式调用和显式调用
隐式调用是最常用的一种调用方法。它需要原
DLL
文件、原头文件和库文件组成。在程序内要包含这个头文件,并加入库文件一同编译。在程序启动时会把所有隐式调用的
DLL
文件加载到内存。
如果想在使用的时候才把
DLL
文件加入到内存的话,可以使用显式调用。显式调用只需要原
DLL
文件即可,但是使用时必须对知道这个
DLL
有哪些导出的符号。可以在
VS
的命令行方式下输入“
depends
”命令来查看
DLL
信息。
示例:
隐式调用:
#include
"..\DllTest\DllTest.h"
……
void
CallDll(
void
)
{
wchar_t
wszBuf[ 32 ];
wsprintf( wszBuf, TEXT(
"%d"
), fnDllTest( 9 ) );
//fnDllTest
是DLL文件导出的方法
wprintf( wszBuf );
}
显式调用:
void
CallDll(
void
)
{
typedef
int
(*ADDPROC)(
int
i );
ADDPROC Fn;
HINSTANCE hInst = LoadLibrary( L
"DllTest.dll"
);
if
( NULL == hInst )
{
wprintf( L
"Failed on load DLL."
);
return
;
}
Fn = ( ADDPROC )GetProcAddress( hInst,
"fnDllTest"
);
//
如果导出时使用的是_stdcall, 那么这里我们也应该使用(_stdcall ADDPROC)
if
( !Fn )
wprintf( L
"Failed on get Process Address."
);
else
{
int
i;
i = Fn( 9 );
wchar_t
wszBuf[ 32 ];
wsprintf( wszBuf, L
"%d"
, i );
wprintf( wszBuf );
}
FreeLibrary(hInst);
//
释放DLL
/*
* ADDRPROC Add = (ADDPROC)GetProcAddress(hInst, "add");
*
第而个参数也可以使用序号:
* MAKEINTRESOURCE(1)
代替函数名.
*/
}
3
.注意事项
如果使用
C++
编程,那么在程序编译的时候会为变量名等符号重命为诸如“
?fnDllTest@QAEAAV
0
”
之类的形式,为显式调用带来了不便。针对这个问题,我们可以为要导出的符号加上“
extern “C”
”修饰符,就可以保持原有名称。但是导出的类名仍然是重命名后的名称,要再研究研究。
如果你使用MFC生成MFC DLL那么只要做如下定义就可以了class AFX_EXT_CLASS yourClass。