Windows API

Windows API

Windows 這個多作業系統除了協調應用程式的執行、分配記憶體、管理資源之外, 它同時也是一個很大的服務中心,調用這個服務中心的各種服務(每一種服務就是一個函式),可以幫套用程式達到開啟視窗、描繪圖形、使用周邊設備等目的,由於這些函式服務的對象是應用程式(Application), 所以便稱之為 Application Programming Interface,簡稱 API 函式。WIN32 API也就是Microsoft Windows 32位平台的應用程式編程接口

基本介紹

  • 中文名:Windows API
  • 外文名:Windows Application Programming Interface
  • 別稱Windows應用程式接口
  • 性質:系統編程接口
  • 分類:用戶界面服務;圖形多媒體服務
簡介,基本信息,函式分類,發展現狀,概要介紹,表達方式,API舉例,分類,

簡介

基本信息

Windows API 就是Windows應用程式接口,是針對Microsoft Windows作業系統家族的系統編程接口,這樣的系統包括Windows 8.1、Windows 8、Windows 7、Windows Vista、Windows XP、Windows Server 2012、Windows 2008 R2 、Windows Server 2003、Windows 2000、Windows 95、Windows 98、Windows Me(Millennium Editon)和Windows CE等幾乎所有版本。
其中32位Windows作業系統的編程接口稱為 Win32 API,以便與以前16位版本Windows編程接口(16位Windows API)區別開來。

函式分類

Windows API包括幾千個可調用的函式,它們大致可以分為以下幾個大類:
基本服務;
用戶界面服務;
圖形多媒體服務;
訊息和協作;
網路;
Web服務。

發展現狀

Windows作業系統開始占據主導地位的時候,開發Windows平台下的應用程式成為人們的需要。而在Windows程式設計領域處於發展的初期,Windows程式設計師所能使用的編程工具唯有API函式,這些函式是Windows提供給應用程式與作業系統的接口,他們猶如“積木塊”一樣,可以搭建出各種界面豐富,功能靈活的應用程式。所以可以認為API函式是構築整個Windows框架的基石,在它的下面是Windows的作業系統核心,而它的上面則是所有的華麗的Windows應用程式。
程式設計師想編寫具有Windows風格的軟體,必須藉助API,API也因此被賦予至高無上的地位。但是,如若沒有合適的Windows編程平台,那么Windows開發是一項很複雜的工作。在可視化編程IDE出來之前,那時的Windows程式開發還是比較複雜的工作,程式設計師必須熟記一大堆常用的API函式,而且還得對Windows作業系統有深入的了解。然而隨著軟體技術的不斷發展,在Windows平台上出現了很多優秀的可視化編程環境,程式設計師可以採用“所見即所得”的編程方式來開發具有精美用戶界面和功能強大的應用程式。
這些優秀可視化編程環境操作簡單、界面友好(諸如VB、VC++、DELPHI等),在這些工具中提供了大量的類庫和各種控制項,它們替代了API的神秘功能,事實上這些類庫和控制項都是構架在WIN32 API函式基礎之上的,是封裝了的API函式的集合。它們把常用的API函式的組合在一起成為一個控制項或類庫,並賦予其方便的使用方法,所以極大的加速了Windows應用程式開發的過程。有了這些控制項和類庫,程式設計師便可以把主要精力放在程式整體功能的設計上,而不必過於關注技術細節。
實際上如果我們要開發出更靈活、更實用、更具效率的應用程式,必然要涉及到直接使用API函式,雖然類庫和控制項使應用程式的開發簡單的多,但它們只提供Windows的一般功能,對於比較複雜和特殊的功能來說,使用類庫和控制項是非常難以實現的,這時就需要採用API函式來實現。
這也是API函式使用的場合,所以我們對待API函式不必刻意去研究每一個函式的用法,那也是不現實的(能用得到的API函式有幾千個呢)。正如某位大蝦所說:API不要去學,在需要的時候去查API幫助就足夠了。但是,許多API函式令人難以理解,易於誤用,還會導致出錯,這一切都阻礙了它的推廣。

概要介紹

應用程式接口為:“‘計算機作業系統(Operating system)’或‘程式庫’提供給應用程式調用使用的代碼”。其主要目的是讓應用程式開發人員得以調用一組例程功能,而無須考慮其底層的原始碼為何、或理解其內部工作機制的細節。API本身是抽象的,它僅定義了一個接口,而不涉入應用程式如何實現的細節。
例如,圖形庫中的一組API定義了繪製指針的方式,可於螢幕上顯示指針。當應用程式需要指針功能時,可引用、編譯時連結到這組API,而運行時就會調用此API的實現(庫)來顯示指針。
應用程式接口是一組數量上千、極其複雜的函式和副程式,可讓程式設計師做很多任務作,譬如“讀取檔案”、“顯示選單”、“在視窗中顯示網頁”等等。作業系統的API可用來分配存儲器或讀取檔案。許多系統應用程式藉由API接口來實現,像是圖形系統、資料庫、網路Web服務,甚至是線上遊戲。
應用程式接口有諸多不同設計。用於快速執行的接口通常包括函式、常量、變數與數據結構。也有其它方式,如通過解釋器,或是提供抽象層以遮蔽同API實現相關的信息,確保使用API的代碼無需更改而適應實現變化。
應用程式接口經常是軟體開發工具包(SDK)的一部分。

表達方式

[Public|Private] Declare Function|Sub name Lib "libname" [Alias "aliasname"]([[Byval] variable [As type][,[Byval] variable [As type]]...]) [As type]
C #
[DllImport("libname",'Named Parameters')][public|private|internal] [Type] FunctionName(Type parameter1,Type parameter2...);

API舉例

C#中調用Windows API:
一、調用格式
using System.Runtime.InteropServices; //引用此名稱空間,簡化後面的代碼
...
//使用DllImportAttribute特性來引入api函式,注意聲明的是空方法,即方法體為空。
[DllImport("user32.dll")]
public static extern ReturnType FunctionName(type
arg1,type arg2,...);
//調用時與調用其他方法並無區別
可以使用欄位進一步說明特性,用逗號隔開,如:
[ DllImport( "kernel32",EntryPoint="GetVersionEx" )]
DllImportAttribute特性的公共欄位如下:
1、CallingConvention 指示向非託管實現傳遞方法參數時所用的 CallingConvention
值。
CallingConvention.Cdecl : 調用方清理堆疊。它使您能夠調用具有 varargs 的函式。
CallingConvention.StdCall :
被調用方清理堆疊。它是從託管代碼調用非託管函式的默認約定。
2、CharSet 控制調用函式的名稱版本及指示如何向方法封送 String 參數。
此欄位被設定為 CharSet 值之一。如果 CharSet 欄位設定為
Unicode,則所有字元串參數在傳遞到非託管實現之前都轉換成 Unicode 字元。這還導致向 DLL
EntryPoint 的名稱中追加字母“W”。如果此欄位設定為 Ansi,則字元串將轉換成 ANSI
字元串,同時向 DLL EntryPoint 的名稱中追加字母“A”。大多數 Win32 API
使用這種追加“W”或“A”的約定。如果 CharSet 設定為 Auto,則這種轉換就是與平台有關的(在
Windows NT 上為 Unicode,在 Windows 98 上為 Ansi)。CharSet
的默認值為 Ansi。CharSet 欄位也用於確定將從指定的 DLL
導入哪個版本的函式。CharSet.Ansi 和 CharSet.Unicode 的名稱匹配規則大不相同。對於
Ansi 來說,如果將 EntryPoint
設定為“MyMethod”且它存在的話,則返回“MyMethod”。如果 DLL
中沒有“MyMethod”,但存在“MyMethodA”,則返回“MyMethodA”。對於 Unicode
來說則正好相反。如果將 EntryPoint
設定為“MyMethod”且它存在的話,則返回“MyMethodW”。如果 DLL
中不存在“MyMethodW”,但存在“MyMethod”,則返回“MyMethod”。如果使用的是
Auto,則匹配規則與平台有關(在 Windows NT 上為 Unicode,在 Windows 98 上為
Ansi)。如果 ExactSpelling 設定為 true,則只有當 DLL
中存在“MyMethod”時才返回“MyMethod”。
3、EntryPoint 指示要調用的 DLL 入口點的名稱或序號。
如果你的方法名不想與api函式同名的話,一定要指定此參數,例如:
[DllImport("user32.dll",CharSet="CharSet.Auto",EntryPoint="MessageBox")]
public static extern int MsgBox(IntPtr hWnd,string
txt,string caption,int type);
4、ExactSpelling 指示是否應修改非託管 DLL 中的入口點的名稱,以與 CharSet
欄位中指定的 CharSet 值相對應。如果為 true,則當
DllImportAttribute.CharSet 欄位設定為 CharSet 的 Ansi
值時,向方法名稱中追加字母 A,當 DllImportAttribute.CharSet 欄位設定為
CharSet 的 Unicode 值時,向方法的名稱中追加字母 W。此欄位的默認值是 false。
5、PreserveSig 指示託管方法簽名不應轉換成返回 HRESULT、並且可能有一個對應於返回值的附加
[out,retval] 參數的非託管簽名。
6、SetLastError 指示被調用方在從屬性化方法返回之前將調用 Win32 API
SetLastError。true 指示調用方將調用 SetLastError,默認為
false。運行時封送拆收器將調用 GetLastError 並快取返回的值,以防其被其他 API
調用重寫。用戶可通過調用 GetLastWin32Error 來檢索錯誤代碼
二、參數類型:
1、數值型直接用對應的就可。(DWORD -> int,WORD -> Int16)
2、API中字元串指針類型 -> .net中string
3、API中句柄 (dWord) -> .net中IntPtr
4、API中結構 -> .net中結構或者類。注意這種情況下,要先用StructLayout特性限定聲明結構或類
公共語言運行庫利用StructLayoutAttribute控制類或結構的數據欄位在託管記憶體中的物理布局,即類或結構需要按某種方式排列。如果要將類傳遞給需要指定布局的非託管代碼,則顯式控制類布局是重要的。它的構造函式中用LayoutKind值初始化
StructLayoutAttribute 類的新實例。LayoutKind.Sequential
用於強制將成員按其出現的順序進行順序布局。
LayoutKind.Explicit 用於控制每個數據成員的精確位置。利用 Explicit,
每個成員必須使用 FieldOffsetAttribute 指示此欄位在類型中的位置。如:
[StructLayout(LayoutKind.Explicit,Size=16,
CharSet=CharSet.Ansi)]
public class MySystemTime
{
[FieldOffset(0)]public ushort wYear;
[FieldOffset⑵]public ushort wMonth;
[FieldOffset⑷]public ushort wDayOfWeek;
[FieldOffset⑹]public ushort wDay;
[FieldOffset⑻]public ushort wHour;
[FieldOffset⑽]public ushort wMinute;
[FieldOffset⑿]public ushort wSecond;
[FieldOffset⒁]public ushort wMilliseconds;
}
下面是針對API中OSVERSIONINFO結構,在.net中定義對應類或結構的例子:
/**********************************************
* API中定義原結構聲明
* OSVERSIONINFOA STRUCT
* dwOSVersionInfoSize DWORD
* dwMajorVersion DWORD
* dwMinorVersion DWORD
* dwBuildNumber DWORD
* dwPlatformId DWORD
* szCSDVersion BYTE 128 dup (?)
* OSVERSIONINFOA ENDS
*
* OSVERSIONINFO equ <OSVERSIONINFOA>
*********************************************/
//.net中聲明為類
[ StructLayout( LayoutKind.Sequential )]
public class OSVersionInfo
{
public int OSVersionInfoSize;
public int majorVersion;
public int minorVersion;
public int buildNumber;
public int platformId;
[ MarshalAs( UnmanagedType.ByValTStr,SizeConst=128 )]
public String versionString;
}
//或者
//.net中聲明為結構
[ StructLayout( LayoutKind.Sequential )]
public struct OSVersionInfo2
{
public int OSVersionInfoSize;
public int majorVersion;
public int minorVersion;
public int buildNumber;
public int platformId;
[ MarshalAs( UnmanagedType.ByValTStr,SizeConst=128 )]
public String versionString;
}
此例中用到MarshalAs特性,它用於描述欄位、方法或參數的封送處理格式。用它作為參數前綴並指定目標需要的數據類型。例如,以下代碼將兩個參數作為數據類型長指針封送給
Windows API 函式的字元串 (LPStr):
[MarshalAs(UnmanagedType.LPStr)]
String existingfile;
[MarshalAs(UnmanagedType.LPStr)]
String newfile;
注意結構作為參數時候,一般前面要加上ref修飾符,否則會出現錯誤:對象的引用沒有指定對象的實例。
[ DllImport( "kernel32",EntryPoint="GetVersionEx" )]
public static extern bool GetVersionEx2( ref
OSVersionInfo2 osvi );
三、如何保證使用託管對象的平台調用成功?
如果在調用平台 invoke
後的任何位置都未引用託管對象,則垃圾回收器可能將完成該託管對象。這將釋放資源並使句柄無效,從而導致平台invoke
調用失敗。用 HandleRef 包裝句柄可保證在平台 invoke 調用完成前,不對託管對象進行垃圾回收。
例如下面:
FileStream fs = new FileStream( "a.txt",FileMode.Open
);
StringBuilder buffer = new StringBuilder( 5 );
int read = 0;
ReadFile(fs.Handle,buffer,5,out read,0 ); //調用Win
API中的ReadFile函式
由於fs是託管對象,所以有可能在平台調用還未完成時候被垃圾資源回收筒回收。將檔案流的句柄用HandleRef包裝後,就能避免被垃圾站回收:
[ DllImport( "Kernel32.dll" )]
public static extern bool ReadFile(
HandleRef hndRef,
StringBuilder buffer,
int numberOfBytesToRead,
out int numberOfBytesRead,
ref Overlapped flag );
......
......
FileStream fs = new FileStream( "HandleRef.txt",
FileMode.Open );
HandleRef hr = new HandleRef( fs,fs.Handle );
StringBuilder buffer = new StringBuilder( 5 );
int read = 0;
// platform invoke will hold reference to HandleRef
until call ends
ReadFile( hr,buffer,5,out read,0 );

分類

Windows API所提供的功能可以歸為七類:
1.基礎服務(Base Services),提供對Windows系統可用的基礎資源的訪問接口。比如像:檔案系統(file system)、外部設備(device)、進程(process)、執行緒(thread)以及訪問註冊表(Windows registry)和錯誤處理機制(error handling)。這些功能接口位於 16位Windows下的kernel.exe、krnl286.exe或krnl386.exe系統文檔中,以及32位Windows下的 kernel32.dll和advapi32.dll中。
2.圖形設備接口(GDI),提供功能為:輸出圖形內容到顯示器、印表機以及其他外部輸出設備。它位於16位Windows下的gdi.exe;以及32位Windows下的gdi32.dll。
3.圖形化用戶界面(GUI),提供的功能有創建和管理螢幕和大多數基本控制項(control),比如按鈕滾動條。接收滑鼠和鍵盤輸入,以及其他與GUI有關的功能。這些調用接口位於:16位Windows下的user.exe,以及32位Windows下的user32.dll。從Windows XP版本之後,基本控制項和通用對話框控制項(Common Control Library)的調用接口放在comctl32.dll中。
4.通用對話框程式庫(Common Dialog Box Library),為應用程式提供標準對話框,比如打開/保存文檔對話框、顏色對話框和字型對話框等等。這個程式庫位於:16位Windows下的commdlg.dll中,以及32位Windows下comdlg32.dll中。它被歸類為User Interface API之下。
5.通用控制項程式庫(Common Control Library),為應用程式提供接口來訪問作業系統提供的一些高級控制項。比如像:狀態欄(status bar)、進度條(progress bars)、工具列(toolbar)和標籤(tab)。這個程式庫位於:16位Windows下的commctrl.dll中,以及32位Windows下comctl32.dll中。。它被歸類為User Interface API之下。
6.Windows外殼(Windows Shell),作為Windows API的組成部分,不僅允許應用程式訪問Windows外殼提供的功能,還對之有所改進和增強。它位於16位Windows下的shell.dll中,以及32位Windows下的shell32.dll中(Windows 95則在 shlwapi.dll中)。 它被歸類為User Interface API之下。
7.網路服務(Network Services),為訪問作業系統提供的多種網路 功能提供接口。它包括NetBIOSWinsock、NetDDE及RPC等。

相關詞條

熱門詞條

聯絡我們