dll的優點
簡單的說,dll有以下幾個優點:
1) 節省記憶體。同乙個軟體模組,若是以源**的形式重用,則會被編譯到不同的可執行程式中,同時執行這些exe時這些模組的二進位製碼會被重複載入到記憶體中。如果使用dll,則只在記憶體中載入一次,所有使用該dll的程序會共享此塊記憶體(當然,像dll中的全域性變數這種東西是會被每個程序複製乙份的)。
2) 不需編譯的軟體系統公升級,若乙個軟體系統使用了dll,則該dll被改變(函式名不變)時,系統公升級只需要更換此dll即可,不需要重新編譯整個系統。事實上,很多軟體都是以這種方式公升級的。例如我們經常玩的星際、魔獸等遊戲也是這樣進行版本公升級的。
3) dll庫可以供多種程式語言使用,例如用c編寫的dll可以在vb中呼叫。這一點上dll還做得很不夠,因此在dll的基礎上發明了com技術,更好的解決了一系列問題。
最簡單的dll
開始寫dll之前,你需要乙個c/c++編譯器和鏈結器,並關閉你的ide。是的,把你的vc和c++ builder之類的東東都關掉,並開啟你以往只用來記**的記事本程式。不這樣做的話,你可能一輩子也不明白dll的真諦。我使用了vc自帶的cl編譯器和link鏈結器,它們一般都在vc的bin目錄下(若你沒有在安裝vc的時候選擇註冊環境變數,那麼就立刻將它們的路徑加入path吧)。【如果用vc的話步驟:新建專案-windows控制台程式-dll(注意下面有個「輸出符號」要根據情況選擇或不選)】
最簡單的dll並不比c的helloworld難,只要乙個dllmain函式即可,包含objbase.h標頭檔案(支援com技術的乙個標頭檔案)。若你覺得這個標頭檔案名字難記,那麼用windows.h也可以。源**如下:dll_nolib.cpp
#include
#include
bool apientry dllmain(handle hmodule, dword dwreason, void* lpreserved)
{handle g_hmodule;
switch(dwreason)
{case dll_process_attach:
cout<<"dll is attached!"《其中dllmain是每個dll的入口函式,如同c的main函式一樣。dllmain帶有三個引數,hmodule表示本dll的例項控制代碼(聽不懂就不理它,寫過windows程式的自然懂),dwreason表示dll當前所處的狀態,例如dll_process_attach表示dll剛剛被載入到乙個程序中,dll_process_detach表示dll剛剛從乙個程序中解除安裝。當然還有表示載入到執行緒中和從執行緒中解除安裝的狀態,這裡省略。最後乙個引數是乙個保留引數(目前和dll的一些狀態相關,但是很少使用)。
從上面的程式可以看出,當dll被載入到乙個程序中時,dll列印"dll is attached!"語句;當dll從程序中解除安裝時,列印"dll is detached!"語句。
編譯dll需要以下兩條命令:
cl /c dll_nolib.cpp
這條命令會將cpp編譯為obj檔案,若不使用/c引數則cl還會試圖繼續將obj鏈結為exe,但是這裡是乙個dll,沒有main函式,
因此會報錯。不要緊,繼續使用鏈結命令。
link /dll dll_nolib.obj
載入dll(顯式呼叫)
使用dll大體上有兩種方式,顯式呼叫和隱式呼叫。這裡首先介紹顯式呼叫。編寫乙個客戶端程式:dll_nolib_client.cpp
#include
#include
int main(void)
{//載入我們的dll
hinstance hinst=::loadlibrary("dll_nolib.dll");
if (null != hinst)
{cout<<"dll loaded!"並執行dll_nolib_client.exe,得到如下結果:
dll is attached!
dll loaded!
dll is detached!
以上結果表明dll已經被客戶端載入過。但是這樣僅僅能夠將dll載入到記憶體,不能找到dll中的函式。
使用dumpbin命令檢視dll中的函式【也可以用vs2005的工具depends.exe檢視】
dumpbin命令可以檢視乙個dll中的輸出函式符號名,鍵入如下命令:
dumpbin –exports dll_nolib.dll
通過檢視,發現dll_nolib.dll並沒有輸出任何函式。
如何在dll中定義輸出函式
總體來說有兩種方法,一種是新增乙個def定義檔案,在此檔案中定義dll中要輸出的函式;第二種是在源**中待輸出的函
數前加上__declspec(dllexport)關鍵字。
含def檔案的dll
首先寫乙個帶有輸出函式的dll,源**如下:dll_def.cpp
#include
#include
void funcindll (void)
{cout<<"funcindll is called!"《這個dll的def檔案如下:dll_def.def
library dll_def.dll
description "c)2007-2009 wang xuebin"
exports
funcindll @1 private
cl /c dll_def.cpp
link /dll dll_def.obj /def:dll_def.def
再呼叫dumpbin檢視生成的dll_def.dll:
dumpbin –exports dll_def.dll
得到如下結果:
dump of file dll_def.dll
file type: dll
section contains the following exports for dll_def.dll
0 characteristics
46e4ee98 time date stamp mon sep 10 15:13:28 2007
0.00 version
1 ordinal base
1 number of functions
1 number of names
ordinal hint rva name
1 0 00001000 funcindll
summary
2000 .data
1000 .rdata
1000 .reloc
6000 .text
觀察這一行
1 0 00001000 funcindll
會發現該dll輸出了函式funcindll。
顯式呼叫dll中的函式
寫乙個dll_def.dll的客戶端程式:dll_def_client.cpp
#include
#include
int main(void)
{//定義乙個函式指標
typedef void (* dllwithlib )(void);
//定義乙個函式指標變數
dllwithlib pffuncindll = null;
//載入我們的dll
hinstance hinst=::loadlibrary("dll_def.dll");
if (null != hinst)
{cout<<"dll loaded!"《有兩個地方值得注意,第一是函式指標的定義和使用,不懂的隨便找本c++書看看;第二是getprocaddress的使用,這個api是用來查詢dll中的函式位址的,第乙個引數是dll的控制代碼,即loadlibrary返回的控制代碼,第二個引數是dll中的函式名稱,即dumpbin中輸出的函式名(注意,這裡的函式名稱指的是編譯後的函式名,不一定等於dll源**中的函式名)。
dll loaded!
funcindll is called!
這表明客戶端成功呼叫了dll中的函式funcindll。
RAPI程式設計之一
今天剛開始學習rapi程式設計,先將今天學習的成果放出來,大家學習。如果 有問題,請提出,多謝 在pc上使用vc6,好久沒有用它了。一直在evc4下程式設計,呵呵.rapi功能的實現,需要rapi.dll和rapi.h。在以下的實現中,link的動態庫是c windows system32 rapi...
如何學習程式設計之一?
第乙個階段 什麼都不會。不會就先抄你老師給你們寫的例子,不准複製,要乙個字乙個字的敲。放心,其 中肯定會遇到問題,先自己想想問題怎麼解決,能解決就盡量自己解決,不能就 看你老師源 第二個階段 知道大概了。但是要自己寫還是寫不出來,這個時候你要先看你老師 知道大概的思路。然後你以自己的思路開始寫,開始...
小白談程式設計 之一
小白談程式設計 生產者消費者模式之串列埠資料的接收處理顯示 1 串列埠資料接收問題 2 資料快取類實現 3 多執行緒及其同步問題 4 子執行緒間資料傳遞問題 5 子執行緒資料如何實時更新到介面問題 6 窗體資料傳遞問題。問題這麼多?誰讓我是小白啊?小白的痛,小白懂!在開始這個題目之前,先介紹一下例項...