.NET Framework 類別庫未涵蓋所有 Win32 API (數萬個)。當需要:
即須使用 **Platform Invocation Services (P/Invoke)** 直接呼叫 Unmanaged DLL 匯出函式。
| Win32 | C# | 備註 |
|---|---|---|
| DWORD, ULONG, UINT | uint / int | 建議用 `uint` 表達無號,`int` 相容 CLS |
| BOOL | bool / int | `[MarshalAs(UnmanagedType.Bool)]` 為 4 bytes;`bool` 為 1 byte |
| HANDLE, HWND, HMODULE | IntPtr | 永遠用 `IntPtr`,不可用 `int`/`long` |
| LPSTR / LPCSTR | StringBuilder / string | ANSI 字串,`StringBuilder` 可修改 |
| LPWSTR / LPCWSTR | StringBuilder / string | Unicode 字串 (預設) |
| LPVOID / PVOID | IntPtr / void* | 泛型指標 |
| BYTE | byte | |
| WORD | ushort | |
| LONG, INT | int | |
| FLOAT, DOUBLE | float, double | |
| GUID | Guid | `[MarshalAs(UnmanagedType.LPStruct)]` |
| FILETIME | long / System.Runtime.InteropServices.ComTypes.FILETIME | 100-ns intervals since 1601 |
internal static class Kernel32 {
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool Beep(uint dwFreq, uint dwDuration);
}
// 使用
Kernel32.Beep(1000, 500); // 1kHz, 0.5秒
internal static class User32 {
public enum MessageBeepType : uint {
OK = 0x00000000,
IconHand = 0x00000010,
IconQuestion = 0x00000020,
IconExclamation = 0x00000030,
IconAsterisk = 0x00000040,
SimpleBeep = 0xFFFFFFFF // -1
}
[DllImport("user32.dll", SetLastError = true)]
public static extern bool MessageBeep(MessageBeepType uType);
}
User32.MessageBeep(User32.MessageBeepType.IconQuestion);
[StructLayout(LayoutKind.Sequential)]
internal struct SystemPowerStatus {
public byte ACLineStatus; // 0=離線, 1=線上, 255=未知
public byte BatteryFlag; // 1=高, 2=低, 4=關鍵, 8=充電中, 128=無電池
public byte BatteryLifePercent; // 0-100, 255=未知
public byte Reserved1;
public int BatteryLifeTime; // 秒, -1=未知
public int BatteryFullLifeTime; // 秒, -1=未知
}
internal static class Kernel32 {
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool GetSystemPowerStatus(ref SystemPowerStatus lpSystemPowerStatus);
}
// 使用
var status = new SystemPowerStatus();
if (Kernel32.GetSystemPowerStatus(ref status)) {
Console.WriteLine($"AC: {status.ACLineStatus}, Battery%: {status.BatteryLifePercent}, Life: {status.BatteryLifeTime}s");
}
// 進階:將欄位轉為列舉
enum ACLineStatus : byte { Offline = 0, Online = 1, Unknown = 255 }
enum BatteryFlag : byte { High = 1, Low = 2, Critical = 4, Charging = 8, NoBattery = 128, Unknown = 255 }
internal static class User32 {
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetWindowTextLength(IntPtr hWnd);
}
public static string GetWindowTitle(IntPtr hWnd) {
int len = User32.GetWindowTextLength(hWnd);
if (len == 0) return "";
var sb = new StringBuilder(len + 1);
User32.GetWindowText(hWnd, sb, sb.Capacity);
return sb.ToString();
}
關鍵:`CharSet.Auto` 讓運行時依平台自動選擇 `GetWindowTextA` (ANSI) 或 `GetWindowTextW` (Unicode),且自動處理 `string` ↔ `StringBuilder` 封送。
| 需求 | 屬性/寫法 |
|---|---|
| 固定長度字串緩衝區 | `[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string Path;` |
| 陣列內嵌結構 | `[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] SerialNumber;` |
| 自訂封送 | 實作 `ICustomMarshaler`,`[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshaler))]` |
| 委派回呼函式 | `delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);` + `GCHandle.Alloc(delegate)` 防止被 GC |
| 錯誤碼獲取 | `SetLastError = true` + `Marshal.GetLastWin32Error()` |