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

C# 呼叫 Windows API 完整指南:P/Invoke 核心要點與實戰技巧

     編輯:關於C語言

前言

.NET Framework SDK 關於平台呼叫的文件相對分散,且多以 VB.NET 為主。本文整理 C# 呼叫 Windows API 的關鍵知識,並提供實用範例。安裝 Visual Studio 後,可在 C:\Program Files\Microsoft Visual Studio .Net\FrameworkSDK\Samples\Technologies\Interop\PlatformInvoke\WinAPIs\CS 找到大量範例。

基本宣告格式

using System.Runtime.InteropServices;

[DllImport("user32.dll")]
public static extern 回傳型別 函數名稱(參數型別 參數名, ...);
  • 方法本體為空,由 CLR 在執行時導向非受控 DLL。
  • 需引用 System.Runtime.InteropServices 命名空間。

DllImportAttribute 關鍵屬性

屬性說明
CallingConvention 呼叫慣例。StdCall(預設,被呼叫者清理堆疊)適用大多數 Win32 API;Cdecl 用於可變參數函式(如 printf)。
CharSet 控制字串封送與函數名稱修飾。Ansi(預設)對應「A」尾綴;Unicode 對應「W」;Auto 依平台決定(NT 為 Unicode,9x 為 Ansi)。
EntryPoint 指定 DLL 實際匯出的函數名稱或序數。若 C# 方法名不同於 API 名,必須設定此屬性。
ExactSpelling true 時禁止依 CharSet 自動加尾綴;false(預設)允許自動修飾。
SetLastError true 時呼叫端會呼叫 SetLastError,C# 可透過 Marshal.GetLastWin32Error() 取得錯誤碼。

常見型別對應表

非受控型別C# 型別備註
數值型別 (int, long, DWORD 等)對應的 int, long, uint 等直接對應
字串指標 (LPSTR/LPWSTR)string 或 StringBuilder輸出緩衝區必須用 StringBuilder
控制代碼 (HANDLE, HWND)IntPtr平台相關大小
結構struct 或 class + [StructLayout(LayoutKind.Sequential)]欄位順序必須一致

結構封送範例

[StructLayout(LayoutKind.Sequential)]
public class OSVersionInfo
{
    public int OSVersionInfoSize;
    public int majorVersion;
    public int minorVersion;
    public int buildNumber;
    public int platformId;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
    public string versionString;
}

[DllImport("kernel32", EntryPoint = "GetVersionEx")]
public static extern bool GetVersionEx(ref OSVersionInfo osvi);

注意:結構作為參數時,通常需加 ref,否則會出現「物件參考未設定為物件實例」錯誤。

防止垃圾回收提前釋放控制代碼

若受控物件在平台呼叫完成前被 GC 回收,代碼會失效。使用 HandleRef 包裝可延長存活期:

[DllImport("Kernel32.dll")]
public static extern bool ReadFile(
    HandleRef hndRef,
    StringBuilder buffer,
    int numberOfBytesToRead,
    out int numberOfBytesRead,
    ref Overlapped flag
);

// 使用方式
FileStream fs = new FileStream("HandleRef.txt", FileMode.Open);
HandleRef hr = new HandleRef(fs, fs.Handle);
StringBuilder buffer = new StringBuilder(5);
int read = 0;
ReadFile(hr, buffer, 5, out read, 0); // 平台呼叫期間 hr 會保持參考

實用建議

  1. 優先使用 IntPtr 處理指標與控制代碼。
  2. 字串輸出緩衝區一定要用 StringBuilder 並預留足夠容量。
  3. 結構務必加 [StructLayout(LayoutKind.Sequential)],必要時用 [MarshalAs] 精確控制欄位封送。
  4. 長時間持有的非受控資源,實作 IDisposable 並搭配 SafeHandle 衍生類別管理生命週期。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved