java messagebox_由MessageBox透视Win32 API的调用 | 学步园
下面我們來看看Windows平臺下應用程序是怎么調用Windows提供的底層API服務運行的。
我們編寫Win32SDK程序時,需要彈出對話框以作出友好的選擇,MessageBox這個API函數就可以實現該功能。在開頭要添加,因為其包含了眾多的API函數聲明頭文件。為了探究這個小小的MessageBox是怎么彈出來的,我們右擊MessageBox,選擇“Go to definition of MessageBox(轉到定義)”將打開中MessageBox定義處。MessageBox(A/W)的函數原型聲明如下:
// WINUSER.H
WINUSERAPI
int
WINAPI
MessageBoxA(
HWNDhWnd,
LPCSTRlpText,
LPCSTRlpCaption,
UINTuType);
WINUSERAPI
int
WINAPI
MessageBoxW(
HWNDhWnd,
LPCWSTRlpText,
LPCWSTRlpCaption,
UINTuType);
#ifdefUNICODE
#defineMessageBoxMessageBoxW
#else
#defineMessageBoxMessageBoxA
#endif// !UNICODE
我們在使用Windows窗口操作系統時,經常會蹦出大大小小的窗口, MessageBox只是Windows作為提示的對話框窗口單元。那么,MessageBoxW這個API函數到底在哪里實現的呢?應用程序是如何調用系統接口函數的呢?
動態鏈接庫(.dll)
初窺DLL
實際上Windows API函數是定義在一些DLL中的,DLL實現了代碼封裝,從這個角度來看DLL才是真正意義上的API函數包,它是非開源Windows操作系統提供給我們的底層接口。DLL的編制與具體的
動態鏈接庫dll文件(Linux中與之對應的是的.so)存放在C:/WINDOWS/system目錄和C:/WINDOWS/system32目錄下,它在被應用程序調用時才同程序相鏈接。
其中Windows系統最重要的DLL是User32.dll、Gdi32.dll和Kernel32.dll這三個庫文件。這三個庫文件中的API函數大都在頭文件中進行了聲明。從功能上進行分類,User32.dll(Windows XP USER API Client DLL)定義了窗口管理函數,包括窗口的創建、顯示、設置和移動等;Gdi32.dll(GDI Client DLL)定義了圖形設備函數(GDI),實現與設備無關的繪圖功能;Kernel32.dll(Windows NT BASE API Client DLL)定義了系統服務函數,包括諸如內存調度、進程管理等與操作系統有關的底層功能。我們可以通過三種方式來查看DLL文件中的導出函數信息:(1)使用Windows系統的dumpbin命令(在命令行中:C:/WINDOWS/system32>dumpbin ntdll.dll /exports);(2)使用VC自帶的Depends工具(Microsoft Visual Studio 6.0 ToolsàDepends或Visual Studio 2005命令行提示àdepends);(3)ViewDll或ExeScope)。以下使用VC自帶的Depends工具查看user32.dll中MessageBox函數系列。
DLL與API
正如Java的跨平臺(Write Once,Run Everywhere)需要JVM的支持一樣,C/C++成為跨平臺的編程語言,依賴各個平臺(包括操作系統和編譯器)對C/C++標準函數庫的具體平臺實現。
VS編譯器自帶的標準C函數庫,,,中聲明的函數可以到C:/Program Files/Microsoft Visual Studio/VC98/CRT/SRC(或C:/Program Files/Microsoft Visual Studio 8/VC/crt/src)中查看相關實現源代碼。strcat.c文件提供了strcat和strcpy函數的源碼 ,在Windows系統中,C:/WINDOWS/system32/ntdll.dll提供了strcat和strcpy這兩個CRT API的底層實現。用戶對C函數的調用最終通過調用底層API來完成真正的功能。例如C標準庫函數create用于創建文件,但它是靠調用CreateFile(kernel32.dll)函數來完成創建文件功能的;beginthread(process.h,thread.c)需要調用CreateThread(kernel32.dll)函數來完成線程的創建。
DLL的移植升級
Windows將遵循下面的搜索順序來定位DLL: 包含EXE文件的目錄>進程的當前工作目錄>Windows系統目錄>Windows目錄>列在Path環境變量中的一系列目錄。
如果你在本機編寫一個Windows應用程序,移植到其他機子上(當然也是Windows操作系統),有可能因為缺少相關DLL文件而無法執行。因為DLL是動態鏈接,就是隨用隨加載,這就是為什么我們玩3D游戲時經常彈出缺少d3dx9***.dll的錯誤提示。如果啟動的程序調用了一個過期的DLL文件或不匹配的DLL文件,則會出現“未定義的動態鏈接調用”消息。
動態鏈接庫除了實現代碼的共享外,其模塊封裝特性使得應用程序在調用一個DLL的不同版本時,只要導出的函數名相同就不必進行重新編譯鏈接。這樣,軟件產品在更新或升級時,客戶程序不必進行改動。在開發軟件產品時,對于通用功能的函數,一般以DLL的形式來實現。Windows設備驅動程序就是體現上述特點的動態鏈接庫。
DLL的調用
動態鏈接庫的調用方式又分為隱式調用(也稱靜態調用,需要.lib文件)和顯式調用(也稱動態調用,LoadLibraryàGetProcAddressàFreeLibrary)。
那么,在我們編寫的程序中,如何調用DLL中的API呢?既然用戶對C函數的調用最終是通過調用底層API來完成真正的功能,那么,我們在編寫第一個Hello World程序時就已經不知不覺地調用了DLL。實際上中定義的printf函數由msvcrt.dll函數導出,而*printf系列函數在ntdll.dll中有具體底層實現。
DLL文件包括了具體實現的代碼編譯后的結果(二進制的機器碼),而頭文件中的代碼主要是DLL庫文件導出函數的原型聲明。即主要對user32.dll中導出的函數做聲明索引,所以若要使用MessageBox(A/W),需#include(已被包含)。正如調用printf函數需要#include。
在調用printf函數或MessageBox函數時,我們僅僅包含了聲明頭文件,沒有顯式LoadLibraryàGetProcAddress,那我們是如何是隱式調用(定位)DLL中的API的呢?實際上我們在利用VC向導生成一個Win32 Console Application時,向導已經為項目設置了link項(Project SettingsàLinkàInputàObject/library modules),其中默認鏈接kernel32.lib、user32.lib、gdi32.lib等。
靜態鏈接庫(.lib)
目標代碼集靜態鏈接庫
在早期庫的組織形式相對簡單,里面的目標代碼只能夠進行靜態鏈接,所以我們稱為“靜態庫”,靜態庫的結構比較簡單,其實就是把原來的目標代碼(*.obj)集合在一起,鏈接程序LINKER根據每一份目標代碼的符號表查找相應的符號(函數和變量的名字),找到的話就把該函數里面需要定位的進行定位,然后將整塊函數代碼放進可執行文件里,若是找不到需要的函數就報錯退出。標準Turbo C2.0中的C庫函數,例如scanf、printf、memcpy、strcpy等,就是使用的靜態庫技術。
以下是C程序的編譯鏈接過程:(1)執行cl /c main.c;cl /c lib1.c;cl /c lib2.c生成了main.obj lib1.obj lib2.obj三個文件;(2)執行link /lib lib1.obj;link /lib lib2.obj生成了2個文件lib1.lib lib2.lib;(3)執行link main.obj lib1.lib lib2.lib生成main.exe。
靜態鏈接lib庫(Linux中與之對應的是的.a)的兩個特點:
(1)鏈接后產生的可執行文件包含了所有需要調用的函數的代碼,因此占用磁盤空間較大。
(2)如果有多個(調用相同庫函數的)進程在內存中同時運行,內存中就存有多份相同的庫函數代碼,因此占用內存空間較多。
DLL隱式調用靜態鏈接庫
使用DLL隱式鏈接時,可執行程序鏈接到一個包含DLL導出函數信息的輸入庫文件(.LIB文件)。操作系統在加載使用可執行程序時加載DLL??蓤绦谐绦蛑苯油ㄟ^函數名像調用其他源文件中的函數一樣調用DLL中的導出函數。
我們可以用記事本打開C:/Program Files/Microsoft Visual Studio/VC98/Lib中的USER32.LIB文件,其中有
__imp__MessageBoxA@16?_MessageBoxW@16? //這里16為參數的字節數
? _MessageBoxW@16 USER32.dll USER32.dll/889206797
靜態鏈接庫lib文件中存放的是接口函數的入口地址,dll中存放的是函數實體。當我們隱式調用dll時,需要在Link選項指明其對應的lib庫。lib告訴編譯器你的dll都導出了什么函數,以及這些函數的相對地址,運行的時候就根據這些信息就可以找到dll中相應的API。
除了在“Project SettingsàLink
總結
以上是生活随笔為你收集整理的java messagebox_由MessageBox透视Win32 API的调用 | 学步园的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【转载】Swift属性Property
- 下一篇: 深入react技术栈(10):受控组件和