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。