基本數值類型對應
| Win32 / C 類型 | C/C++ 關鍵字 | .NET 類型 (System) | 位元寬度 | 備註 |
| HANDLE / PVOID | void* | IntPtr / UIntPtr | 32/64 位元隨平台 | 句柄、指標通用 |
| BYTE | unsigned char | Byte | 8 | |
| SHORT | short | Int16 | 16 | |
| WORD / USHORT | unsigned short | UInt16 | 16 | |
| INT / LONG | int / long | Int32 | 32 | Windows 長整數為 32 位元 |
| UINT / ULONG / DWORD | unsigned int / unsigned long | UInt32 | 32 | |
| LONGLONG / INT64 | long long / __int64 | Int64 | 64 | |
| ULONGLONG / DWORDLONG | unsigned long long | UInt64 | 64 | |
| FLOAT | float | Single | 32 | IEEE 754 |
| DOUBLE | double | Double | 64 | IEEE 754 |
| BOOL | int / long (Win32) | Int32 / Boolean | 32 | Win32 BOOL 為 4 bytes;C++ bool 為 1 byte |
| CHAR | char | SByte / Byte | 8 | 有號/無號視語境 |
| WCHAR | wchar_t | Char | 16 | UTF-16 |
字串與陣列指標對應
| 非托管類型 | C/C++ 宣告 | .NET 封送類型 | CharSet / 屬性 |
| LPSTR | char* | string / StringBuilder | [MarshalAs(UnmanagedType.LPStr)] / CharSet.Ansi |
| LPCSTR | const char* | string / StringBuilder | [MarshalAs(UnmanagedType.LPStr)] / CharSet.Ansi |
| LPWSTR | wchar_t* | string / StringBuilder | [MarshalAs(UnmanagedType.LPWStr)] / CharSet.Unicode (預設) |
| LPCWSTR | const wchar_t* | string / StringBuilder | [MarshalAs(UnmanagedType.LPWStr)] / CharSet.Unicode |
| 固定長度陣列 | char name[32] | string / StringBuilder | [MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)] |
結構體封送關鍵屬性
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 4)]
public struct MY_STRUCT
{
public int Id;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string Path; // 固定長度字串
public IntPtr Handle; // 指標/句柄
public double Value;
// 陣列需指定大小
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public int[] Items;
}
LayoutKind.Sequential:依宣告順序配置,符合 C 結構體預設。
Pack:對齊邊界 (1, 2, 4, 8);需與 C 端 #pragma pack 一致。
CharSet:決定字串封送為 ANSI 或 Unicode,影響 string、Char 編碼。
常見陷阱與對策
| 陷阱 | 現象 | 解決 |
| 長整數寬度不一 | C++ long 在 64-bit Linux 為 8 bytes,Windows 為 4 bytes | Windows 端固定用 Int32;跨平台用 IntPtr 或明確 int32_t/int64_t |
| BOOL vs bool | Win32 BOOL 4 bytes,C++ bool 1 byte | P/Invoke 簽名用 int 或 Int32 對應 BOOL;byte 對應 bool |
| 字串編碼錯誤 | 中文亂碼 | 明確指定 CharSet = CharSet.Unicode 或 Ansi,勿依賴預設 |
| 結構體對齊 | 欄位位移錯誤導致讀寫錯誤 | 檢查 Pack、LayoutKind,使用 offsetof 驗證 |
| 記憶體釋放 | 非托管配置記憶體未釋放 | 約定由呼叫端釋放,或提供 Free 函數;.NET 端用 Marshal.FreeHGlobal/FreeCoTaskMem |
快速查詢速查表 (GitHub Gist 風格)
// 數值
HANDLE -> IntPtr
DWORD -> uint
LONG -> int
ULONGLONG -> ulong
FLOAT -> float
DOUBLE -> double
// 字串 (預設 Unicode)
LPCWSTR -> string
LPWSTR -> StringBuilder (輸出緩衝區)
LPCSTR -> string (CharSet.Ansi)
// 陣列/指標
int* -> int[] / ref int / IntPtr
BYTE* -> byte[] / IntPtr
// 結構體
struct FOO -> [StructLayout(LayoutKind.Sequential)] struct Foo { ... }
總結
正確的類型對應是 P/Invoke 穩定互通的基石。建議將上表做為團隊共享文件,並在程式碼審查時核對 StructLayout、MarshalAs、CharSet 與 Pack 設定,避免 90% 的封送錯誤。