差異處

這裏顯示兩個版本的差異處。

連向這個比對檢視

cpp:dll:windows:howtousedll [2017/03/15 21:05]
tony [Reference]
cpp:dll:windows:howtousedll [2023/06/25 09:48]
行 1: 行 1:
-{{tag>​cpp dll}} 
-====== How to use DLL? ====== 
-===== Introduction ===== 
-網路上能夠找到許多和DLL相關的教學。但我相信大家看了之後依然會存在許多疑問,或者想只要會用就好並不會去了解更深一層的意義。有時我會想:​ 別人所撰寫的API,我們是不是應該至少要去了解其原理或設計呢?​ 如果一直當個只懂Call API的Programmer,而沒去學習更多解決問題的方法,只要換個語言應該就和廢人無異了吧! 言歸正傳,今天這篇教學是特地寫給Albert兄的,教導大家DLL使用的兩種方法:​ **裝載期間動態連結**與**執行期間動態連結**。我以範例來說明,讓大家可以迅速了解該如何使用(千言萬語抵不過Example Code吧?​)。\\ 
-{{:​cpp:​dll:​windows:​howtouserdll.zip|Download SourceCode}} 
-===== Write a DLL ===== 
-寫DLL相當簡單。如果是VC的用戶,直接透過Wizard產生出DDL的專案,基本的Skeleton都有了。其中的2個重點如下:​ 匯出函式宣告與DLL檔定義。\\ 
-匯出的函式我們必須使用_declspec(dllexport)或_declspec(dllimport)宣告,目的是為了讓裝載期間動態連結能夠找到DLL對應的函式。 
-<code cpp> 
-#ifdef MYDLLHELLOWORLD_EXPORTS 
-#define MYDLLHELLOWORLD_API __declspec(dllexport) 
-#else 
-#define MYDLLHELLOWORLD_API __declspec(dllimport) 
-#endif 
  
-// Declare export functions 
-MYDLLHELLOWORLD_API void showHelloWorldString( LPCTSTR s); 
-</​code>​ 
-如果是在執行期間動態連結,我們必須宣告def檔。VC中新增def的畫面如下:​\\ 
-{{.:​dll_add_def.png?​700|}}\\ 
-接著將要匯出的函式加入def中(其實已經可以不需要def了):​ 
-<code cpp> 
-LIBRARY "​DLLHelloWolrd"​ 
-EXPORTS 
- showHelloWorldString @1 
-</​code>​ 
-在編譯之後,會產生DLLHelloWolrd.dll與DLLHelloWolrd.lib,這兩個檔案在使用DLL時是所被需要的。 
-===== 裝載期間動態連結 ===== 
-使用裝載期間動態連結的重點如下:​ 
-  - 將**lib放置專案目錄**下。 
-  - 宣告**_declspec(dllexport) void showHelloWorldString( LPCTSTR s)**或**_declspec(dllimport) void showHelloWorldString( LPCTSTR s)**。一般會直接將DDL的header file include進來,目前看過third-party的library都會附上dll、lib與header file。 
-  - 加入#​pragma comment宣告我們所要載入的lib。如果這個lib不正確,在編譯時就會發生連結錯了。lib與dll相同也有32位元與64位元之區別。 
-<code cpp> 
-#include "​stdafx.h"​ 
-#include "​DLLHelloWorld.h"​ 
-#include <​atlbase.h> ​ 
-#include <​iostream>​ 
- 
-using namespace std; 
- 
-#pragma comment(lib,​ "​DLLHelloWolrd"​) 
- 
-int _tmain(int argc, _TCHAR* argv[]) 
-{ 
- LPCWSTR pw = W2T( L"​Hello world!"​);​ 
- showHelloWorldString(pw);​ 
- 
- system("​pause"​);​ 
- return 0; 
-} 
-</​code>​ 
-===== 執行期間動態連結 ===== 
-使用執行期間動態連結的重點如下:​ 
-  - 宣告欲呼叫之函式之function pointer,如**typedef void (*PFNEXPORTFUNC)(LPCTSTR)**。 
-  - LoadLibrary與FreeLibrary。使用DLL之前,必須使用LoadLibrary將它載入,如果不是傳路徑給檔而是使用檔名,它會有一定的[[java:​jna:​dll_search_path|搜尋路徑]]。如果Load有問題,可確認HMODULE是否為NULL,最後用完當然要釋放資源。 
-  - 透過GetProcAddress取得函式在DLL中的執行位置並呼叫。如**GetProcAddress( hModule, "​showHelloWorldString"​)**,**showHelloWorldString**為要呼叫的函式名稱。也可透過判斷取得結果是否為NULL去確認呼叫是否正確。 
-<code cpp> 
-#include "​stdafx.h"​ 
-#include <​atlbase.h> ​ 
- 
-using namespace std; 
- 
-LPCWSTR hwdll = W2T(L"​DLLHelloWolrd.dll"​);​ 
-typedef void (*PFNEXPORTFUNC)(LPCTSTR);​ 
- 
-int _tmain(int argc, _TCHAR* argv[]) 
-{ 
- HMODULE hModule = ::​LoadLibrary(hwdll);​ 
- if( hModule != NULL ){ 
- 
- PFNEXPORTFUNC fnHelloWorldDLL = (PFNEXPORTFUNC)::​GetProcAddress( hModule, "​showHelloWorldString"​);​ 
- if( fnHelloWorldDLL != NULL ){ 
- fnHelloWorldDLL( W2T( L"​Hello world!"​));​ 
- } else { 
- cout << "Init function failure!"​ << endl; 
- } 
- 
- FreeLibrary(hModule);​ 
- } else { 
- cout << "Load " << hwdll << " failure!"​ << endl; 
- } 
- system("​pause"​);​ 
- 
- return 0; 
-} 
-</​code>​ 
-===== 總結 ===== 
-到底用哪一個方法好呢?​ 裝載期間動態連接的優點是:​ 我們不需要去宣告有的沒的函式指標,也不用擔心介面宣告錯誤的問題。 但缺點是:​ 如果DDL檔案一但不見,這隻程式會永遠起不來。執行期間動態連結的缺點是:​ 一堆有的沒的函式指標宣告,稍微打錯就ㄘㄨㄚˋ賽了。 但優點是:​ 由於是在執行期間載入,如果讀取不到會獲得一個NULL,程式設計人員也可以根據這種情況做些例外處置。舉例來說,支援32與64位元的程式,會載入32與64位元的DLL。假如它所使用的名稱如example32.dll與example64.dll,我們可以透過先讀取example32.dll是否成功,再決定是否讀取example64.dll。另外一種使用情況也許是對於功能的alternative選擇。\\ 
- 
-另外大家看完這篇文章後,可能還有以下疑問:​ 
-  - dllexport與dllimport差在哪? ​ 
-  - showHelloWorldString @1的@1有何用途?​ 
- 
-第一個問題經過Silvius的指導,​ dllexport與dllimport的函義如下: ​ 
-  * 以上述的例子而言,DLL專案在前處理器會加入MYDLLHELLOWORLD_EXPORTS一同編譯。這將使得函式宣告為dllexport以做匯出之用。(前處理器的用途可參考[[cpp:​mixed:​preprocessor|這篇]]) 
-  * 而使用此DLL的Client,會使用dllimport宣告,將DLL函式做匯入之用。 
-{{:​cpp:​dll:​windows:​dll_preproc.png?​800|}} 
- 
- 
- 
-第二個問題,等之後我有時間且完全了解後,會替大家解答。 
- 
-===== Reference ===== 
-  * Windows程式設計 - 王艷平 編著 
-  * [[http://​msdn.microsoft.com/​zh-tw/​library/​1ez7dh12(v=vs.80).aspx|MSDN - DLL]] 
-  * [[https://​msdn.microsoft.com/​zh-tw/​library/​d91k01sh.aspx|使用 .DEF 檔從 DLL 匯出]] 
- 
-=====    ===== 
----- 
-\\ 
-~~DISQUS~~