Windows API

Windows應用程式接口（Windows API），或俗稱的WinAPI，是微軟Windows作業系統中的一套核心應用程式接口。Windows API這一叫法實際上是多個Windows平台上相似接口的統稱，這些接口也擁有各自的名字，如Win32 API。幾乎所有的Windows應用程式都在與 Windows API 進行交互。

Windows API將與Windows系統有關的複雜操作封裝在簡單的函數當中，編譯成動態連結庫，再隨Windows一同發布。開發者可以簡單地藉助這些函數來完成複雜的操作，有效降低了編寫Windows程序的難度。

Windows有一個軟體開發套件（SDK, software development kit）提供相應的文檔和工具，以使程式設計師開發使用Windows API的軟體和利用Windows技術。

C是Windows API（Win32）的主要程式語言，在該API的文檔中所公開的函數和數據結構均以該語言進行了描述。但是，如果某種程式語言能夠處理（明確定義的）低級數據結構，並能按照規定進行調用與回調，那麼其編譯器或彙編器也可以調用Windows API。類似地，在歷史上Windows API也由多種語言進行了開發。儘管C不是面向對象的程式語言，但Windows API和Windows都具有面向對象的特性；同時，也有許多面向對象語言的包裝類和擴展（如微軟基礎類庫MFC、可視化組件庫VCL、GDI+等）使這種面向對象的結構更加清晰。例如，Windows 8提供的Windows API和WinRT API就是用C++實現的，並且在設計上也是面向對象的。

## 概述

Windows API所提供的功能可以歸為八類：

### 基礎服務（Base Services）

提供了對Windows系統可用的基礎資源的訪問接口，包括文件系統（file system）、外部設備（device）、進程（process）、線程（thread）和錯誤處理（error handling）等。這些功能接口在16位Windows中位於kernel.exe、krnl286.exe或krnl386.exe中；在32位和64位Windows下位於kernel32.dll和KernelBase.dll中。這些文件在所有Windows的\Windows\System32 目錄中都可以被找到。

### 高級服務（Advanced Services）

提供了對內核以外功能的訪問，包括註冊表（Windows registry）、關閉/重啟系統（shutdown/restart）、服務（Windows Service）、使用者帳戶（user accounts)等。這些函數位於32位Windows上的advapi32.dll和advapires32.dll中。

### 圖形設備接口（GDI）

提供了將圖形內容輸出到顯示器、印表機和其他外部輸出設備的功能。它位於16位Windows下的gdi.exe，以及32位Windows下的gdi32.dll中。

### 圖形化使用者界面（GUI）

提供了創建和管理窗口和大多數基本控制項（control）、接收滑鼠和鍵盤輸入，以及其他與GUI有關的功能。這些調用接口位於：16位Windows下的user.exe，以及32位Windows下的user32.dll。從Windows XP版本之後，基本控制項和通用對話框控制項（Common Control Library）的調用接口放在comctl32.dll中。

### 通用對話框連結庫（Common Dialog Box Library）

為應用程式提供標準對話框（如打開／保存文件對話框、顏色對話框和字體對話框等）。這個連結庫位於：16位Windows下的commdlg.dll中，以及32位Windows下的comdlg32.dll中。它被歸類為User Interface API之下。

### 通用控制項連結庫（Common Control Library）

為應用程式提供接口來訪問作業系統提供的一些高級控制項。比如像：狀態欄（status bar）、進度條（progress bars）、工具欄（toolbar）和標籤（tab）。這個連結庫位於：16位Windows下的commctrl.dll中，以及32位Windows下comctl32.dll中。它被歸類為User Interface API之下。使用API函數InitCommonControls或InitCommonControlsEx初始化（即註冊）相應的窗口類。InitCommonControlsEx實際註冊指定的通用控制項的窗口類。注意ICC_WIN95_CLASSES代表12個控制項類的集合。InitCommonControls是個空函數，但會使應用程式加載comctl32.dll；在comctl32.dll加載到進程時會在DLL的入口點調用InitCommonControlsEx註冊ICC_WIN95_CLASSES控制項類。

### Windows Shell

作為Windows API的組成部分，不僅允許應用程式訪問Windows Shell提供的功能，還對之有所改進和增強。它位於16位Windows下的shell.dll中，以及32位Windows下的shell32.dll中（Windows 95則在shlwapi.dll中）。它被歸類為User Interface API之下。

### 網路服務（Network Services）

為訪問作業系統提供的多種網路功能提供接口。它包括NetBIOS、Winsock、NetDDE及遠程過程調用（RPC）等。

### Web相關API

Internet Explorer網頁瀏覽器還公開了許多經常被應用程式調用的API，因此通常其也被視為是Windows API的一部分。IE從Windows 95 OSR2起就包含在了Windows系統中，並從Windows 98起開始為應用程式提供Web相關服務。具體來說，它提供：

- 可嵌入的網頁瀏覽器控制項（以及 Trident / MSHTML 引擎），位於shdocvw.dll和mshtml.dll之中。
- urlmon.dll中的命名服務（URL moniters service），利用COM對象為應用程式提供解析URL服務。應用程式也可以為其他程序提供自己的URL處理程序。
- WinInet IE的網路層，支持HTTP和HTTPS等協議。
- 一個支持多種語言文本的連結庫（mlang.dll）。
- DirectX Transforms，一組圖像過濾組件。
- XML支持（MSXML組件）。

和Windows的郵件功能相關的API，例如地址本和郵件API，在Windows 7取消郵件功能之後也隨之從Windows API中去除。由於Windows Mail在Windows Vista上取代了Outlook Express，對應的API也隨之變化。

### 多媒體相關API

經典的Windows多媒體API位於winmm.dll中，包含了播放音訊、MIDI通訊、遊戲手柄及其他促進多媒體體驗的功能。該API源自Windows 3.x。

自從Windows 95 OSR2以來，Microsoft把DirectX API作為Windows安裝的一部分。DirectX提供一組鬆散相關的多媒體和遊戲服務，包括：

- Direct3D可以作為OpenGL的替代，來訪問3D加速硬體。
- DirectDraw提供硬體加速2D framebuffer（幀緩衝）訪問接口。自DirectX 9以來，相比Direct3D更傾向於後者，因為Direct3D提供更全面的高性能圖形功能（畢竟2D渲染只是3D渲染的（不嚴格）子集）。已被Direct2D替代。
- DirectSound提供底層次的硬體加速音效卡訪問。被XAudio替代。
- DirectInput用來與輸入設備（搖桿和gamepad）進行通信。已被DirectX 9中引入的XInput所替代。
- DirectPlay提供一個多人遊戲的架構（multiplayer gaming infrastructure）。它已經被DirectX 9所替代，Microsoft不建議用它開發遊戲。
- DirectShow可以創建和運行通用的多媒體管道（generic multimedia pipelines）。它可以與GStreamer框架相媲美，並且經常被用來渲染遊戲影片和創建媒體播放器（Windows Media Player及諸如FFDShow之類的編解碼器正是基於此；但在Windows Vista及更高版本中，DirectShow被Media Foundation替代）。不建議用DirectShow開發遊戲。
- DirectMusic提供類似MIDI的功能。與DirectSound一起被XAudio替代。

Microsoft還提供了多個用於媒體編碼和播放的API：

- DirectShow，用於構建和運行通用的媒體管道。它類似於GStreamer框架，常用於渲染遊戲內的影片和構建媒體播放器（著名的Windows Media Player即基於它）。如今DirectShow已不再被推薦用於開發。
- Media Foundation，一種較新的數字媒體API，旨在取代DirectShow。

### 程序通信API

Windows API最重要功能即為此：處理作業系統和應用程式之間的交互。對於不同的Windows應用程式之間的通信，Microsoft發展了一系列的技術並開發了最主要的Windows API。這些技術從動態數據交換（DDE）開始，隨後被對象連結和嵌入（OLE）取代，再被組件對象模型（COM）、自動化對象、ActiveX控制項和.NET框架取代。不過，這些技術之間區別並不總是十分明顯，並且有很多重疊之處。

這些技術的多樣性基本上是對軟體開發的不同方面進行細分的結果。自動化特別涉及了導出應用程式和組件的功能為API，以便使其可以由其他應用程式而不是人類來進行控制。.NET是一種自包含的通用方法和技術，用於開發各種使用即時編譯語言編寫的桌面和Web應用程式。

Windows.pas是一個Pascal/Delphi單元，其中包含了Windows特定的API聲明。它在Pascal中的作用就像C中的windows.h一樣。

### 封裝庫

微軟利用許多更底層的Windows API函數，開發出許多封裝庫（wrapper），讓應用程式以更抽象的方式與Windows API進行交互。MFC（Microsoft Foundation Class Library）用C++ 類來封裝Windows API的功能，因而允許用更為物件導向的方式與API進行交互。ATL（Active Template Library）是對COM的面向模板（template oriented）的封裝。WTL（Windows Template Library）作為ATL的增強，被用來作為MFC的輕型的替代物。

其他著名的封裝庫是Borland公司的產品，為了與MFC競爭而推出的OWL（Object Windows Library）提供了類似的物件導向封裝。不久Borland又推出VCL（Visual Component Library）來取而代之。

大多數的Windows 程序框架（application framework）是對Windows API的封裝，因而.NET Framework、Java以及其他在Windows下的程序語言，都是（或者包含）封裝庫。

## 歷史

Windows API總會為程式設計師提供大量的構建不同 Windows的底層結構，這有助於為 Windows 程式設計師開發應用程序提供大量的靈活性和功能。但是，它同樣使Windows應用程式要負責處理大量底層且有時是繁瑣的與圖形使用者界面（GUI）相關的操作。

例如，初學C的程式設計師通常會把編寫簡單的「Hello world」作為他們的第一項任務。程序的工作部分僅僅是主程序中的一個printf行，在連結到標準I/O庫時也僅需要一個include行：

```c
#include <stdio.h>

int main(void) {
    printf("Hello, World!\n");
}
```

Windows版本的工作部分仍然只有一行代碼，但除此之外它需要很多很多行的額外開銷。

許多有關Windows API的暢銷書的作者查爾斯·佩佐德（Charles Petzold）曾經說過：

Windows 1.0 SDK中的最初的Hello world程式或多或少沾了些醜聞。HELLO.C大約有150行，而HELLO.RC資源腳本還多加了大約20多行……在接觸到Windows 的Hello world程式時，資深的C程式員通常會驚恐或大笑起來。

這些年來，Windows作業系統已經今非昔比，而Windows API也隨之改變和成長並反映出這種變化。Windows API的Windows 1.0版本只提供不到450個函數調用（Subroutine），而現在的版本提供上千個。然而，整體而言，Windows接口保持了相當好的一致性，習慣於現在版本Windows API的程式設計師對古老的Windows 1.0程序也並不會陌生。

微軟特別強調維持軟體的向後兼容性。為了實現此一目標，有時微軟甚至不惜支持使用了非官方乃至（編程上）非法的API的軟體。一位致力於Windows API的Windows開發者雷蒙德·陳（Raymond Chen）曾提及：

僅僅是關於應用程式所做出的壞事以及我們讓應用程式重新運作所必須（通常是在不由自主的情況下）採用的方法，我可能會寫上幾個月。這就是在人們指責微軟在作業系統升級期間惡意破壞應用程式時，我會特別憤怒的原因。如果有任何無法在Windows95上運行的應用程式，我會將這些應用程式視為個人故障。

對Windows API來說，其歷史上最大的變化之一就是從Win16（在Windows 3.1及更早的版本中提供）到Win32（Windows NT和Windows 95及更高版本）的過渡。雖然Win32早已在Windows NT 3.1中引入，並在Windows 95前就已允許使用，但直到Windows 95應用程式才開始廣泛移植到Win32。為了簡化轉換的過程，在Windows 95中對Microsoft內外的開發人員Windows使用了一種複雜的API thunk方案來允許32位代碼調用到16位代碼（對大多數Win16 API有效），反之亦然。同樣的，64位的Windows也可以通過WoW64運行32位的應用程式，而位於Windows目錄下的SysWOW64文件夾中包含了多個用於支持32位應用程式的工具。

## 版本

幾乎每個版本的Windows都引入了其對Windows API的添加和修改，但是API的名稱在不同版本的Windows間保持了一致，並且僅當Windows主要的架構和平台都更改時API的名稱才會改變。Microsoft最終將當時名叫Win32的API家族改名為Windows API，並使其成為過去和未來API版本的統稱。

- Win16是第一個16位版本Windows的API。它最早被簡單地叫做Windows API，但後來為了與較新的32位API區分，它被重新命名為了Win16。Win16 API的功能主要駐留在作業系統的核心文件中，如kernel.exe（或krnl286.exe、krnl386.exe）、user.exe和gdi.exe。值得一提的是，儘管這些文件採用了exe的擴展名，它們本質上其實是動態連結庫。
- Win32是Windows 95及後續版本的32位API。與Win16相同，這個API由在系統DLL中實現的函數組成。Win32的核心文件是kernel32.dll、user32.dll和gdi32.dll。Win32最早在Windows NT中引入，而不是Windows 95。Windows 95中的Win32最早被稱為Win32c，其中的「c」表示兼容性（英語：compatibility）；這個名稱後來被微軟捨棄，轉而使用Win32。
- Win32s是Windows 3.1x系列的擴展，它為這些系統實現了Win32 API的一部分功能。其中的「s」表示子集（英語：subset）。
- Win64是64位Windows上的Windows API變體。此時應用程式的32位和64位版本可以從同一個代碼庫進行編譯。在默認情況下，所有記憶體指針都是64位的（LLP64型），因此部分程序的原始碼必須被重寫以兼容64位指針演算法。
- WinCE是Windows CE作業系統中的Windows API。

## 其它實現

儘管微軟的Windows API實現有版權保護，但被普遍認可的是，根據美國的法律先例，其他廠商仍然可以通過提供一致的API來模擬Windows，而不會侵犯版權。

Wine項目為類Unix平台提供了一個在Linux內核API與Windows API程序之間的Win32 API兼容層。ReactOS則更進一步，想要實現一個完整的Windows作業系統；它通過與Wine項目的密切合作來促進其代碼的重用和兼容。DosWin32和HX DOS-Extender是另外兩個模擬Windows API的項目，它們允許通過DOS命令行來運行簡單的Windows程序。Odin是一個在OS/2平台上模擬Win32的項目。

## 編譯器支持

為了開發使用Windows API的軟體，編譯器必須能處理和導入微軟相關的DLLs或者COM對象。編譯器必須接受一種C或C++方言，或者能夠處理揭示了內部API函數名稱的接口定義語言（Interface description language）文件和頭文件及生成的類型庫（Type Library）。概括而言，這些預備條件（編譯器、開發工具、庫和頭文件）被統稱為Microsoft Platform SDK。很長時間以來，包含了編譯器和開發工具的專利產品如Microsoft Visual Studio系列和Borland編譯器（儘管至少在Windows下，SDK是可以從整個IDE環境中剝離出來單獨免費下載的，據 Microsoft Platform SDK Update），是僅有的能提供整套開發環境的選擇。如今MinGW和Cygwin也能提供一套這樣的開發環境——是基於採用一種獨立頭文件集合來保證能與微軟DLL連接的GCC。LCC-Win32是由Jacob Navia維護的一種「非商業用途免費」的C編譯器。Pellesc是由Pelle Orinius維護的一種免費C編譯器。MASM32是一個成熟的項目，它通過自製或由SDK平台轉換的頭文件和庫，並利用32位微軟彙編器來實現支持Windows API。

微軟相關的編譯器支持也是異常處理（Structured Exception Handling）特性所需要的。這個體制有雙重目的：它提供了語言相關的異常處理賴以實現的基礎，同時也是內核藉以通知程序發生諸如解除一個非法指針的引用或堆棧溢出之類異常狀況的渠道。甫一被引入Windows 95和NT，微軟／Borland C++編譯器就有使用這種體制的能力，然而實際實現未被公開，而且必須經過反向工程方可用於Wine項目和免費編譯器。SEH的運行機制是先把異常的句柄推入堆棧，繼而將它們添加到存儲於線程本地資源（即線程環境塊的首欄位）的一個鍊表里。事實上，每一個未有程序本身處理的異常，都將由會彈出常規Windows崩潰對話框的默認backstop處理器處理。

API在Visual Basic中的實現示例（這個簡化的例子使得使用者可以讓命令按鈕在窗體上四處移動）：

```vb
  Private Const WM_NCLBUTTONDOWN As Long = &HA1&
  Private Const HTCAPTION As Long = 2&
  Private Declare Function ReleaseCapture Lib "user32" () As Long
  Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd&, ByVal wMsg&, wParam As Any, lParam As Any) As Long

  If Command1.MousePointer = 14 Then
    Call ReleaseCapture
    Call SendMessage(Command1.hWnd, WM_NCLBUTTONDOWN, ByVal HTCAPTION, ByVal 0&)
  End If
```

## 參考資料

- Diomidis Spinellis。A critique of the Windows application programming interface . Computer Standards & Interfaces, 20(1):1–8, November 1998. doi:10.1016/S0920-5489(98)00012-9。

## 外部連結

- Microsoft Developer Network Windows API development guide
- The Old New Thing Weblog by Microsoft developer Raymond Chen，who works on the Windows API and posts extensively about it.
- Localization in Win32
- pinvoke.net: the interop wiki! PINVOKE.NET attempts to address the difficulty of calling Win32 or other unmanaged APIs in managed code (languages such as C# and VB .NET).
- Windows API Notes
- WinapiZone Free tutorials and extensions for Winapi
- Stromcode's Win32/C++ tutorial (formerly Glowdot) an extensive, 20-part tutorial.
- Catch22 Tutorials Well documented Win32 API tutorials for developing small, nifty, and efficient programs in Windows.
- theForger's Win32 API Tutorial
- Using Win32 API in Visual FoxPro online reference