DLL與Lib

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章