DLL
目標:寫幾個比較簡單的dll並瞭解**.dll與**.lib的關係。
一:沒有lib的dll
1.1建一個沒有lib的dll
1) 新建一個com_1.cpp文件(注意此dll根本沒有什麼用)
2) 在com_1.cpp寫下下面的代碼
3) 按下F5運行,所有的東西都按確定。
4) 應該出現如下錯誤:
Linking...
Creating library Debug/COM_1.lib and object Debug/COM_1.exp
LIBCD.lib(crt0.obj) : error LNK2001: unresolved external symbol _main
Debug/COM_1.exe : fatal error LNK1120: 1 unresolved externals5)進入 project|setting,在 "C/C++" 屬性框的 "project Options" 裏把
"/D ''_console''" 修改成"/D ''_WINDOWS''"。
6)進入project|setting,在 "link" 屬性框的 "project Options" 裏增加下
面的編譯開關 "/dll "
增加的編譯開關大致如下:
kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib
ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:yes
/pdb:"Debug/COM_1.pdb" /debug /machine:I386 /out:"Debug/COM_1.dll" /implib:"Debug/COM_1.lib"
/pdbtype:sept 注意:"/dll"應該與後面的開關之間有一個空格
//com_1.cpp
#include <objbase.h>
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, void* lpReserved)
{
HANDLE g_hModule;
switch(dwReason)
{
case DLL_PROCESS_ATTACH:
g_hModule = (HINSTANCE)hModule;
break;
case DLL_PROCESS_DETACH:
g_hModule=NULL;
break;
}
} 現在可以編譯了,這小片段代碼將會生成一個dll,但這個dll是沒有用的。沒有引出函數和變量。
1.2 調試沒有 lib 的 dll
1) 新建一個工程 Client,工程類型爲 console,將上面創建的 dll copy 到 client 工程目錄下
2) 增加 Client.cpp(代碼見下)到工程 Client 中去
3) 選中 Client 工程,並在 project|setting|debug|Category 下拉框,如圖:
圖1.4 調試
注意這是一種調試 dll 的方法
5) 現在可以在Client和COM_1.dll裏打斷點調試了。
在這裏我們只能調試DllMain()函數,因爲那個dll裏除了就沒別的東西了,下面我開始 增加一點東西。
二:帶有lib的dll
2.1 創建一個帶有lib的dll
我們在原來的基礎上讓上面的代碼產生一個lib了。新的代碼如下:
#include <objbase.h>
extern "C" __declspec(dllexport) void tulip (void)
{
::MessageBox(NULL,"ok","I''am fine",MB_OK);
}
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, void* lpReserved)
{
HANDLE g_hModule;
switch(dwReason)
{
case DLL_PROCESS_ATTACH:
g_hModule = (HINSTANCE)hModule;
break;
case DLL_PROCESS_DETACH:
g_hModule=NULL;
break;
}
return TRUE;
}在這個dll裏,我們引出一個tulip函數。如果此時我們想要在客戶調用此函數應該用什麼方法呢?
上面的代碼除了生成dll外,他比第一個程序多產生一個lib文件,現在應該知道dll與lib的關係吧。Lib文件是dll輸出符號文件。如果一個dll沒有任何東西輸出那麼不會有對應的lib文件,但只要一個dll輸出一個變量或函數就會相應的lib文件。總的說來,dll與lib是相互配套的。
當某個dll他有輸出函數(或變量)而沒有lib文件時,我們應該怎麼調用 dll 的函數呢?請看下面的方法。
2.2 調試帶有引用但沒有頭文件的 dll
注意:本方法根本沒有用 COM_1.lib 文件,你可以把 COM_1.lib 文件刪除而不影響。
此時的客戶端代碼如果下:
#include <windows.h>
int main(void)
{
//定義一個函數指針
typedef void ( * TULIPFUNC )(void);
//定義一個函數指針變量
TULIPFUNC tulipFunc;
//加載我們的dll
HINSTANCE hinst=::LoadLibrary("COM_1.dll");
//找到dll的tulip函數
tulipFunc=(TULIPFUNC)GetProcAddress(hinst,"tulip");
//調用dll裏的函數
tulipFunc();
return 0;
}對於調用系統函數用上面的方法非常方便,因爲對於User32.dll,GUI32.dll這種dll,我沒有對應的lib,所以一般用上面的方法。
三:帶有頭文件的dll
3.1 創建一個帶有引出信息頭文件的dll
如果用上面的方法調用我們自己創建的dll那太煩了!因爲我們的dll可能沒有像window這樣標準化的文檔。可能過了一段時間後,我們都會忘記dll內部函數的格式。再如當我們把此dll發佈客戶時,那個客戶肯定會在背後罵你的!
這時我們需要一個能瞭解dll引出信息途徑。我創建一個.h文件。繼續我們旅途。
我們的dll代碼只需要修改一點點,代碼如下:
#include <objbase.h>
#include "header.h"//看到沒有,這就是我們增加的頭文件
extern "C" __declspec(dllexport) void tulip (void)
{
::MessageBox(NULL,"ok","I''am fine",MB_OK);
}
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, void* lpReserved)
{
HANDLE g_hModule;
switch(dwReason)
{
case DLL_PROCESS_ATTACH:
g_hModule = (HINSTANCE)hModule;
break;
case DLL_PROCESS_DETACH:
g_hModule=NULL;
break;
}
return TRUE;
}而 header.h文件只有一行代碼:
extern "C" __declspec(dllexport) void tulip (void); 3.2 調試帶有頭文件的dll
而此時我們的客戶程序應該變成如下樣子:(比第二要簡單多了)
#include <windows.h>
#include "../header.h"//注意路徑
//注意路徑,加載 COM_1.lib 的另一種方法是 Project | setting | link 設置裏
#pragma comment(lib,"COM_1.lib")
int main(void)
{
tulip();//只要這樣我們就可以調用dll裏的函數了
return 0;
} 四:小結
今天講了三種 dll 形式,第一種是沒有什麼實用價值的,但能講清楚 dll 與 lib 的關係。我們遇到的情況大多數是第三種,dll 的提供一般會提供 **.lib 和 **.h 文件,而第二種方法適用於系統函數。
希望各位高手指正與交流,
注:今天一時興起,寫了上面的東西,本來我是總結一下有關 COM 的東西,但寫着寫着就成這個樣子,COM 也是從 dll 起步的。
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/wsxqaz/archive/2006/10/09/1327232.aspx