動態鏈接庫英文為DLL,是Dynamic Link Library的縮寫。DLL是一個包含可由多個程序,同時使用的代碼和數據的庫 --------------百度百科
下面我們使用vs2010創建一個可供win32程序使用的dll
-
打開vs2010,點擊新建項目
- 新建一個win32項目
-
點擊下一步
- 新建一個空的dll項目
-
右鍵源文件,添加,新建項
- 新建一個c文件
- 同樣的在頭文件里新建一個h文件
-
然后就可以開始寫代碼了
每一個dll都有一個入口函數,這個入口函數叫做 DLLMain
這個東西咱暫時用不到,就先不寫了,如果你生成的是標准的dll文件,這個入口函數就會出現在你的源代碼中。然后就可以開始寫函數了,在寫函數之前,先介紹一下dll中的規則
- 函數前面要加上修飾符 如__declspec(dllexport) 他的意思是 declear spece dll export 聲明這是一個導出的dll函數。
- windows要求dll函數要加上修飾符CALLBACK (但這只是windows要求,dll要是不是給windows應用程序用的就不用加上這個)。
- 用extern "c"來表明使用c語言的規則解釋函數
函數:
__declspec(dllexport) void GiaoWarningA() { MessageBoxA(NULL,"giao","warning",MB_OK); return; }
__declspec(dllexport) void GiaoWarningW() { MessageBoxW(NULL,L"giao",L"warning",MB_OK); return; } |
一般winapi中的函數都有兩個版本,一個是ascii碼版本,一個是unicode版本,windows使用宏來自動選擇,例如
//編碼判斷 #ifdef UNICODE #define GiaoWarning GiaoWarningA
#else #define GiaoWarning GiaoWarningW
#endif |
我們也可以借鑒這種思想,來自動選擇是否加上extern "C"
例如
//語言判斷 #ifdef __cplusplus #define EXPORT extern "C" __declspec (dllexport) #else #define EXPORT __declspec (dllexport) #endif |
了解了這些我們就可以開始寫我們的頭文件了
頭文件giao.h
//語言判斷 #ifdef __cplusplus #define EXPORT extern "C" __declspec (dllexport) #else #define EXPORT __declspec (dllexport) #endif
//函數聲明 EXPORT void CALLBACK GiaoWarningA(); EXPORT void CALLBACK GiaoWarningW();
//編碼判斷 #ifdef UNICODE #define GiaoWarning GiaoWarningA
#else #define GiaoWarning GiaoWarningW
#endif |
注意這三塊代碼我擺放的順序
- 語言判斷 聲明了EXPORT宏
- 函數聲明 使用了EXPORT宏
- 編碼判斷 使用函數名創建了統一函數名的宏
另外還有一點,在函數聲明中EXPORT void CALLBACK的順序可別弄亂了
這個CALLBACK是win32函數所需的,必須包含windows.h,
CALLBACK可以不用
EXPORT void CALLBACK GiaoWarningA(); |
源文件giao.c
#include "giao.h" #include <Windows.h>
EXPORT void CALLBACK GiaoWarningA() { MessageBoxA(NULL,"giao","warning",MB_OK); return; }
EXPORT void CALLBACK GiaoWarningW() { MessageBoxW(NULL,L"giao",L"warning",MB_OK); return; } |
源文件中的函數原型與頭文件中的一毛一樣
還有就是頭文件中要包含giao.h和函數用到的頭文件
-
然后右鍵項目,點擊生成
- 右鍵giao點擊打開所在的文件夾
-
返回到上一級目錄
共有三個重要的文件 giao.h giao.lib giao.dll - 進入這一級的Debug目錄
-
然后就找到了全部的三個文件
-
如何使用動態鏈接庫
使用動態鏈接庫的方法有兩種,一種是啟動時加載,一種是運行時加載我們先來將如何在 啟動時加載鏈接庫
-
啟動時加載鏈接庫
我們依然還是新建一個win32項目 - 直接點擊完成
- 右鍵打開項目所在文件夾
- 將之前的giao.h giao.lib giao.dll全都復制到這里
-
添加頭文件 giao.h
-
添加鏈接庫導入文件 giao.lib
注意lib和dll的名字是你dll項目的名字,而h文件的名字是你創建的時候指定的,不要弄混了,還有這里千萬不要寫成wdnmd.dll要不然會出錯,而且編譯器也發現不了。 - 開始使用
我是把函數放在WM_PAINT里了,你也可以放在其他地方,
- 運行結果
-
運行時加載動態鏈接庫
我們會用到兩個函數,LoadLibrary,GetProcAddress功能是加載動態鏈接庫,獲取函數地址
-
定義一個宏,創建兩個變量
因為我們會用到函數地址,就要用函數指針來保存這個函數地址
而且因為我們要對GetProcAddress返回的地址進行強制類型轉換,所以我們要定義一個宏來代替一個函數指針的類型還有一個實例句柄用來操作動態鏈接庫
typedef void (*FUC)(); FUC fuc; HINSTANCE hlibrary; |
然后
hlibrary = LoadLibraryA("wdnmd.dll"); fuc = (FUC)GetProcAddress(hlibrary,"GiaoWarningA"); fuc(); |
這里我遇到了一些問題,GetProcAddress的返回值一直都是NULL,好像是函數名有問題。
找到了一些解決的方法,但也不是太好
關於__stdcall 導出的函數名為: _函數名@0 (0為參數所占的總字節數)
__fastcall 導出的函數名為: @函數名@0 (同上)
__cdel 導出的函數名為: 函數名
啥都不加 導出的函數名為: 函數名
windows要求的CALLBACK其實就是這個__stdcall,所以可以按照他的導出格式,去調用函數。如 fuc = (FUC)GetProcAddress(hlibrary,"_GiaoWarningA@0");