| C/C++ | C# | 備註 |
| int / long | int / long | 32/64 位元 |
| DWORD / UINT | uint | 無號整數 |
| HWND / HANDLE | IntPtr | 平台相關指標大小 |
| LPCTSTR | string / StringBuilder | 字串參數 |
| BOOL | bool / int | Windows BOOL 為 4 bytes |
| struct * | ref struct / out struct | 傳址 |
範例 1:MessageBox 簡易呼叫
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class ApiDemo
{
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int MessageBox(IntPtr hWnd, string text, string caption, uint type);
public static void Main()
{
MessageBox(IntPtr.Zero, "API 呼叫成功", "P/Invoke Demo", 0); // MB_OK
}
}
範例 2:GetSystemInfo 結構封送
using System;
using System.Runtime.InteropServices;
public class SystemInfoDemo
{
// 1. 定義結構,指定 Sequential 配置
[StructLayout(LayoutKind.Sequential)]
public struct SYSTEM_INFO
{
public ushort wProcessorArchitecture;
public ushort wReserved;
public uint dwPageSize;
public IntPtr lpMinimumApplicationAddress;
public IntPtr lpMaximumApplicationAddress;
public IntPtr dwActiveProcessorMask;
public uint dwNumberOfProcessors;
public uint dwProcessorType;
public uint dwAllocationGranularity;
public ushort wProcessorLevel;
public ushort wProcessorRevision;
}
// 2. 宣告 API
[DllImport("kernel32.dll", SetLastError = true)]
public static extern void GetSystemInfo(ref SYSTEM_INFO lpSystemInfo);
public static void Main()
{
SYSTEM_INFO info = new SYSTEM_INFO();
GetSystemInfo(ref info);
Console.WriteLine($"處理器架構: {info.wProcessorArchitecture}");
Console.WriteLine($"頁面大小: {info.dwPageSize} bytes");
Console.WriteLine($"處理器核心數: {info.dwNumberOfProcessors}");
Console.WriteLine($"處理器類型: {info.dwProcessorType}");
Console.WriteLine($"配置粒度: {info.dwAllocationGranularity} bytes");
}
}
進階主題
字串緩衝區:StringBuilder
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern uint GetWindowsDirectory(StringBuilder lpBuffer, uint uSize);
// 呼叫
var sb = new StringBuilder(260);
GetWindowsDirectory(sb, (uint)sb.Capacity);
Console.WriteLine(sb.ToString());
回呼函數
public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll")]
public static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
// 使用
EnumWindows((hWnd, lParam) => {
var sb = new StringBuilder(256);
GetWindowText(hWnd, sb, sb.Capacity);
Console.WriteLine($"0x{hWnd.ToInt64():X}: {sb}");
return true; // 繼續列舉
}, IntPtr.Zero);
安全與非安全代碼
- 預設 P/Invoke 為非安全,需
unsafe 區塊或 AllowUnsafeBlocks 編譯選項。
- 傳遞指標時使用
void* 或 byte*,搭配 fixed 陳述式固定記憶體位置。
最佳實務清單
- 優先使用 .NET Framework 內建類別(
Environment、Process、ManagementObjectSearcher),避免直接呼叫 API。
- 使用
SetLastError = true 搭配 Marshal.GetLastWin32Error() 取得錯誤碼。
- 結構務必標註
[StructLayout(LayoutKind.Sequential)] 或 Explicit。
- 字串參數加
CharSet = CharSet.Auto 確保 Unicode/ANSI 正確。
- 處理
IntPtr 時注意 32/64 位元相容性。
- 上一篇文章: C# 開發 COM+ 元件完整指南:強名稱、註冊與部署實戰
- 下一篇文章: C# 進階筆記:委派、事件與 XML 文件註解完整指南
Copyright ©
程式碼之家 All Rights Reserved