什么是 DLL?
動(dòng)態(tài)鏈接庫(kù) (DLL) 是包含函數(shù)和數(shù)據(jù)的模塊的集合。程序文件(如 .exe 文件或 .dll 文件)在運(yùn)行時(shí)加載這些模塊(亦即所需的模塊映射到調(diào)用進(jìn)程的地址空間)。下面兩類函數(shù)定義了 DLL:
? |
導(dǎo)出函數(shù):這些函數(shù)由其他模塊調(diào)用。 |
? |
內(nèi)部函數(shù):這些函數(shù)僅從定義它們的 DLL 中調(diào)用。 |
DLL 還導(dǎo)出數(shù)據(jù)。不過(guò),這些數(shù)據(jù)由相應(yīng)的函數(shù)使用。
動(dòng)態(tài)鏈接和靜態(tài)鏈接
動(dòng)態(tài)鏈接包括系統(tǒng)在加載或運(yùn)行時(shí)查找導(dǎo)出的 DLL 函數(shù)的代碼所需的信息。
在靜態(tài)鏈接中,鏈接器將庫(kù)函數(shù)的代碼復(fù)制到調(diào)用 DLL 的每個(gè)模塊。
可以通過(guò)下列方式調(diào)用 DLL 中的函數(shù):
? |
加載時(shí)動(dòng)態(tài)鏈接:調(diào)用方模塊執(zhí)行顯式調(diào)用以導(dǎo)出 DLL 函數(shù)。為 DLL 創(chuàng)建導(dǎo)入庫(kù),然后將 DLL 鏈接到應(yīng)用程序。在加載應(yīng)用程序時(shí),導(dǎo)入庫(kù)提供加載 DLL 和查找導(dǎo)出的 DLL 函數(shù)所需的信息。 |
? |
運(yùn)行時(shí)動(dòng)態(tài)鏈接:在運(yùn)行時(shí)加載 DLL 時(shí),調(diào)用方模塊使用 LoadLibrary 函數(shù)或 LoadLibraryEx 函數(shù)。調(diào)用方模塊調(diào)用 GetProcAddress 函數(shù)以獲取導(dǎo)出的 DLL 函數(shù)的地址。 |
在鏈接時(shí),Windows 搜索預(yù)安裝的一組 DLL,例如性能庫(kù) (Kernel32.dll) 和安全庫(kù) (User32.dll)。然后,Windows 按以下順序搜索 DLL:
1. |
當(dāng)前進(jìn)程的可執(zhí)行程序所在的目錄。 |
2. |
當(dāng)前目錄。 |
3. |
Windows 系統(tǒng)目錄。(GetSystemDirectory 函數(shù)獲取 Windows 系統(tǒng)目錄的路徑。) |
4. |
Windows 目錄。(GetWindowsDirectory 函數(shù)獲取 Windows 目錄的路徑。) |
5. |
PATH 環(huán)境變量中列出的目錄。
注意:LIBPATH 環(huán)境變量不用于搜索。 |
aspx?scid=kb;zh-cn;815065#toc">返回頁(yè)首
DLL 和靜態(tài)庫(kù)
? |
DLL 可節(jié)省內(nèi)存并減少交換。 通過(guò)在內(nèi)存中共享 DLL 的單個(gè)副本,多個(gè)進(jìn)程可以同時(shí)使用一個(gè) DLL。相比之下,對(duì)于使用靜態(tài)鏈接庫(kù)構(gòu)建的每一個(gè)應(yīng)用程序,Windows 都要在內(nèi)存中為其加載庫(kù)代碼的一個(gè)副本。 |
? |
DLL 可節(jié)省磁盤空間。 多個(gè)應(yīng)用程序可以共享磁盤上的一個(gè) DLL 副本。相比之下,使用靜態(tài)鏈接庫(kù)構(gòu)建的每一個(gè)應(yīng)用程序都需要讓鏈接到程序文件映像的庫(kù)代碼作為一個(gè)單獨(dú)的專用副本。 |
? |
DLL 可節(jié)省時(shí)間。 更改 DLL 中的函數(shù)時(shí),只要函數(shù)的參數(shù)和返回值不變,就不必重新編譯或重新鏈接使用這些函數(shù)的應(yīng)用程序。但是,如果您使用靜態(tài)鏈接的對(duì)象代碼,則在更改函數(shù)后必須重新鏈接應(yīng)用程序。 |
? |
DLL 可以共享函數(shù)。 在 Win32 中,DLL 可以共享函數(shù)。默認(rèn)情況下,數(shù)據(jù)對(duì)于每個(gè)進(jìn)程來(lái)說(shuō)是獨(dú)立的。但是,靜態(tài)庫(kù)包含針對(duì)每一個(gè)進(jìn)程的單獨(dú)的數(shù)據(jù)副本和函數(shù)。 |
aspx?scid=kb;zh-cn;815065#toc">返回頁(yè)首
DLL 入口點(diǎn)
DLL 有一個(gè)特殊的入口點(diǎn)(
DllMain 函數(shù)),它在附加和分離進(jìn)程和線程時(shí)運(yùn)行。此行為允許根據(jù)需要?jiǎng)?chuàng)建和銷毀數(shù)據(jù)結(jié)構(gòu)。文件擴(kuò)展名為
.ocx、
.cpl 和
.drv 的文件類型也是 DLL,盡管文件擴(kuò)展名已改變。在 Windows 2.
x 和 Windows 3.
x 中,每個(gè) DLL 都只有一個(gè)數(shù)據(jù)段實(shí)例,而不管有多少應(yīng)用程序。在 Windows 32 中,可以將 DLL 標(biāo)記為共享以導(dǎo)致相同的行為。但是,每個(gè)進(jìn)程的默認(rèn)設(shè)置是擁有 DLL 數(shù)據(jù)的專用副本。
您可以通過(guò)創(chuàng)建 DLL 實(shí)現(xiàn)以下目的:
? |
將程序劃分為可按需加載的單獨(dú)模塊。 |
? |
存儲(chǔ)特定于語(yǔ)言或特定于區(qū)域的資源。 |
? |
使您自己的應(yīng)用程序能夠使用核心代碼庫(kù)。 |
? |
生成進(jìn)程內(nèi) COM 對(duì)象或 ActiveX 控件 (OCX)。 |
? |
將 OLE 對(duì)象用作進(jìn)程內(nèi) DLL。這一用法可改進(jìn) OLE 鏈接的性能。 |
? |
使用控制面板擴(kuò)展或使用某些類型的驅(qū)動(dòng)程序。 |
要生成 DLL,請(qǐng)使用
DllMain 函數(shù)(而不是程序文件)替換
WinMain 函數(shù)。
要在 Win16 中導(dǎo)出函數(shù),請(qǐng)將
FAR EXPORT 添加到所有導(dǎo)出的 DLL 函數(shù)(在 Win32 中不要求這樣做)。許多 32 位編譯器提供了函數(shù)聲明符,例如
__declspec(dllexport) 和
__declspec(dllimport)。這些函數(shù)聲明符出現(xiàn)在函數(shù)聲明之前以代替調(diào)用。不過(guò),定義必須僅指定
dllexport 屬性。
aspx?scid=kb;zh-cn;815065#toc">返回頁(yè)首
DLL 問(wèn)題和故障排除工具
初始化問(wèn)題
在 DLL 初始化過(guò)程中,您可能會(huì)遇到下列一個(gè)或多個(gè)問(wèn)題:
? |
如果計(jì)劃服務(wù)的服務(wù)帳戶密碼與域用戶管理器帳戶的密碼不同,則您在計(jì)劃服務(wù)時(shí)可能會(huì)收到以下初始化錯(cuò)誤信息:
Initialization of dynamic link library c:\winnt\system32\KERNEL32.dll failed.Process is terminating abnormally
有關(guān)其他信息,請(qǐng)單擊下面的文章編號(hào),以查看 Microsoft 知識(shí)庫(kù)中相應(yīng)的文章:
250265 使用 Cmd.exe 運(yùn)行 AT 計(jì)劃命令時(shí)出現(xiàn) Kernel32.dll 動(dòng)態(tài)鏈接庫(kù)初始化錯(cuò)誤
|
? |
如果不斷加載和卸載 Crypt32.dll,則在加載 Crypt32.dll 時(shí)將分配傳輸層安全性 (TLS),但在卸載 Crypt32.dll 時(shí)卻不釋放它。此行為可能導(dǎo)致一般性保護(hù)錯(cuò)誤 (GPF) 錯(cuò)誤,并且您可能會(huì)收到以下錯(cuò)誤信息:
Initialization of the dynamic link library C:\WINNT40\System32\CRYPT32.dll failed.The process is terminating abnormally.
有關(guān)其他信息,請(qǐng)單擊下面的文章編號(hào),以查看 Microsoft 知識(shí)庫(kù)中相應(yīng)的文章:
212825 SMS:一般性保護(hù)錯(cuò)誤:Initialization of CRYPT32.DLL Failed(CRYPT32.DLL 初始化失?。?
|
? |
如果您將計(jì)算機(jī)升級(jí)到 McAfee VirusScan 6.0,則可能會(huì)在啟動(dòng) Outlook 2000 后的三分鐘內(nèi)收到以下錯(cuò)誤信息:
Outlook.exe. DLL initialization failed.Initialization of c:\winnt\system32\compstui.dll. Process is terminating abnormally.
有關(guān)其他信息,請(qǐng)單擊下面的文章編號(hào),以查看 Microsoft 知識(shí)庫(kù)中相應(yīng)的文章:
310413 OL2000:升級(jí)到 McAfee VirusScan 6.0 后 Outlook 2000 發(fā)生 DLL 初始化錯(cuò)誤
|
? |
如果您將 Windows NT Mail 或 MSMail32.exe 設(shè)置為按計(jì)劃啟動(dòng),計(jì)劃服務(wù)可能被記錄為系統(tǒng)以外的其他內(nèi)容,而且您可能會(huì)收到以下錯(cuò)誤信息:
Initialization of the Dynamic Link Library OLECLI32.dll failed Abnormally
有關(guān)其他信息,請(qǐng)單擊下面的文章編號(hào),以查看 Microsoft 知識(shí)庫(kù)中相應(yīng)的文章:
133476 Windows NT 郵件錯(cuò)誤信息:Initialization of the Dynamic Link...(動(dòng)態(tài)鏈接的初始化...)
|
? |
如果遠(yuǎn)程訪問(wèn)服務(wù) (RAS) 文件或調(diào)制解調(diào)器文件丟失或損壞,并且您試圖打開控制面板,則可能會(huì)收到以下錯(cuò)誤信息:
Explorer.exe - DLL Initialization Failed Initialization of the dynamic link library E:\WINNT\System32\RASSCRPT.dll failed.The process is terminating abnormally.
有關(guān)其他信息,請(qǐng)單擊下面的文章編號(hào),以查看 Microsoft 知識(shí)庫(kù)中相應(yīng)的文章:
184443 錯(cuò)誤信息:Explorer.exe - DLL Initialization Failed...(Explorer.exe — DLL 初始化失敗...)
|
? |
如果系統(tǒng)內(nèi)存不足,無(wú)法為正在啟動(dòng)的服務(wù)創(chuàng)建新的桌面堆棧,您可能會(huì)收到以下錯(cuò)誤信息:
ServiceName - DLL initialization failure Initialization of the dynamic link library c:\windows\system32\user32.dll failed.The process is terminating abnormally.
有關(guān)其他信息,請(qǐng)單擊下面的文章編號(hào),以查看 Microsoft 知識(shí)庫(kù)中相應(yīng)的文章:
142676 解決 User32.dll 初始化失敗錯(cuò)誤
|
aspx?scid=kb;zh-cn;815065#toc">返回頁(yè)首
依賴性問(wèn)題
如果您沒有等到所有系統(tǒng)服務(wù)開始運(yùn)行就啟動(dòng)您的服務(wù),可能會(huì)遇到依賴性問(wèn)題。例如,服務(wù)依賴于其他服務(wù)或驅(qū)動(dòng)程序。這些服務(wù)或驅(qū)動(dòng)程序又轉(zhuǎn)而依賴于另外一些服務(wù)或驅(qū)動(dòng)程序。更確切地說(shuō),RasApi32.dll 隱式依賴于 RAS 服務(wù)。使用 Rasapi32.dll 上的
LoadLibrary 的一個(gè) Windows NT 服務(wù)使該服務(wù)依賴于 RAS 服務(wù)。
在您對(duì)項(xiàng)目進(jìn)行更改時(shí),定期通過(guò)“項(xiàng)目”菜單掃描所有依賴項(xiàng)以確保依賴性列表的準(zhǔn)確性。如果您在執(zhí)行依賴性掃描之前未保存對(duì)項(xiàng)目中文件所做的更改,新的依賴項(xiàng)不會(huì)顯示在列表中。
aspx?scid=kb;zh-cn;815065#toc">返回頁(yè)首
性能問(wèn)題
如果加載應(yīng)用程序的同時(shí)加載隱式鏈接到該應(yīng)用程序的 DLL,則會(huì)出現(xiàn)性能問(wèn)題。例如,當(dāng)運(yùn)行 Windows 2000 的計(jì)算機(jī)在內(nèi)存中加載 Winmm.dll 文件時(shí),可能會(huì)出現(xiàn)延遲。此延遲可能會(huì)在不同的時(shí)間發(fā)生,具體取決于 Winmm.dll 文件是如何加載的:
? |
如果程序使用導(dǎo)入庫(kù)來(lái)加載 Winmm.dll 文件,則 Winmm.dll 在程序啟動(dòng)時(shí)加載。在這種情況下,可能會(huì)在啟動(dòng)程序時(shí)出現(xiàn)延遲。因此,如果使用批處理文件多次啟動(dòng)此程序,性能會(huì)顯著下降。 |
? |
如果程序使用 LoadLibrary 加載 Winmm.dll 文件,則 Winmm.dll 僅在程序需要時(shí)才加載。例如,如果在您打開菜單時(shí) Explorer.exe 播放聲音,則在第一次播放聲音時(shí)加載 Winmm.dll 文件。在這種情況下,可能會(huì)在程序加載 Winmm.dll 文件時(shí)出現(xiàn)延遲。 |
要提高性能,請(qǐng)?jiān)诩虞d時(shí)使用優(yōu)化技巧。另外,可將 DLL 分為兩個(gè) DLL:
? |
將調(diào)用應(yīng)用程序在加載后立刻需要的所有函數(shù)放入一個(gè) DLL,然后將該調(diào)用應(yīng)用程序隱式鏈接到此 DLL。 |
? |
將調(diào)用應(yīng)用程序不立即需要的函數(shù)放入另一個(gè) DLL,然后將該應(yīng)用程序顯式鏈接到此 DLL。 |
aspx?scid=kb;zh-cn;815065#toc">返回頁(yè)首
故障排除工具
支持使用下列工具進(jìn)行故障排除:
? |
Dependency Walker Dependency Walker 不僅僅是一個(gè)故障排除實(shí)用工具。Dependency Walker 提供了許多關(guān)于某一特定應(yīng)用程序的模塊布局的寶貴信息。此實(shí)用工具還提供關(guān)于每個(gè)模塊的詳細(xì)信息。有關(guān)更多信息,請(qǐng)參閱本文的“aspx?scid=kb;zh-cn;815065#6">DLL 依賴性”部分。 |
? |
DLL Universal Problem Solver 工具出現(xiàn) DLL 文件版本沖突問(wèn)題(也稱為“DLL Hell”問(wèn)題)時(shí),可以使用 DLL Universal Problem Solver (DUPS) 工具查找這些問(wèn)題并進(jìn)行修復(fù)。DUPS 程序包是一個(gè)實(shí)用工具集,使用它可以跟蹤和比較多臺(tái)基于 Windows 的計(jì)算機(jī)上的 DLL 版本。有關(guān)更多信息,請(qǐng)?jiān)L問(wèn)下面的 Microsoft Web 站點(diǎn):
asp?url=/library/en-us/dnsetup/html/dlldanger1. asp">http://msdn.microsoft.com/library/default. asp?url=/library/en-us/dnsetup/html/dlldanger1. asp
|
? |
RegSvr32 使用 Regsvr32 工具 (Regsvr32.exe) 可注冊(cè)或注銷 OLE 控件,例如可自行注冊(cè)的 DLL 控制文件或 ActiveX 控件 (OCX) 文件。為排查 Windows、Microsoft Internet Explorer 或其他程序中的故障,您可能必須注冊(cè)或注銷這些文件。有關(guān)其他信息,請(qǐng)單擊下面的文章編號(hào),以查看 Microsoft 知識(shí)庫(kù)中相應(yīng)的文章:
249873 Regsvr32 用法和錯(cuò)誤消息的說(shuō)明
|
? |
OLE/COM 對(duì)象查看器使用 OLE/COM 對(duì)象查看器,可通過(guò)讀取類型庫(kù)來(lái)查看控件(DLL 或 OCX 文件)的接口。有關(guān)更多信息,請(qǐng)?jiān)L問(wèn)下面的 Microsoft Web 站點(diǎn):
asp?url=/library/en-us/vccore/html/vcrefusingolecomobjectviewertoviewcontrolsinterfaces. asp">http://msdn.microsoft.com/library/default. asp?url=/library/en-us/vccore/html/vcrefUsingOLECOMObjectViewerToViewControlsInterfaces. asp
|
? |
.Net Framework 工具 Microsoft .Net Framework SDK 工具旨在使您創(chuàng)建、部署和管理使用 .Net Framework 的應(yīng)用程序和組件的過(guò)程更輕松。.Net Framework 提供四組工具:配置和部署工具、調(diào)試工具、安全工具和常規(guī)工具。有關(guān)更多信息,請(qǐng)?jiān)L問(wèn)下面的 Microsoft Web 站點(diǎn):
asp?url=/library/en-us/cptools/html/cpconnetframeworktools. asp">http://msdn.microsoft.com/library/default. asp?url=/library/en-us/cptools/html/cpconnetframeworktools. asp
|
aspx?scid=kb;zh-cn;815065#toc">返回頁(yè)首
DLL 依賴性
通過(guò)使用 Dependency Walker,您可以查看應(yīng)用程序?qū)?DLL 的依賴情況。例如,Depends.exe 包含在
Visual C++ .Net 中。Depends.exe 安裝在 \Microsoft Visual Studio
.Net 2003\Common7\Tools\Bin 文件夾中。僅當(dāng)您在
Visual C++ .Net 自定義安裝的
Visual C++ 工具類別中選擇了 Win32 Platform SDK 工具時(shí),才可以安裝 Depends.exe 可執(zhí)行文件。
通過(guò)使用 Depends.exe 或 DUMPBIN 實(shí)用工具并使用
/DEPENDENTS 選項(xiàng),可以查看靜態(tài)鏈接到您的應(yīng)用程序的 DLL 列表和延遲加載的 DLL 的列表。要查看動(dòng)態(tài)加載了哪些 DLL(如 ActiveX 控件),請(qǐng)使用 Depends.exe 的信息摘要功能。有關(guān)更多信息,請(qǐng)?jiān)L問(wèn)下面的 Microsoft Web 站點(diǎn):
asp?url=/library/en-us/vccore/html/vccondeterminingwhichdllstoredistribute.
asp">http://msdn.microsoft.com/library/default.
asp?url=/library/en-us/vccore/html/vccondeterminingwhichdllstoredistribute.
asp
aspx?scid=kb;zh-cn;815065#toc">返回頁(yè)首
Win32 與 .Net 程序集的比較
在
.Net Framework 中,程序集是一個(gè)邏輯 EXE 或 DLL。下面是程序集與 Win32 DLL 相比較二者之間的不同之處:
? |
這些 EXE 或 DLL 文件中的代碼是由語(yǔ)言編譯器生成的。此代碼不是 x86 計(jì)算機(jī)代碼或?qū)S糜谌魏翁囟?CPU 操作系統(tǒng)的計(jì)算機(jī)代碼。該代碼是用 Microsoft 中間語(yǔ)言 (MSIL) 生成的。MSIL 可以用匯編語(yǔ)言編寫。Microsoft 提供了 MSIL 匯編程序 (ILAsm.exe) 和 MSIL 反匯編程序 (ILDasm.exe)。 |
? |
此 DLL 或 EXE 文件包含編譯器產(chǎn)生的元數(shù)據(jù)。公共語(yǔ)言運(yùn)行庫(kù)使用此元數(shù)據(jù)查找和加載文件中的類類型,確定對(duì)象實(shí)例在內(nèi)存中的布局,解析方法調(diào)用和字段引用,將 MSIL 轉(zhuǎn)換為本機(jī)代碼,執(zhí)行安全設(shè)置。 |
? |
您生成的組件不僅僅是 EXE 文件或 DLL 文件。它們是重新使用和部署的基本單位,是 .Net 中的一個(gè)程序集。您可以生成單文件程序集或多文件程序集。在單文件程序集中,程序集的文件擴(kuò)展名是 .exe 或 .dll。
多文件程序集是這樣一種思想:通過(guò)將一個(gè)可重用組件的邏輯概念和物理概念分離開來(lái),將代碼劃分到多個(gè)文件中以滿足您的需求。不過(guò),您仍然可以保留集合作為版本控制和部署的一個(gè)單位。例如,如果您使用多文件程序集,則可以使用增量和按需下載。 |
? |
通過(guò)使用程序集,開發(fā)人員和管理員能夠表示程序的各組件之間嚴(yán)格的版本依賴性。由于各組件是自描述的,所以您可以創(chuàng)建無(wú)影響安裝。
在安裝新應(yīng)用程序的組件時(shí),它們可能覆蓋早期的應(yīng)用程序的組件。如果發(fā)生此覆蓋,早期的應(yīng)用程序可能會(huì)運(yùn)行不正常或停止運(yùn)行。.Net Framework 體系結(jié)構(gòu)讓應(yīng)用程序的各組件保持獨(dú)立,這樣應(yīng)用程序始終能夠加載正確的組件。因此,在安裝后能按預(yù)期運(yùn)行的應(yīng)用程序?qū)⒗^續(xù)運(yùn)行。(此功能解決了“DLL Hell”問(wèn)題。) |
? |
程序集是 .Net 安全系統(tǒng)的一部分。程序集是申請(qǐng)和授予權(quán)限的單位。為了正確地在 .Net Framework 中強(qiáng)制實(shí)施版本控制、部署和安全功能,程序集起到了解析范圍的作用,用于解析對(duì)類型的引用。 |
清單 中描述了程序集的各個(gè)組件。清單是一個(gè)數(shù)據(jù)塊,它列出程序集的文件,并控制著向程序集之外公開哪些類型和資源。例如,某些類型可能保留為僅在程序集內(nèi)使用。其他類型可能能夠?qū)С龅匠绦蚣氖褂谜摺?a href="http://www./net/" target="_blank">.Net Framework 按照在程序集清單中表達(dá)的規(guī)則將類型和資源解析為程序集中的實(shí)現(xiàn)文件和綁定到從屬程序集。
雖然
.Net Framework 很大而且范圍很廣,但仍然存在可使用 Win32 API 執(zhí)行,而使用
.Net Framework 則無(wú)法執(zhí)行的一些功能。例如,您可以使用 Win32 API
MessageBeep 和
Beep 在應(yīng)用程序中包含生成噪音的功能。
aspx?scid=kb;zh-cn;815065#toc">返回頁(yè)首
.Net 連接的客戶端應(yīng)用程序使用 Win32 DLL 導(dǎo)出 (PInvoke)
要通過(guò)
.Net 連接的應(yīng)用程序使用 Win32 DLL 例程,請(qǐng)使用“平臺(tái)調(diào)用服務(wù)”機(jī)制(也叫平臺(tái)調(diào)用或
PInvoke)。此服務(wù)通過(guò)在
System.Runtime.InteropServices 命名空間中定義的一個(gè)自定義屬性 (
DllImportAttribute) 運(yùn)行。該屬性允許實(shí)現(xiàn) DLL 的名稱(和其他必需信息)與一個(gè)過(guò)程或函數(shù)聲明關(guān)聯(lián)。通過(guò)此關(guān)聯(lián),您可以調(diào)用 DLL 例程。組件對(duì)象模型 (COM) Interop 支持使用 Interop 封送拆收器自動(dòng)在托管
.Net 環(huán)境和非托管 Win32 環(huán)境之間封送拆收參數(shù)和返回值。
要使用導(dǎo)出的 DLL 函數(shù),請(qǐng)按照下列步驟操作:
1. |
標(biāo)識(shí)函數(shù)名稱和導(dǎo)出該函數(shù)的 DLL 的名稱。例如,通過(guò)指定 User32.dll 中的 MessageBox 函數(shù),您可以標(biāo)識(shí)函數(shù) (MessageBox) 和函數(shù)的位置(User32.dll、User32 或 user32)。 |
2. |
創(chuàng)建一個(gè)類以包裝 DLL 函數(shù)。在類中為要調(diào)用的每個(gè) DLL 函數(shù)定義一個(gè)靜態(tài)方法。例如,您可以調(diào)用 User32.dll 中的 MessageBox 函數(shù),如下例所示:
using System.Runtime.InteropServices;
[DllImport("user32.dll")]
public static extern int MessageBox(int hWnd, String text,
String caption, uint type);
|
3. |
使用 DllImportAttribute 屬性標(biāo)識(shí) DLL 和函數(shù)。使用外部“C”標(biāo)記包裝方法或函數(shù)。 |
4. |
通過(guò)傳遞在托管代碼中定義的類的成員,調(diào)用托管類中的方法。 例如,將 MySystemTime 類的成員(這些成員是按順序定義的)傳遞到 User32.dll 文件中的 GetSystemTime 方法,如下例中所示:
void GetSystemTime(SYSTEMTIME* SystemTime);
class Win32API {
[DllImport("Kernel32.dll")]
public static extern void GetSystemTime(MySystemTime st);
}
|
有關(guān)更多信息,請(qǐng)?jiān)L問(wèn)下面的 Microsoft Web 站點(diǎn):
asp?url=/library/en-us/cpguide/html/cpconconsumingunmanageddllfunctions.
asp">http://msdn.microsoft.com/library/default.
asp?url=/library/en-us/cpguide/html/cpconconsumingunmanageddllfunctions.
asp
aspx?scid=kb;zh-cn;815065#toc">返回頁(yè)首
Win32 客戶端應(yīng)用程序使用 .Net 程序集導(dǎo)出(反向 PInvoke)
要在 Win32 應(yīng)用程序中使用
.Net 程序集,請(qǐng)使用“反向平臺(tái)調(diào)用服務(wù)”機(jī)制。 此服務(wù)使用的機(jī)制與
PInvoke 使用的機(jī)制反向。
通過(guò)使用此機(jī)制,
.Net 中的公共語(yǔ)言運(yùn)行庫(kù)可以向外部 (Win32) 世界公開任何
.Net 方法。此機(jī)制執(zhí)行下列操作:
1. |
將 .Net 程序集反匯編為對(duì)應(yīng)的中間語(yǔ)言 (IL) 源代碼和元數(shù)據(jù)。 |
2. |
重新匯編對(duì)等的 .Net 程序集中的 IL 代碼、元數(shù)據(jù)和資源。 |
詳細(xì)信息要對(duì)
.Net 程序集進(jìn)行反匯編,您可以使用 Framework SDK 中包含的
.Net Framework IL 反匯編程序 (Ildasm.exe)。 例如,MyAssembly.dll 包含下列獨(dú)立例程,即 HelloWorld 和 HelloMyWorld:
public static void HelloWorld()
{
Console.WriteLine("Hello World!");
}
public static void HelloMyWorld()
{
Console.WriteLine("Hello My World!");
}
要對(duì)該程序集進(jìn)行反匯編,請(qǐng)使用以下命令行:
ildasm MyAssembly.dll /linenum /out:MyAssembly.il
此命令將生成命名的 IL 文件。它還在 MyAssembly.res 文件中存儲(chǔ)任何非托管資源,在具有程序集元數(shù)據(jù)中指定的名稱的文件中存儲(chǔ)任何托管資源。如果 PDB 文件中包含調(diào)試信息,則
/linenum 選項(xiàng)使 IL 文件包括對(duì)原始源代碼行的引用。
aspx?scid=kb;zh-cn;815065#toc">返回頁(yè)首
從程序集公開方法
要從程序集公開方法,必須對(duì)程序集清單進(jìn)行某些更改。該清單位于 IL 文件頂部的類聲明之前:
.module MyAssembly.dll
// MVID: {140B1958-FC28-4802-80E3-74C0F2015CDC}
.imagebase 0x11000000
.subsystem 0x00000003
.file alignment 512
.corflags 0x00000001
要進(jìn)行更改,請(qǐng)執(zhí)行下列操作:
1. |
要定義一個(gè) v-table 修正并使之包含的插槽與要導(dǎo)出的方法一樣多(上例中有兩個(gè)方法),請(qǐng)按如下所示更改清單:
module MyAssembly.dll
.module MyAssembly.dll
// MVID: {140B1958-FC28-4802-80E3-74C0F2015CDC}
.imagebase 0x11000000
.subsystem 0x00000003
.file alignment 512
.corflags 0x00000001
.data VT_01 = int32[2]
.vtfixup [2] int32 fromunmanaged at VT_01
|
2. |
.corflags 指令設(shè)置運(yùn)行庫(kù)頭文件標(biāo)志。默認(rèn)情況下,.corflags 指令指定值 1。 此值等于 COMIMAGE_FLAGS_ILONLY 標(biāo)志(在 .Net Framework SDK 中的 CorHdr.h 包含文件中定義)。 設(shè)置此標(biāo)志后,Windows XP 加載程序會(huì)忽略該程序集文件的主要部分,而且不進(jìn)行修正。 在您嘗試使用程序集導(dǎo)出時(shí),這會(huì)導(dǎo)致致命錯(cuò)誤。 所以,如果您希望程序集在 Windows XP 上運(yùn)行,必須指定 COMIMAGE_FLAGS_32BITREQUIRED 標(biāo)志(此值為 2):
module MyAssembly.dll
.module MyAssembly.dll
// MVID: {140B1958-FC28-4802-80E3-74C0F2015CDC}
.imagebase 0x11000000
.subsystem 0x00000003
.file alignment 512
.corflags 0x00000002.data VT_01 = int32[2]
.vtfixup [2] int32 fromunmanaged at VT_01
|
這些方法的 IL 表示當(dāng)前顯示如下:
.method public hidebysig static void
HelloWorld() cil managed
{
// Code size 11 (0xb)
.maxstack 1
.line 18:4
IL_0000: ldstr "Hello World!"
IL_0005: call void [mscorlib]System.Console::WriteLine(string)
.line 19:3
IL_000a: ret
} // end of method Class1::HelloWorld
.method public hidebysig static void
HelloMyWorld() cil managed
{
// Code size 11 (0xb)
.maxstack 1
.line 23:4
IL_0000: ldstr "Hello My World!"
IL_0005: call void [mscorlib]System.Console::WriteLine(string)
.line 24:3
IL_000a: ret
} // end of method Class1::HelloMyWorld
要讓這些方法作為非托管導(dǎo)出,請(qǐng)對(duì)它們進(jìn)行如下更改:
.method public hidebysig static void
HelloWorld() cil managed
{
// Code size 11 (0xb)
.maxstack 1
.line 18:4
.vtentry 1:1
.export [1] as HelloWorld
IL_0000: ldstr "Hello World!"
IL_0005: call void [mscorlib]System.Console::WriteLine(string)
.line 19:3
IL_000a: ret
} // end of method Class1::HelloWorld
.method public hidebysig static void
HelloMyWorld() cil managed
{
// Code size 11 (0xb)
.maxstack 1
.line 23:4
.vtentry 1:2
.export [2] as HelloMyWorld
IL_0000: ldstr "Hello My World!"
IL_0005: call void [mscorlib]System.Console::WriteLine(string)
.line 24:3
IL_000a: ret
} // end of method Class1::HelloMyWorld
每個(gè)方法需要一個(gè) .vtentry 指令以將該方法鏈接到 v-table 修正(粗體顯示指定的插槽號(hào)),還需要一個(gè) .export 指令以指定導(dǎo)出的名稱。
要將代碼重新匯編為 .Net 程序集,請(qǐng)使用 .Net Framework 中包含的 IL 匯編程序 (Ilasm.exe)。使用以下命令行:
C:\Temp\MyAssembly\bin\Debug>ilasm /dll MyAssembly.il /out:MyAssembly_new.dll /r
es:MyAssembly.res
Microsoft (R) .Net Framework IL Assembler. Version 1.0.3705.0
Copyright (C) Microsoft Corporation 1998-2001. All rights reserved.
Assembling ‘MyAssembly.il‘ , no listing file, to DLL --> ‘MyAssembly_new.dll‘
Source file is ANSI
Assembled method Class1::Main
Assembled method Class1::HelloWorld
Assembled method Class1::HelloMyWorld
Assembled method Class1::.ctor
Creating PE file
Emitting members:
Global
Class 1 Methods: 4;
Resolving member refs: 1 -> 1 defs, 0 refs
Writing PE file
Operation completed successfully
使用反向 PInvoke 時(shí)可能遇到的主要困難是維護(hù)問(wèn)題。如果要通過(guò)創(chuàng)造性往返修改編譯器生成的程序集,請(qǐng)重新手動(dòng)更新程序集以導(dǎo)出例程。
aspx?scid=kb;zh-cn;815065#toc">返回頁(yè)首