一丶什么是Win32 API? 微軟為了保護(hù)操作系統(tǒng)的安全性和穩(wěn)定性,把系統(tǒng)分為內(nèi)核層和用戶層(內(nèi)核層的代碼只能在當(dāng)CPU的特權(quán)級(jí)為R0狀態(tài)下執(zhí)行,用戶層的代碼在CPU特權(quán)級(jí)為R0和R3都能執(zhí)行),windows在內(nèi)核層構(gòu)建了一套管理和保護(hù)機(jī)制,用于維護(hù)系統(tǒng)的正常運(yùn)行,這些機(jī)制的實(shí)現(xiàn)被稱為系統(tǒng)內(nèi)核。為了區(qū)別于windows的內(nèi)部實(shí)現(xiàn),把我們?nèi)粘J褂玫膽?yīng)用程序所運(yùn)行的環(huán)境稱為用戶層,此時(shí)CPU特權(quán)級(jí)為R3,無(wú)法調(diào)用系統(tǒng)的內(nèi)核函數(shù)。但是,只有內(nèi)核函數(shù)才能操控硬件,所以windows又提供了可在用戶層調(diào)用的函數(shù)接口,即Windows API,調(diào)用API最后調(diào)用的是系統(tǒng)的內(nèi)核函數(shù)。 所有基于NT內(nèi)核(XP到Win10都是基于NT內(nèi)核開發(fā))的Windows API都可以稱為Win32,即便是64位系統(tǒng),也用這個(gè)名稱,因?yàn)?4位系統(tǒng)是完全兼容32位程序的(純32位系統(tǒng)不兼容16位程序),所以你可以看到這些DLL名稱都有個(gè)"32"的后綴。那我們用C/C++寫程序,沒用到Win32,怎么也能夠執(zhí)行分配內(nèi)存,打開進(jìn)程等操作呢?實(shí)際上在Windows系統(tǒng)上的C/C++的運(yùn)行庫(kù)內(nèi)部也是封裝了Win32API。進(jìn)一步說,幾乎所有運(yùn)行在Windows用戶層的程序都調(diào)用了Win 32API。 Windows采用分層結(jié)構(gòu),大致來(lái)說就是(用戶層->內(nèi)核層->硬件抽象層->硬件層)(這里的分層只是指一個(gè)功能分成多個(gè)層次執(zhí)行,Windows下CPU只有內(nèi)核模式R0和用戶模式R3兩種狀態(tài)), 一個(gè)Win32 API調(diào)用的大體過程如下: Win32 API(kernel32.dll、user32.dll等函數(shù))->調(diào)用ntdll.dll函數(shù)->使CPU進(jìn)入內(nèi)核模式(改變CPU特權(quán)級(jí)為R0)->查表并調(diào)用ntoskrnl.exe或win32k.sys內(nèi)的函數(shù)(ntoskrnl.exe即nt系統(tǒng)內(nèi)核程序,提供內(nèi)存、進(jìn)程管理等服務(wù),同時(shí)內(nèi)部包含了windows的內(nèi)核函數(shù)。在任務(wù)管理器中的名字為System)->執(zhí)行結(jié)束返回到用戶模式(改模CPU特權(quán)級(jí)為R3) Win 32API大多是微軟提供的給ntdll.dll函數(shù)的封裝,而ntdll.dll是執(zhí)行內(nèi)核函數(shù)的中介層,由其內(nèi)的函數(shù)進(jìn)入內(nèi)核(改變CPU特權(quán)級(jí))并調(diào)用內(nèi)核函數(shù)。你可以直接調(diào)用ntdll.dll的函數(shù),甚至自己編寫訪問內(nèi)核函數(shù)的接口(有些調(diào)用被windows保護(hù)程序禁止),這樣程序的運(yùn)行效率會(huì)更高,但是我們還是從那幾個(gè)常用的dll開始學(xué)習(xí)更為簡(jiǎn)單。要知道的是,雖然通過Win32 API調(diào)用了內(nèi)核函數(shù),實(shí)現(xiàn)了用戶層與內(nèi)核層的交互,但其實(shí)大多內(nèi)核函數(shù)都是未公開的。 二丶為什么要學(xué)Win32 API? 現(xiàn)在用于windows平臺(tái)的程序開發(fā)方式日新月異,種類繁多,比如使用Delphi、WPF、Qt等,開發(fā)效率遠(yuǎn)高于使用Win32 API開發(fā),那為什么還要學(xué)習(xí)使用Win32 API開發(fā)呢? ?、倮斫釽indows程序底層運(yùn)行機(jī)制。 ?、趲椭鷮W(xué)習(xí)Windows上其他的編程語(yǔ)言、平臺(tái)。 ?、蹖?shí)現(xiàn)其他庫(kù)沒有提供的高級(jí)功能,比如修改其他進(jìn)程內(nèi)存等。
三丶如何學(xué)習(xí)? 學(xué)習(xí)Win32,其實(shí)只是在學(xué)習(xí)兩樣?xùn)|西:機(jī)制、函數(shù) 機(jī)制是Winows運(yùn)作的規(guī)則,函數(shù)是實(shí)現(xiàn)功能的手段 Windows已經(jīng)推出了成千上萬(wàn)個(gè)API函數(shù),要想一一搞懂是不可能的,也是完全沒有必要的。學(xué)習(xí)的目的在于實(shí)踐,不用于實(shí)踐的學(xué)習(xí)沒有價(jià)值,也很容易遺忘。 本文簡(jiǎn)單介紹最常用函數(shù)及相關(guān)機(jī)制,需要深入了解請(qǐng)自行查閱MSDN文檔及相關(guān)文獻(xiàn)。
四丶開始前你必須知道 語(yǔ)言基礎(chǔ): C/C++ 開發(fā)平臺(tái): Visual Studio 編碼格式:Unicode ---------------------- 為什么區(qū)分編碼格式? windows程序的編碼格式分為兩種:ANSI(MBCS:多字節(jié)字符集)和Unicode,Windows會(huì)按程序的編碼格式解碼字符。 ANSI:根據(jù)系統(tǒng)當(dāng)前設(shè)置的語(yǔ)言采用不同編碼,比如系統(tǒng)語(yǔ)言設(shè)置為簡(jiǎn)體中文,則ANSI采用GBK編碼。 Unicode:統(tǒng)一的字符集,在所有系統(tǒng)中均相同,每個(gè)字符占用兩個(gè)字節(jié)。 為什么使用Unicode? ①Windows NT是使用Unicode開發(fā)的,調(diào)用API時(shí)要把ANSI字符轉(zhuǎn)換成Unicode字符,直接使用Unicode可以提高運(yùn)行效率。 ?、谑鼓愕某绦蛟诓煌Z(yǔ)言的系統(tǒng)上運(yùn)行時(shí)不會(huì)出現(xiàn)亂碼。 ?、垡恍〢PI只能處理Unicode字符。 怎么設(shè)置Unicode? 修改編譯器設(shè)置 項(xiàng)目->屬性->高級(jí)->字符集:使用Unicode字符集 設(shè)置后觀察 項(xiàng)目->屬性->C/C++->命令行:看到兩個(gè)選項(xiàng) /D "_UNICODE" /D "UNICODE",說明已成功設(shè)置為Unicode編碼,否則看到選項(xiàng) /D "_MBCS",說明使用的是MBCS編碼。 其中_UNICODE定義在C運(yùn)行庫(kù)的頭文件中,UNICODE定義在Windows的頭文件中。 ---------------------- 盡量使用Windows數(shù)據(jù)類型 在平時(shí)使用C/C++編程時(shí),我們都使用C/C++標(biāo)準(zhǔn)提供的數(shù)據(jù)類型,比如:char,shot,int,long int等等,但是在使用Windows API編程時(shí),我們應(yīng)該盡量使用Windows提供的數(shù)據(jù)類型,因?yàn)閃in32 API函數(shù)都是使用Windows數(shù)據(jù)類型編寫的,所以你必須要認(rèn)識(shí)它。事實(shí)上,這些Windows數(shù)據(jù)類型都是在windows頭文件中對(duì)C/C++庫(kù)原生類型的宏定義,本質(zhì)上并無(wú)差別。下面列舉常見的Windows數(shù)據(jù)類型。 類型前綴: c=const 常量 u=unsigned 無(wú)符號(hào) p=pointer 指針 h=handle 句柄 w=word 字 dw=double word 雙字 lp=long pointer 長(zhǎng)指針 函數(shù)后綴: A=ansi字符 參數(shù)接受ANSI字符 W=wide寬字符 參數(shù)接受Unicode字符 Ex=extended 擴(kuò)展版函數(shù),在原函數(shù)基礎(chǔ)上增加某些新的特性 Windows類型舉例: typedef int INT; typedef int BOOL; typedef unsigned int UINT; typedef unsigned short WORD; typedef WORD near *PWORD; typedef WORD far *LPWORD; 其他定義詳見 <minwindef.h> ------------------------ 在字符串前添加 L標(biāo)志:該字符串將按寬字符(Unicode)編碼 TEXT、__TEXT(winnt.h內(nèi)定義的宏) 如果 UNICODE被定義,則在字符串前添加L _T、__T、_TEXT(tchar.h內(nèi)定義的宏) 如果 _UNICODE被定義,則在字符串前添加L #ifdef UNICODE #define __TEXT(x) L##x #else #define __TEXT(x) x #endif ------------------------ 帶T前綴的數(shù)據(jù)類型,根據(jù)是否定義UNICODE使用寬/窄字符 #ifdef UNICODE typedef wchar_t TCHAR; #else typedef char TCHAR; #endif 五丶其他 筆者學(xué)習(xí)中,盡量在保持準(zhǔn)確性、嚴(yán)謹(jǐn)性的同時(shí)使用比較自然的語(yǔ)言來(lái)寫。 水平有限,不足之處歡迎批評(píng)指正。
本文由Celng原創(chuàng),轉(zhuǎn)載請(qǐng)標(biāo)明出處。 |
|