首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# P/Invoke 非受控型別對應表:Win32 API 參數封送完整速查

     編輯:關於C#

呼叫 Windows API (P/Invoke) 時,正確對應非受控型別至 .NET 受控型別至關重要。錯誤對應會導致記憶體損毀、存取違規、資料截斷等難以除錯的問題。本文提供完整對應表,涵蓋基礎型別、指標/字串/結構體/陣列封送、呼叫慣例、32/64 位元差異,並附上常見 Win32 結構體對應範例。

基礎型別對應表

Win32 (C/C++)說明.NET (C#)大小備註
HANDLE, HWND, HMODULE, HINSTANCE, HDC, HKEY...32/64 位元指標/句柄IntPtr / nint (.NET 7+)4/8 bytes嚴禁用 `int`/`long`
BYTE, UCHAR無號 8 位元byte1
SHORT有號 16 位元short2
WORD, USHORT, ATOM無號 16 位元ushort2
INT, LONG, LONG32, BOOL有號 32 位元int4Win32 `BOOL` 為 4 bytes,非 `bool` (1 byte)
UINT, ULONG, DWORD, DWORD32無號 32 位元uint4
LONGLONG, LONG64, INT64有號 64 位元long8
ULONGLONG, DWORD64, UINT64, QWORD無號 64 位元ulong8
FLOATIEEE 754 單精度float4
DOUBLEIEEE 754 雙精度double8
CHARANSI 字元 (1 byte)byte 或 sbyte1字串用 `string` + `CharSet.Ansi`
WCHAR, TCHAR (Unicode 建置)Unicode 字元 (2 bytes)char2字串用 `string` + `CharSet.Unicode`

指標/字串/陣列封送

非受控宣告用途C# 簽章建議關鍵屬性
LPSTR / char*ANSI 輸入字串string[MarshalAs(UnmanagedType.LPStr)], `CharSet.Ansi`
LPCSTR / const char*ANSI 唯讀字串string同上 (預設 `In`)
LPWSTR / wchar_t*Unicode 輸出/輸入輸出字串StringBuilder[MarshalAs(UnmanagedType.LPWStr)], `CharSet.Unicode`
LPCWSTR / const wchar_t*Unicode 唯讀字串string同上
LPVOID / void*通用指標IntPtr / nint配合 `Marshal.StructureToPtr`/`PtrToStructure`
INT* / int[]整數陣列 (輸入)int[] / Span<int>[In] / [In, Out]
INT* / int[]整數陣列 (輸出)int[] (預先配置)[Out], `SizeParamIndex` 指定長度參數
struct MyStruct*結構體指標ref MyStruct / out MyStruct[In]/[Out], 結構體加 `[StructLayout(LayoutKind.Sequential)]`

常見 Win32 結構體對應範例

POINT

[StructLayout(LayoutKind.Sequential)]
public struct POINT { public int X; public int Y; }

RECT

[StructLayout(LayoutKind.Sequential)]
public struct RECT { public int Left, Top, Right, Bottom; }

WNDCLASSEX (含字串指標、函數指標、大小欄位)

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct WNDCLASSEX
{
    public uint cbSize;
    public uint style;
    public IntPtr lpfnWndProc;      // 函數指標 -> IntPtr
    public int cbClsExtra;
    public int cbWndExtra;
    public IntPtr hInstance;
    public IntPtr hIcon;
    public IntPtr hCursor;
    public IntPtr hbrBackground;
    [MarshalAs(UnmanagedType.LPTStr)] public string lpszMenuName;
    [MarshalAs(UnmanagedType.LPTStr)] public string lpszClassName;
    public IntPtr hIconSm;
}

呼叫慣例與 CharSet 設定

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = false)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

// CharSet.Auto: 依平台自動選 Ansi/Unicode (建議)
// CharSet.Ansi: 強制 ANSI (EntryPoint="FindWindowA")
// CharSet.Unicode: 強制 Unicode (EntryPoint="FindWindowW")
// SetLastError=true: 允許 Marshal.GetLastWin32Error() 取得錯誤碼
// ExactSpelling=false: 允許運行時依 CharSet 修飾函數名稱 (A/W 後綴)

32/64 位元可攜性核心原則

  1. 所有句柄/指標用 IntPtr / nint,絕不使用 `int`/`long`。
  2. 結構體大小欄位 (如 `cbSize`) 在建構函式中用 `Marshal.SizeOf()` 動態計算。
  3. 避免 `ToInt32()` / `ToInt64()` 硬編碼,使用 `IntPtr.Size` 判斷平台。
  4. 編譯目標:專案屬性 → Build → 取消勾選 "Prefer 32-bit",讓進程隨平台為 64 位元,或明確指定 x86/x64。

現代工具輔助

  • pinvoke.net:社群維護的簽章庫,可直接搜尋複製。
  • CsWin32 (Microsoft):Source Generator 從 Windows SDK 標頭自動產生 P/Invoke 簽章,支援 .NET 6+,強型別、無需手寫。
  • LibraryImport ( .NET 7+ ):編譯期產生包裝,效能優於 `DllImport`,支援 `StringMarshalling`、`ArrayMarshalling` 等屬性。

結語

P/Invoke 型別對應錯誤是導致「不可重現崩潰」的首要原因。請永遠使用 `IntPtr` 處理句柄/指標、明確指定 `CharSet` 與 `SetLastError`、結構體加上 `StructLayout.Sequential`、優先使用 CsWin32/LibraryImport 自動產生簽章。將此表加入團隊 Wiki,代碼審查時必查項目。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved