,因?yàn)槠浒吮姸嗟腁PI函數(shù)聲明頭文件。為了探究這個(gè)小小的MessageBox是怎么彈出來(lái)的,我們右擊MessageBox,選擇“GotodefinitionofMessageBox(轉(zhuǎn)到定義)”將打開(kāi)

日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

由MessageBox透視Win32 API的調(diào)用

系統(tǒng) 2222 0

下面我們來(lái)看看 Windows 平臺(tái)下應(yīng)用程序是怎么調(diào)用 Windows 提供的底層 API 服務(wù)運(yùn)行的。

我們編寫(xiě) Win32SDK 程序時(shí),需要彈出對(duì)話框以作出友好的選擇, MessageBox 這個(gè) API 函數(shù)就可以實(shí)現(xiàn)該功能。在開(kāi)頭要添加 <windows.h> , 因?yàn)槠浒吮姸嗟? API 函數(shù)聲明頭文件。為了探究這個(gè)小小的 MessageBox 是怎么彈出來(lái)的,我們右擊 MessageBox ,選擇“ Go to definition of MessageBox( 轉(zhuǎn)到定義 ) ”將打開(kāi) <winuser.h> MessageBox 定義處。 MessageBox(A/W) 的函數(shù)原型聲明如下:

// WINUSER.H

WINUSERAPI

int

WINAPI

MessageBoxA (

HWND hWnd ,

LPCSTR lpText ,

LPCSTR lpCaption ,

UINT uType );

WINUSERAPI

int

WINAPI

MessageBoxW (

HWND hWnd ,

LPCWSTR lpText ,

LPCWSTR lpCaption ,

UINT uType );

#ifdef UNICODE

#define MessageBox MessageBoxW

#else

#define MessageBox MessageBoxA

#endif // !UNICODE

我們?cè)谑褂? Windows 窗口操作系統(tǒng)時(shí),經(jīng)常會(huì)蹦出大大小小的 窗口, MessageBox 只是 Windows 作為提示的對(duì)話框窗口單元。那么, MessageBoxW 這個(gè) API 函數(shù)到底在哪里實(shí)現(xiàn)的呢?應(yīng)用程序是如何調(diào)用系統(tǒng)接口函數(shù)的呢?

動(dòng)態(tài)鏈接庫(kù)( .dll

初窺 DLL

實(shí)際上 Windows API 函數(shù)是定義在一些 DLL 中的, DLL 實(shí)現(xiàn)了代碼封裝,從這個(gè)角度來(lái)看 DLL 才是真正意義上的 API 函數(shù)包,它是非開(kāi)源 Windows 操作系統(tǒng)提供給我們的底層接口。 DLL 的編制與具體的編程語(yǔ)言及編譯器無(wú)關(guān)。

動(dòng)態(tài)鏈接庫(kù) dll 文件( Linux 中與之對(duì)應(yīng)的是的 .so 存放在 C:/WINDOWS/system 目錄和 C:/WINDOWS/system32 目錄下,它在被應(yīng)用程序調(diào)用時(shí)才同程序相鏈接。

其中 Windows 系統(tǒng)最重要的 DLL User32.dll Gdi32.dll Kernel32.dll 這三個(gè)庫(kù)文件。這三個(gè)庫(kù)文件中的 API 函數(shù)大都在頭文件 <windows.h> 中進(jìn)行了聲明。從功能上進(jìn)行分類, User32.dll Windows XP USER API Client DLL )定義了窗口管理函數(shù),包括窗口的創(chuàng)建、顯示、設(shè)置和移動(dòng)等; Gdi32.dll GDI Client DLL )定義了圖形設(shè)備函數(shù)( GDI ),實(shí)現(xiàn)與設(shè)備無(wú)關(guān)的繪圖功能; Kernel32.dll Windows NT BASE API Client DLL )定義了系統(tǒng)服務(wù)函數(shù),包括諸如內(nèi)存調(diào)度、進(jìn)程管理等與操作系統(tǒng)有關(guān)的底層功能。我們可以通過(guò)三種方式來(lái)查看 DLL 文件中的導(dǎo)出函數(shù)信息:( 1 )使用 Windows 系統(tǒng)的 dumpbin 命令(在命令行中: C:/WINDOWS/system32> dumpbin ntdll.dll /exports );( 2 )使用 VC 自帶的 Depends 工具( Microsoft Visual Studio 6.0 Tools à Depends Visual Studio 2005 命令行提示 à depends );( 3 Dll 函數(shù)查看器 ViewDll ExeScope )。以下使用 VC 自帶的 Depends 工具查看 user32.dll MessageBox 函數(shù)系列。

由MessageBox透視Win32 API的調(diào)用

DLL API

正如 Java 的跨平臺(tái)( Write Once, Run Everywhere )需要 JVM 的支持一樣, C/C++ 成為跨平臺(tái)的編程語(yǔ)言,依賴各個(gè)平臺(tái)(包括操作系統(tǒng)和編譯器)對(duì) C/C++ 標(biāo)準(zhǔn)函數(shù)庫(kù)的具體平臺(tái)實(shí)現(xiàn)。

VS 編譯器自帶的標(biāo)準(zhǔn) C 函數(shù)庫(kù) <stdio.h> , <stdlib.h> , <string.h> <math.h> 中聲明的函數(shù)可以到 C:/Program Files/Microsoft Visual Studio/VC98/CRT/SRC( C:/Program Files/Microsoft Visual Studio 8/VC/crt/src) 中查看相關(guān)實(shí)現(xiàn)源代碼。 strcat.c 文件提供了 strcat strcpy 函數(shù)的源碼 , Windows 系統(tǒng)中, C: / WINDOWS/system32/ ntdll.dll 提供了 strcat strcpy 這兩個(gè) CRT API 的底層實(shí)現(xiàn)。用戶對(duì) C 函數(shù)的調(diào)用最終通過(guò)調(diào)用底層 API 來(lái)完成真正的功能。例如 C 標(biāo)準(zhǔn)庫(kù)函數(shù) create 用于創(chuàng)建文件,但它是靠調(diào)用 CreateFile kernel32.dll 函數(shù)來(lái)完成創(chuàng)建文件功能的; beginthread( process.h,thread.c ) 需要調(diào)用 CreateThread kernel32.dll 函數(shù)來(lái)完成線程的創(chuàng)建。

DLL 的移植升級(jí)

Windows 將遵循下面的搜索順序來(lái)定位 DLL : 包含 EXE 文件的目錄 > 進(jìn)程的當(dāng)前工作目錄 >Windows 系統(tǒng)目錄 >Windows 目錄 > 列在 Path 環(huán)境變量中的一系列目錄。

如果你在本機(jī)編寫(xiě)一個(gè) Windows 應(yīng)用程序,移植到其他機(jī)子上 ( 當(dāng)然也是 Windows 操作系統(tǒng) ) ,有可能因?yàn)槿鄙傧嚓P(guān) DLL 文件而無(wú)法執(zhí)行。因?yàn)? DLL 是動(dòng)態(tài)鏈接,就是隨用隨加載,這就是為什么我們玩 3D 游戲時(shí)經(jīng)常彈出缺少 d3dx9***.dll 的錯(cuò)誤提示。如果啟動(dòng)的程序調(diào)用了一個(gè)過(guò)期的 DLL 文件或不匹配的 DLL 文件,則會(huì)出現(xiàn)“未定義的動(dòng)態(tài)鏈接調(diào)用”消息。

動(dòng)態(tài)鏈接庫(kù)除了實(shí)現(xiàn)代碼的共享外,其模塊封裝特性使得應(yīng)用程序在調(diào)用一個(gè) DLL 的不同版本時(shí),只要導(dǎo)出的函數(shù)名相同就不必進(jìn)行重新編譯鏈接。這樣,軟件產(chǎn)品在更新或升級(jí)時(shí),客戶程序不必進(jìn)行改動(dòng)。在開(kāi)發(fā)軟件產(chǎn)品時(shí),對(duì)于通用功能的函數(shù),一般以 DLL 的形式來(lái)實(shí)現(xiàn)。 Windows 設(shè)備驅(qū)動(dòng)程序就是體現(xiàn)上述特點(diǎn)的動(dòng)態(tài)鏈接庫(kù)。

DLL 的調(diào)用

動(dòng)態(tài)鏈接庫(kù)的調(diào)用方式又分為隱式調(diào)用(也稱靜態(tài)調(diào)用,需要 .lib 文件)和顯式調(diào)用(也稱動(dòng)態(tài)調(diào)用, LoadLibrary à GetProcAddress à FreeLibrary )。

那么,在我們編寫(xiě)的程序中,如何調(diào)用 DLL 中的 API 呢?既然用戶對(duì) C 函數(shù)的調(diào)用最終是通過(guò)調(diào)用底層 API 來(lái)完成真正的功能,那么,我們?cè)诰帉?xiě)第一個(gè) Hello World 程序時(shí)就已經(jīng)不知不覺(jué)地調(diào)用了 DLL 。實(shí)際上 <stdio.h> 中定義的 printf 函數(shù)由 msvcrt.dll 函數(shù)導(dǎo)出,而 *printf 系列函數(shù)在 ntdll.dll 中有具體底層實(shí)現(xiàn)。

DLL 文件包括了具體實(shí)現(xiàn)的代碼編譯后的結(jié)果(二進(jìn)制的機(jī)器碼),而頭文件中的代碼主要是 DLL 庫(kù)文件 導(dǎo)出函數(shù)的原型聲明。 <winuser.h> 即主要對(duì) user32.dll 中導(dǎo)出的函數(shù)做聲明索引, 所以若要使用 MessageBox(A/W) #include <winuser.h> (已被 <windows.h> 包含)。正如調(diào)用 printf 函數(shù)需要 #include <stdio.h>

在調(diào)用 printf 函數(shù)或 MessageBox 函數(shù)時(shí),我們僅僅包含了聲明頭文件,沒(méi)有顯式 LoadLibrary à GetProcAddress ,那我們是如何是隱式調(diào)用(定位) DLL 中的 API 的呢?實(shí)際上我們?cè)诶? VC 向?qū)梢粋€(gè) Win32 Console Application 時(shí),向?qū)б呀?jīng)為項(xiàng)目設(shè)置了 link 項(xiàng)( Project Settings à Link à Input à Object/library modules ),其中默認(rèn)鏈接 kernel32.lib 、 user32.lib gdi32.lib 等。

靜態(tài)鏈接庫(kù)( .lib

目標(biāo)代碼集靜態(tài)鏈接庫(kù)

在早期庫(kù)的組織形式相對(duì)簡(jiǎn)單,里面的目標(biāo)代碼只能夠進(jìn)行靜態(tài)鏈接,所以我們稱為“靜態(tài)庫(kù)”,靜態(tài)庫(kù)的結(jié)構(gòu)比較簡(jiǎn)單,其實(shí)就是把原來(lái)的目標(biāo)代碼( *.obj) 集合在一起,鏈接程序 LINKER 根據(jù)每一份目標(biāo)代碼的符號(hào)表查找相應(yīng)的符號(hào)(函數(shù)和變量的名字),找到的話就把該函數(shù)里面需要定位的進(jìn)行定位,然后將整塊函數(shù)代碼放進(jìn)可執(zhí)行文件里,若是找不到需要的函數(shù)就報(bào)錯(cuò)退出。標(biāo)準(zhǔn) Turbo C2.0 中的 C 庫(kù)函數(shù),例如 scanf printf 、 memcpy strcpy 等,就是使用的靜態(tài)庫(kù)技術(shù)。

以下是 C 程序的編譯鏈接過(guò)程: (1) 執(zhí)行 cl /c main.c;cl /c lib1.c;cl /c lib2.c 生成了 main.obj lib1.obj lib2.obj 三個(gè)文件; (2) 執(zhí)行 link /lib lib1.obj;link /lib lib2.obj 生成了 2 個(gè)文件 lib1.lib lib2.lib ; (3) 執(zhí)行 link main.obj lib1.lib lib2.lib 生成 main.exe 。

靜態(tài)鏈接 lib 庫(kù)( Linux 中與之對(duì)應(yīng)的是的 .a 的兩個(gè)特點(diǎn):

1 )鏈接后產(chǎn)生的可執(zhí)行文件包含了所有需要調(diào)用的函數(shù)的代碼,因此占用磁盤(pán)空間較大。

2 )如果有多個(gè)(調(diào)用相同庫(kù)函數(shù)的)進(jìn)程在內(nèi)存中同時(shí)運(yùn)行,內(nèi)存中就存有多份相同的庫(kù)函數(shù)代碼,因此占用內(nèi)存空間較多。

DLL 隱式調(diào)用靜態(tài)鏈接庫(kù)

使用 DLL 隱式鏈接時(shí),可執(zhí)行程序鏈接到一個(gè)包含 DLL 導(dǎo)出函數(shù)信息的輸入庫(kù)文件 (.LIB 文件 ) 。操作系統(tǒng)在加載使用可執(zhí)行程序時(shí)加載 DLL ??蓤?zhí)行程序直接通過(guò)函數(shù)名像調(diào)用其他源文件中的函數(shù)一樣調(diào)用 DLL 中的導(dǎo)出函數(shù)。

我們可以用記事本打開(kāi) C:/Program Files/Microsoft Visual Studio/VC98/Lib 中的 USER32.LIB 文件,其中有

__imp__MessageBoxA@16_ MessageBoxW @16 // 這里 16 為參數(shù)的字節(jié)數(shù)

? _ MessageBoxW @16 USER32.dll USER32.dll/ 889206797

靜態(tài)鏈接庫(kù) lib 文件中存放的是接口函數(shù)的入口地址, dll 中存放的是函數(shù)實(shí)體。當(dāng)我們隱式調(diào)用 dll 時(shí),需要在 Link 選項(xiàng)指明其對(duì)應(yīng)的 lib 庫(kù)。 lib 告訴編譯器你的 dll 都導(dǎo)出了什么函數(shù),以及這些函數(shù)的相對(duì)地址,運(yùn)行的時(shí)候就根據(jù)這些信息就可以找到 dll 中相應(yīng)的 API 。

除了在“ Project Settings à Link à Input à object/library modules” 中填寫(xiě)靜態(tài)鏈接庫(kù)( *.lib )外,我們還可以通過(guò) #pragma comment 宏顯示輸入 *.lib 庫(kù)文件, 例如在網(wǎng)絡(luò)編程中需要添加 WS2_32.LIB 庫(kù),則可以在文件的開(kāi)頭包含頭文件后 #pragma comment ( lib , "WS2_32.LIB" ) 引入靜態(tài)鏈接庫(kù)文件。

由于 我們 經(jīng)常 要調(diào)用一些第三方廠商或其他編譯器編寫(xiě)的動(dòng)態(tài)鏈接庫(kù),但是一般都不提供源文件或 .lib 文件。我們?nèi)糁老鄳?yīng) API 的函數(shù)原型,通過(guò) LoadLibrary à GetProcAddress 以實(shí)現(xiàn)正確的調(diào)用。如果隱式調(diào)用,則需要 lib 文件,可使用 DLL2LIB 工具生成 DLL 對(duì)應(yīng)的 LIB 文件。

在編寫(xiě) MFC 項(xiàng)目時(shí),我們打開(kāi) Project Settings à General Microsoft Foundation Classes 里面有兩種鏈接方式: Use MFC in a Static Library , Use MFC in a Shared Library 。對(duì)應(yīng)在 Visual Studio 2005 中“項(xiàng)目屬性 à 配置屬性 à 常規(guī) à MFC 的使用”中設(shè)置鏈接方式。

如果選擇 Use MFC in a Shared Library 的話,你編譯后的程序中不包含 MFC 庫(kù),所以文件會(huì)比較小,但是如果你的程序直接移到一個(gè)沒(méi)有安裝過(guò) MFC 的機(jī)器上時(shí),可能會(huì)導(dǎo)致找不到 MFC DLL ,故發(fā)布時(shí)要帶 MFC DLL 文件。如果選擇 Use MFC in a Static Library ,那么編譯后的程序就直接包含了 MFC 的靜態(tài)鏈接庫(kù)(目標(biāo)代碼集,相當(dāng)于基于源碼級(jí)集成),文件可能會(huì)大一些,但是可以直接移到其他機(jī)器上運(yùn)行,即發(fā)布時(shí)不用帶 MFC DLL 文件。

參考:

動(dòng)態(tài)鏈接庫(kù) DLL 的創(chuàng)建和使用

深入探究 VC- 編譯 CL.EXE

隱式 鏈接 無(wú).LIB 動(dòng)態(tài)鏈 庫(kù)

由MessageBox透視Win32 API的調(diào)用


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦?。?!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 通江县| 苏尼特左旗| 淮安市| 上蔡县| 罗山县| 安国市| 阿城市| 大同县| 丹巴县| 运城市| 大兴区| 突泉县| 呼伦贝尔市| 左云县| 兴仁县| 开封县| 宁明县| 乡宁县| 正定县| 麻阳| 顺平县| 高雄市| 内江市| 东山县| 丁青县| 盐源县| 上高县| 新安县| 泸西县| 武夷山市| 达拉特旗| 桐庐县| 甘洛县| 台东市| 南康市| 古丈县| 岳普湖县| 西城区| 吐鲁番市| 政和县| 马公市|