C++ WINDOWS API 第2章 Windows API概要
目錄
2.1?????? Windows數據類型.. 1
2.1.1?????? Windows數據類型示例.. 1
2.1.2?????? Windows 數據類型與標準C 數據類型的關系.. 5
2.1.3?????? Windows 數據類型與Windows API 5
2.1.4?????? Windows 中的數據結構.. 6
2.2?????? Windows API 的功能分類.. 7
2.2.1?????? 系統基本服務.. 7
2.2.2?????? 系統管理.. 9
2.2.3?????? 用戶界面.. 9
2.2.4?????? 圖像和多媒體.. 15
2.2.5?????? 網絡.. 15
2.2.6?????? 其他功能.. 15
2.3?????? Windows API核心DLL. 16
2.3.1?????? Kerne132.dll 16
2.3.2?????? User32.dll 16
2.3.3?????? Gdi32.dll 16
2.3.4?????? 標準C函數.. 17
2.3.5?????? 其他Dll 17
2.4?????? Unicode和多字節.. 17
2.4.1?????? W版本和A版本的API 21
2.4.2?????? Unicode與ASGII的轉換.. 22
2.4.3?????? 對Windows程序設計規范的建議.. 22
2.5?????? 小結.. 23
?
?
?
2.1??? Windows數據類型
Windows API 使用了很多 Windows 自己定義的數據類型。讀者可能較為熟悉 C 語言或 C++語言的數據類型。要熟練使用 Windows API 必須要熟悉 Windows 數據類型。這些數據類型是Windows 特有的。在 SDK 的相關頭文件中有定義。
在眾多的Windows 數據類型中,最常用的有 DWORD、HANDLE、LPTSTR、WORD、BYTE、CHAR 等。在 Windows 系統中,DWORD 用于表示無符號整型的數據,意為 double word,32位。
在一般情況下 BYTE 是 8 位的,而 WORD 是 16 位,DWORD 就是 32 位的。
Windows 系統的應用程序中還具有一個特有的數據類型-HANDLE,通常 HANDLE 類型的變量用于唯一標識一個“對象”,如窗口、控件、文件等,Windows 平臺中存在眾多這樣的對象,對象是程序操作的目標。HANDLE 也是一個 32 位的數據類型。
2.1.1??? Windows數據類型示例
實例2-1使用了幾種基本的 Windows 數據類型,演示 Windows 數據類型在程序中的使用方法。
本實例定義了幾個常用常量的 Windows 數據類型,包括 DWORD,LPSTR 和 CHAR,并演示了如何使用它們進行了復制、比較大小等操作。
/* ************************************ *《精通 Windows API》 * 示例代碼 * windata.c * 2.1.1 常用的 Windows 數據類型 **************************************/ /* 頭文件 */ #include <windows.h> #include <stdio.h> /* ************************************ * 功能 Windows 數據類型演示 **************************************/ int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { //定義字符串 LPSTR szString = "Windows data type, string."; //定義字符數組 CHAR lpString[120];//要大于 szString 的長度 //定義 DWORD 類型的數據 DWORD dwMax = 0xFFFFFFFF; DWORD dwOne = 0x1; //定義 INT 類型的數據 INT iMax = 0xFFFFFFFF; INT iOne = 0x1; //顯示字符串 MessageBox(NULL,szString,"LPSTR",MB_OK); //復制內存,將字符串復制到數組中(包括 NULL 結束符) CopyMemory(lpString, szString,lstrlen(szString)+1); //顯示復制的字符串 MessageBox(NULL,lpString,"CHAR[]",MB_OK); //比較 DWORD 并顯示結果 if(dwMax>dwOne) { MessageBox(NULL,"DWORD 類型的數據 OxFFFFFFFF > 0x1","DWORD",MB_OK); } //比較 INT 并顯示結果 if(iMax<iOne) { MessageBox(NULL,"INT 類型的數據 OxFFFFFFFF < 0x1","INT",MB_OK); } return 0; }?
?
在這個程序中,使用了 4 種 Windows 數據類型,分別是 LPSTR、CHAR、DWORD 和 INT。
LPSTR 類型的數據是字符串,也就是字符指針,CHAR 是字符,DWORD 是 32 位的無符號整數,INT 是 32 位有符號整數。程序運行后會彈出 4 個對話框。這說明 dwMax>dwOne 是成立的。iMax<iOne 也是成立的。dwMax 與 iMax 的數值是一樣的,dwOne 與 iOne 的數值也是一樣的。但是比較結果不同,是因為二者的數據類型不一樣。
?
在 Visual Studio 中可以查看數據類型的定義。在數據類型的類型名(比如“DWORD”)上單擊右鍵,選擇“轉到定義”,如圖 2-1 所示。
?
圖2-1
可以從 SDK 的頭文件中看到各類型的類型定義。
“INT”的定義如下:
typedef int INT;?
“DWORD”的定義如下:
typedef unsigned long DWORD;?
"CHAR"的定義如下:
typedef char CHAR;?
??? 從中可以發現,這些 Windows 數據類型都是從標準 C 的數據類型經過類型重定義而來。INT 數據類型是有符號整型,DWORD 數據類型是無符號整型。 這就說明了為什么在實例 2-1 中 INT 數據類型的變量 iMax 實際是“-1”,而 DWORD 類型的變量 dwMax 實際是“4294967295”,所以會出現如上的比較結果。
表2.1 常用的基本Windows數據類型
| 類型 | 描述 |
| BOOL | 布爾型變量(值只能是True或False) |
| BYTE | 字節類型(8位) |
| CHAR | 8比特字節(ANSI) |
| CONST | 常量,相當于標準C中的”const”關鍵字 |
| DWORD | 32字節無符號整型數據 |
| DWORD32 | 32字節無符號整型數據 |
| DWORD64 | 64字節無符號整型數據 |
| FLOAT | 浮點數據類型 |
| HANDLE | 對象的句柄,最基本的句柄類型 |
| HICON | 圖標的句柄 |
| HINSTANCE | 程序實例的句柄 |
| HKEY | 注冊表鍵的句柄 |
| HMODULE | 模塊的句柄 |
| HWND | 窗口的句柄 |
| INT | 32位符號整型數據類型 |
| INT_PTR | 指向INT類型數據的指針類型 |
| INT32 | 32位符號整型 |
| INT64 | 64位符號整型 |
| LONG | 32位符號整型,相當于C語言的標準數據類型long |
| LONGLONG | 64位符號整型 |
| LONG32 | 32位符號整型 |
| LONG64 | 64位符號整型 |
| LPARAM | 消息的L參數 |
| WPARAM | 消息的W參數 |
| LPCSTR | Windows(ANSI)字符串常量 |
| LPCTSTR | 根據環境配置,如果定義了UNICODE宏,則是LPCWSTR類型,否則是LPCSTR類型 |
| LPCWSTR | UNICODE字符串常量 |
| LPDWORD | 指向DWORD類型數據的指針 |
| LPSTR | Windows(ANSIC)字符串常量 |
| LPTSTR | 根據環境配置,如果定義了UNICODE宏,則是LPTSTR類型,否則是LPSTR類型 |
| LPWSTR | UNICODE字符串常量 |
| SHORT | 無符號短整型(16位) |
| SIZE_T | 表示內存大小,以字節為單位,其最大值是CPU最大尋址范圍 |
| TCHAR | 如果定義了UNICOD,則為WCHAR,否則為CHAR |
| UCHAR | 無符號CHAR |
| UINT | 無符號INT |
| ULONG | 無符號LONG |
| VOID | 無類型,相當于標準C語言的void |
| WCHAR | 16位Unicode字符 |
| WINAPI | Windows API的函數調用方式,常見于SDK頭文件中對API函數的聲明中,相當于__stdcall(更嚴格講,不是數據類型,而是函數調用約定) |
| WORD | 16位無符號整型數據 |
Windows 數據類型的命名都很有規律。
基本數據類型包括 BYTE、CHAR、WORD、SHORT、DOWRD、INT 等。
指針類型的命令方式一般是在其指向的數據類型前加“LP”或“P”,比如指向 DWORD的指針類型為“LPDWORD”和“PDWORD”。
各種句柄類型的命令方式一般都是在對象名前加“H”。Windows 系統中有很多對象,所有表示一個對象的數據類型都是句柄,每一種對象都對應著一種句柄類型,比如與位圖( BITMAP)對應的句柄類型為“HBITMAP”,與菜單(MENU)對應的句柄類型為“HMENU”,與窗口(WINDOW)對應的句柄類型為“HWND”。無符號類型一般是以“U”開頭,比如“INT”是符號類型,“UINT”是無符號類型,“LONG”是符號類型“ULONG”是無符號類型等。
2.1.2??? Windows 數據類型與標準C 數據類型的關系
查看 Windows 數據類型的定義可以看到,所有的 Windows 數據類型都是由 C 數據類型經過類型重定義得到的。如 DWORD 實質上就是 unsigned long 數據類型,32 位的無符號整型:
typedef unsigned long DWORD;?
實際上 VC 編譯器是一個完整的 C 編譯器,此外并沒有過多的擴展。Windows 數據類型也不是 VC 的內建類型,而從標準 C 類型重定義得到。
2.1.3??? Windows 數據類型與Windows API
Windows API 函數的參數、返回值或一些重要的常量使用的數據類型都是 Windows 數據類型。如:
int MessageBox( HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType );?
MessageBox 函數的返回值是 int 型的,是標準 C 數據類型,但是所有的參數都使用了Windows 數據類型。如 HWND 是一種 W indows 數據類型,用于表示窗口的句柄;LPCTSTR 也是Windows 數據類型,表示字符串常量;UINT 也是 Windows 數據類型,為無符號整型。
2.1.4??? Windows 中的數據結構
Windows 中包含很多種數據結構類型,在不同類型的 API 中會使用到不同的數據結構,由于數據結構的數量眾多,將在后續章節具體的實例中介紹實現每一種功能所使用的數據結構。數據結構通常會作為一些 API 的參數輸入。
typedef struct _WIN32_FILE_ATTRIBUTE_DATA{ DWORD dwFileAttributes; FILETIME ftCreationTime; FILETIME ftLastAccessTime; FILETIME ftLastWriteTime; DWORD nFileSizeHigh; DWORD nFileSizeLow; } WIN32_FILE_ATTRIBUTE_DATA,*LPWIN32_FILE_ATTRIBUTE_DATA;?
相當于:
typedef struct _WIN32_FILE_ATTRIBUTE_DATA{ DWORD dwFileAttributes; FILETIME ftCreationTime; FILETIME ftLastAccessTime; FILETIME ftLastWriteTime; DWORD nFileSizeHigh; DWORD nFileSizeLow; }; typedef _WIN32_FILE_ATTRIBUTE_DATA WIN32_FILE_ATTRIBUTE_DATA; typedef _WIN32_FILE_ATTRIBUTE_DATA *LPWIN32_FILE_ATTRIBUTE_DATA;?
Windows SDK 中,結構體也有自己的命名規范。一般情況下,Windows 系統中使用全大寫來命名結構體、共用體,并使用“_”來分隔單詞,在結構名加“LP”或“P”表示指向數據結構的指針。
2.2??? Windows API 的功能分類
Windows API 所能實現的功能包括很多方面,在進行應用程序的開發時,開發人員可能會使用到文件、進程、內存、權限、系統信息等系統的基本服務和系統管理類的 API,可能會用到圖形用戶界面、控件等函數和對象,可能需要在界面上繪制圖像處理多媒體信息等,還包括進行網絡通信開發等。
2.2.1??? 系統基本服務
系統基本服務是 Windows API 最基本的內容,是最常使用到的程序接口。系統基本服務API 包括以下幾個方面。
對文件的基本操作包括文件的創建、打開、讀寫、關閉、刪除,文件屬性的設置與獲取,目錄操作,以及磁盤分卷的操作,還包括鏡像文件、加密文件系統等。
主要是內在的分配、共享、釋放等內容,包括虛擬內存管理、分頁機制、堆管理等。
包括進程主程序( exe)、模塊、動態鏈接庫(dll)的編寫;線程的基本概念,線程創建、遍歷、同步等操作;進程與權限;線程與纖程等內容。
包括設備對象等基本概念。加載與卸載驅動程序,控制驅動程序,與驅動程序通信等。
包括如何開發調試器,程序運行錯誤的處理,日志的記錄、Windows 可執行文件的結構等。
包括注冊表的操作,如打開注冊表,讀取、寫入鍵值,創建、刪除鍵;還包括系統基本信息的獲取和設置,如系統目錄、系統版本、計算機名等。
包括使用共享文件進行進程間通信的方法,使用消息進行進程間通信的方法,使用郵槽、管道等進行進程間通信的方法,使用網絡共享進行進程間通信的方法。
消息機制是 Windows 系統中很重要的一種機制。幾乎所有的 Windows 應用程序都在與消息打交道,而 Windows 的消息機制又是依賴于定時器的。所以了解 Windows 消息機制是學習Windows 應用程序開發的重要內容。
Windows 的系統基本服務還包括性能監視、電源管理、索引與數據存儲等,也將在本書中有所涉及。
本實例使用了 Windows 系統基本服務中的部分 API,實現將系統目錄路徑寫入文件中。在這里不對實現原理做過多的解釋,只是使讀者對 Windows 系統服務 API 有初步的了解。
/* ************************************ *《精通 Windows API》 * 示例代碼 * basic.c * 2.2 Windows API 的功能分類 **************************************/ /* 頭文件 */ #include <windows.h> /* ************************************ * 功能 獲取系統目錄信息,并存儲到文件中 **************************************/ int main(int argc, TCHAR argv[]) { //文件句柄 HANDLE hFile; DWORD dwWritten; //字符數組,用于存儲系統目錄 TCHAR szSystemDir[MAX_PATH]; //獲取系統目錄 GetSystemDirectory(szSystemDir,MAX_PATH); //創建文件 systemroot.txt hFile = CreateFile("systemroot.txt", GENERIC_WRITE, 0,NULL,CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); //判斷文件是否創建成功 if(hFile != INVALID_HANDLE_VALUE) { //將系統目錄系統信息寫入文件 if(!WriteFile(hFile,szSystemDir,lstrlen(szSystemDir),&dwWritten,NULL)) { return GetLastError(); } } //關閉文件,返回。 CloseHandle(hFile); return 0; }?
運行程序,在程序所在的目錄會生成文件“systemroot.txt”,文件內容為系統目錄。
2.2.2??? 系統管理
系統管理是 Windows 系統中很重要的內容。Windows 系統提供了以下方面的 API 供應用程序開發人員使用,包括:管理控制臺接口、程序安裝、系統恢復、任務調度、Windows 運程管理。
2.2.3??? 用戶界面
用戶界面開發是 Windows 應用程序開發的重要內容。Windows 用戶界面主要包括兩個部分,Windows Shell 和 Windows 圖形用戶界面。Windows 圖形用戶界面包括窗口對象的相關內容,界面資源,控件、用戶數據交換(粘貼板等)和用戶輸入的處理。
包括一些基本數據概念和對象:窗口類、消息對列、窗口過程(消息處理函數)、窗口屬性等。 主要包括的 API 有窗口類注冊的函數、窗口建立與關閉函數、窗口屬性修改函數等。
資源是 Windows 應用程序中很重要的一項內容,在可執行文件中,專門有用于存儲資源的節。 這里所說的資源是界面資源,包括圖標、菜單、字符串、版本信息、對話框、動態光標、插入號(Carets)等。資源的處理涉及眾多 API 函數。
包括對話框、鍵盤加速器(快捷鍵)、鍵盤輸入、鼠標輸入、原始數據輸入等。這些概念是程序通過用戶界面與用戶進行交互的基本概念。
包括 Atom 表(包括了若干字符串和標識符)、粘貼板、數據復制、動態數據交接等基本概念,是用戶和應用程序通過用戶界面進行數據交換的主要載體。
Windows 系統提供了不少于 30 種的控件供應用程序使用,其中最常用的幾種包括 Edit控件(文本框)、Button 控件(按鈕)、ListView 控件(列表)、ToolTip 控件(提示框)、ComboBox 控件(下拉選擇框)、Tree-View 控件(樹)、Rich-Edit 控件(多功能文本框)、Tab 控件(分頁)、Process 控件(進度條)等。
Windows 桌面瀏覽器(explorer.exe)的功能強大,Windows Shell 應用程序可以利用WindowsShell 桌面的程序接口達到管理系統、定制圖標和默認程序、擴展桌面功能等目的。
?
實例中,首先注冊了窗口類,然后創建了一個窗口,創建窗口時指定的窗口的屬性和窗口消息的處理函數。函數消息的處理函數大多調用系統默認函數來處理。如下:
D:\002>cl window.cpp user32.lib gdi32.lib 用于 80x86 的 Microsoft (R) 32 位 C/C++ 優化編譯器 15.00.21022.08 版 版權所有(C) Microsoft Corporation。保留所有權利。 window.cpp Microsoft (R) Incremental Linker Version 9.00.21022.08 Copyright (C) Microsoft Corporation. All rights reserved. /out:window.exe window.obj user32.lib gdi32.lib?
運行效果:
?
2.2.4??? 圖像和多媒體
Windows 的圖像引擎和多媒體編程有多種接口,包括最基本的 GDI、GDI+,以及更高級的OpenGL、DirectX 等圖像引擎編程接口。DirectX 和 OpenGL 在游戲開發、動畫制作等方面應用比較廣泛,使用它們進行應用程序開發需要專門的 SDK。本書只講解 GDI,對一般的應用程序開發,已經足夠使用。
GDI 的基本概念包括圖像(Image)、位圖(Bitmaps)、筆(Pen)、畫刷(Brush)、文本和字體( Text and Fonts)、線(Line)、區域(Regions)、形狀(Shapes)等。其基本的功能是對顯示設備進行控制、獲取和修改相關配置,在計算機屏幕上顯示用戶所需要顯示的內容。
2.2.5??? 網絡
用戶利用 Windows API 可以開發基于各種網絡協議的應用程序,例如 TCP\UDP Socket、HTTP、DHCP、RPC、QOS、藍牙,以及傳真、點對點文件傳輸、即插即用設備管理等。 還可以進行網絡管理,包括網絡的基本信息,使用 IP helper 獲取網絡配置和網絡信息、進行網絡監視等。 同時微軟還提供了進行網絡安全編程的部分接口,主要是防火墻 Windows、防火墻 API,以及一些 Windows 自帶的網絡應用程序的接口,包括 IE、Outlook 等。
2.2.6??? 其他功能
Windows API 能實現的功能還有很多,限于篇幅不能全部介紹。有一些內容本書未涉及,但是 Windows API 也提供了相關接口。
包括微軟的“動態數據存取組件”技術(MDAC,包含了 ADO、ODBC)、OLE 數據庫、XML 標準、微軟 XML、可擴展存在引擎等多方面內容。主要是 Windows 系統內的數據庫文件、Windows.系統對數據庫的訪問接口等技術。
2.消息與協作
消息與協作大多是 Windows 系統自帶的一些應用程序所提供的開發接口。其中最主要的內容是“協作數據對象”( CDO)。CDO 包括了若干種 Windows 數據傳輸典型應用,包括 Mssager (MSN)、郵件 SMTP (Outlook)應用接口等。
3.Web 開發
IIS(Intemet Information Server,互聯網信息服務)等應用程序提供的開發接口,使用戶可以直接在 Windows 平臺上進行 Web 開發,開發的程序運行于 ns 框架下。“數據存在與訪問”、“消息與協作”、“Web 開發”等都可以歸為 COM 開發的范圍內。COM 是 Windows 應用程序接口的一種,具有固定的接口模式,大多是 Windows 系統中自帶的應用程序所提供的開發接口的集合。
2.3??? Windows API核心DLL
在 Windows 的系統目錄中,存在著很多的動態鏈接庫文件(DLL 文件)。這些 DLL 文件中 包括了 Windows API 函數可執行程序。DLL 將各函數“導出”,這樣應用程序就可以找到 DLL中的函數地址,當應用程序調用 Windows API 時,程序會運行到 DLL 中。API 函數主要存在于幾個核心的動態連接庫文件中。Keme132.dll 是最重要的 DLL,Windows 系統最主要的系統服務 API 函數都存在于 Kerne132.dll 中。User32.dll 主要包括圖形用戶界面中所使用到的一些函數接口。 GDI32.dll 中,主要包括 Windows 圖形引擎中的接口函數。
當用戶調用一個 API 時,系統會通過程序文件中的導入表結構找到需要調用的 API 函數位于哪個 DLL,確定函數的地址,以便應用程序可以成功調用 API 函數。
2.3.1??? Kerne132.dll
Keme132.dll 包括了系統基本服務中最基本的 API 函數,如文件系統、進程與線程、內存管理等。 Windows XPSP2 系統中,Keme132.d11 有 949 個導出函數,例如,CreateFileA、CreateProcessA、OpenThread、SetFileTime 等。本書將在后續章節中通過實例介紹這些 API的使用。
2.3.2??? User32.dll
User32.dll 是 Windows 圖形用戶界面的主要支持。一些重要的圖形用戶界面函數由User32.dll 函數導出。Windows XP SP2 系統中,User32.dll 有 732 個導出函數,例如CreateWindowExW、RegisterClassA 等。
2.3.3??? Gdi32.dll
Gd132.dll 是 Windows GDI 應用程序設計接口,Gdi32.dll 導出了與此相關的若干函數,如 GetTextColor、LineTo、TextOutA 等。
2.3.4??? 標準C函數
標準 C 程序是一種標準,任何支持 C 語言應用程序開發的系統都應該提供 C 語言庫函數的 調用。在系統環境下使用標準 C 進行程序開發時,用戶所使用的庫函數實際上是由操作系統提供的。正是由于各個主流操作系統都提供了一套標準 C 庫所定義的函數接口,標準 C 函數庫才會有如此廣泛的跨越操作系統平臺。所以 C 程序仍然依賴于操作系統開發人員為其實現接口,而 C 庫函數的實現仍然依賴于操作系統提供的調用接口,如標準 C 函數 fopen 函數在Windows 系統中的實現就依賴于 API CreateFile 函數(CreateFile 實現了文件的創建和打開等操作)。
Windows 系統的 C 標準庫函數接口主要存在于crtdll.dll 中。實際上,C 標準函數庫必須由操作系統為其提供接口,否則使用標準 C 開發的程序無法在特定的系統上運行。 Windows XP SP2 系統中,crtdll.dll 有 526 個導出函數,如 fopen、printf. strlen等。
2.3.5??? 其他Dll
當然,Windows 系統中的 DLL 文件遠遠不止這幾個,Windows 系統提供了非常豐富而且功能強大的 API,上文已經介紹了 Windows API 所主要依賴的幾個 DLL,其他的 DLL 庫文件由于過于龐雜,就不一一介紹,將在后續的章節中有所涉及。讀者只需要了解調用 Windows API 的基本原理就可以了。
2.4??? Unicode和多字節
Windows 既可以使用 Unicode 字符集又可以使用傳統的字符集(如多字節編碼)來實現對多種語言的支持,以適應國際市場的要求。與傳統的字符集編碼相比,Unicode 是世界通用的字符編碼標準,使用 16 位數據表示一個字符,一共可以表示 65535 種字符,可以包括現代計算機中所使用的所有字符,包括各種字母、文字、在出版業中使用的特殊符號等。 傳統的字符集,如 Windows ASNI 字符集,使用 8 位數據或將相鄰的兩個 8 位的數據組合在一起表示特殊的語言字符。Windows 系統采用了 ASNI 字符的擴展方式,如果一個字節是負數,則將其后續的一個字節組合在一起表示一個字符。這種編碼方式的字符集也稱作“多字節”字符集。
在 Windows 系統中,Unicode 字符編碼和多字節字符編碼都可以使用。
?
在本實例中,一共使用了 3 種類型的字符串變量,每種類型的字符串變量的初始化是不同的,如表 2.2 所示。
表2.2 字符串與初始化
| 類型 | 變量類型 | 初始化形式 |
| Unicode | LPWSTR | L”string” |
| 多字節 | LPSTR | ”string” |
| 根據開發環境的設置自動適應 | LPTSTR | TEXT(”string”) |
本實例首先使用“多字節”方式進行編譯。可以使用二進制編輯器來查看編譯得到的可執行文件,上例中定義的字符串分別存儲為以下形式。使用二進制編輯器查看,可以從 exe可執行文件中找到如下信息。讀者可以對照 ASCII 編碼表查看。
“This is a Unicode String;”使用 Unicode 方式的十六進制編碼:
54 00 68 00 69 00 73 00 20 00 69 00 73 00 20 00 61 00 20 00 55 00 6e 00 69 00 63 00 6f 00 64 00 65 00 20 00 53 00 74 00 72 00 69 00 6e 00 67 00 3b 00?
?
“This is not a Unicode String;”使用 ASCII 方式的十六進制編碼:
54 68 69 73 20 69 73 20 61 20 55 6e 69 63 6f 64 65 20 53 74 72 69 6e 67 3b?
?
“This string is Unicode or not depends on the option.”的ASCII 方式的十六進制編碼:
54 68 69 73 20 73 74 72 69 6e 67 20 69 73 20 55 6e 69 63 6f 64 65 20 6f 72 20 6e 6f 74 20 64 65 70 65 6e 64 73 20 6f 6e 20 74 68 65 20 6f 70 74 69 6f 6e 2e?
之后是“<字符編碼 1>”和 Unicode 編碼、“<字符編碼 2>”和“<字符編碼 3>”的多字節編碼。對漢字字符,兩種編碼的方式是不同的,如“字符編碼”四個字,兩種編碼分別為:
Unicode編碼
57 5b 26 7b 16 7f 01 78?
?
和多字節ASCII
d7 d6 b7 fb b1 e0 c2 eb?
?
讀者可以分析設置使用 Unicode 字符集后編譯完成的可執行文件與設置為多字節字符集后編譯得到的可執行文件有什么不同。
?
設置的方法是在Visual Studio工程屬性中選擇“配置屬性”→“常規”→“字符集”選項中進行選擇。
2.4.1??? W版本和A版本的API
Windows 支持 Unicode 和 ASCII 編碼的字符。Windows 系統 API 凡是以字符串作為參數的很多具有 W 和 A 兩個版本以實現兩種不同編碼的字符處理。
下面以 MessageBox 為例介紹兩種不同版本 API 函數的使用。在 User32.dll 中導出的函數實際上沒有 MessageBox,只有 MessageBoxA 和 MessageBoxW,這兩者是同一個 API,實現了同樣的功能。不同的是,MessageBoxA 以多字節字符串作為參數輸入,MessateBoxW 以Unicode 字符串作為參數輸入。
可以從 User32.dll 的導出函數看到兩個不同版本的 API 函數。在 Platform SDK 中,MessageBox 函數聲明所在的頭文件中發現如下定義(以下代碼來自于 Microsoft Platform SDK):
WINUSERAPI int WINAPI MessageBoxA( __in_opt HWND hWnd, __in_opt LPCSTR lpText, __in_opt LPCSTR lpCaption, __in UINT uType); WINUSERAPI int WINAPI MessageBoxW( __in_opt HWND hWnd, __in_opt LPCWSTR lpText, __in_opt LPCWSTR lpCaption, __in UINT uType); #ifdef UNICODE #define MessageBox MessageBoxW #else #define MessageBox MessageBoxA #endif // !UNICODE?
可以看到,在程序進行編譯和連接時,如果程序在 UNICODE 環境下,會使用 MessageBoxW,否則使用 MessageBoxA。
軟件開發人員可以自行設定使用 Unicode 編碼或都多字節編碼文件,不影響程序的正常功能。
但如果在編寫程序時,使用的字符集與代碼中使用的函數不一致、定義的字符串變量不兼容,將會引起編譯錯誤或者運行程序顯示亂碼,甚至可能引起程序運行錯誤,這一點需要引起注意。
2.4.2??? Unicode與ASGII的轉換
Windows 專門提供了若干個 API 來實現對字符編碼的轉換工作。ideCharToMultiByte、MultiByteToWideChar、UnicodeToBytes 函數可以完成這些工作。
WideCharToMultiByte 函數將 Unicode 字符串轉換為多字節字符串,以適應 A 版本的API,MultiByteToWideChar 函數將多字節字符串轉換為了 Unicode 字符串,以適應 W 版本的 API 的參數形式要求。
2.4.3??? 對Windows程序設計規范的建議
每個程序員都有自己的規范化編程習慣。代碼的規范不是本書的重點,所以這里只給出一些微軟經常使用代碼規范,MSDN 的示例中,SDK 的頭文件和例子中幾乎都是使用的這種方法。
變量名:通常采用所謂的“匈牙利命名法”,變量名由“類型縮寫(小寫)”+“變量描述(單詞首字母大寫)”構成,如字符串類型的變量可以命名為 szFileName,DWORD 類型的數據可以命名為 dwFileSize,指針類型可以命名為 lpBuffer,句柄類型的變量可以命名為 hLogFile 等。
函數名:各單詞的首字母大寫,如 EnumerateFilesInDrectory、ShowFileSize 等。
類型名:全大寫,各單詞以下劃線分隔,如 WIN32_FILE_ ATTRIBUTE_DATA、DWORD、 HANDLE 等。
常量:同類型名的命名方式。
宏:多與類型名命名方式相同,有的也與函數名命名方式相同。 大括號與代碼段:一般大括號獨立占一行,大括號內的代碼段縮進。如果代碼段僅一行(如 if-else 后的語句),也建議使用大括號。
在調用或定義函數時,如果函數太長,可以分行寫,將每個參數寫一行。一般多于 3個參數的函數需要分行寫,以美觀和方便閱讀為原則。
在本書的示例中,都將盡量使用這些規范化的方式。
?
2.5??? 小結
PDF下載:http://files.cnblogs.com/yongfeng/WINDOWSAPI02.rar
摘自:《精通Windows.API-函數、接口、編程實例》 人民郵電出版社
范文慶、周彬彬、安靖編著
from:?http://www.cnblogs.com/yongfeng/archive/2013/04/30/3051696.html
總結
以上是生活随笔為你收集整理的C++ WINDOWS API 第2章 Windows API概要的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++ WINDOWS API 第1章
- 下一篇: 数据分类:决策树Decision Tre