.NET Framework 雖提供大量托管類別庫,但 Win32 API 龐大且涵蓋底層系統功能,框架團隊無法為所有 API 提供托管包裝。當需要使用未封裝的 Windows 原生功能(如特定裝置控制、系統級設定)時,平台呼叫 P/Invoke 是最常用的橋接方案。
static extern 宣告,參數型別需對應 Win32 型別(如 DWORD → int/uint,BOOL → bool)。kernel32.dll、user32.dll)。[DllImport("kernel32.dll")]
public static extern bool Beep(int frequency, int duration);
// 呼叫
Beep(1000, 500);
將 Win32 常數定義為 enum,提升可讀性與型別安全:
public enum BeepType : uint
{
SimpleBeep = 0xFFFFFFFF,
IconAsterisk = 0x00000040,
IconExclamation = 0x00000030,
IconHand = 0x00000010,
IconQuestion = 0x00000020,
Ok = 0x00000000,
}
[DllImport("user32.dll")]
public static extern bool MessageBeep(BeepType beepType);
對應 SYSTEM_POWER_STATUS 結構,使用 ref 傳遞指標,並將位元欄位定義為 enum:
[StructLayout(LayoutKind.Sequential)]
struct SystemPowerStatus
{
public ACLineStatus ACLineStatus;
public BatteryFlag BatteryFlag;
public byte BatteryLifePercent;
public byte Reserved1;
public int BatteryLifeTime;
public int BatteryFullLifeTime;
}
enum ACLineStatus : byte { Offline = 0, Online = 1, Unknown = 255 }
enum BatteryFlag : byte { High = 1, Low = 2, Critical = 4, Charging = 8, NoSystemBattery = 128, Unknown = 255 }
[DllImport("kernel32.dll")]
public static extern bool GetSystemPowerStatus(ref SystemPowerStatus status);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern int GetShortPathName(
[MarshalAs(UnmanagedType.LPTStr)] string path,
[MarshalAs(UnmanagedType.LPTStr)] StringBuilder shortPath,
int shortPathLength);
使用 StructLayout 指定 CharSet.Unicode,並以 MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32) 對應固定長度字元陣列。
以 delegate 替代函式指標,並注意委派生命週期:若非托管碼長期持有指標,必須在托管端保持委派參考防止 GC 回收。
| 屬性 | 用途 |
|---|---|
| CallingConvention | 指定呼叫慣例(預設 StdCall,C 函式需設 Cdecl) |
| ExactSpelling | 設 true 關閉 A/W 自動查找 |
| SetLastError | 啟用 GetLastError 取得錯誤碼 |
| StructLayout.Pack | 控制結構體對齊封裝大小 |
常見錯誤:long 大小不一(C++ 4 bytes vs C# 8 bytes)、字串封送型別錯誤、結構體大小不符。建議使用 Marshal.SizeOf() 驗證結構大小。