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

C# 調用 Windows API 核心要點總結

     編輯:PHP 相關知識

.NET 透過 P/Invoke (Platform Invocation Services) 調用非託管 Windows API。本文彙總 C# 簽名映射、資料類型對應、呼叫約定、字元集控制、結構體封送、錯誤處理等核心要點,並提供實用範本。

基礎宣告範本

using System;
using System.Runtime.InteropServices;

public static class WinApi {
    // 1. 基礎宣告:DllImport 屬性指定 DLL、進入點、呼叫約定、字元集
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern int MessageBox(IntPtr hWnd, string text, string caption, uint type);

    // 2. 若方法名與 API 不同,用 EntryPoint 指定真實名稱
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, EntryPoint = "GetVersionEx")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool GetVersionEx(ref OSVERSIONINFOEX lpVersionInfo);
}

DllImport 關鍵屬性詳解

屬性用途常用值
CallingConvention堆疊清理者、參數壓棧順序CallingConvention.StdCall (Win32 預設)、Cdecl (C 標準、可變參數)
CharSet字串封送編碼、API 名稱後綴 (A/W)CharSet.Auto (NT=Unicode, 9x=ANSI)、Unicode、Ansi
EntryPointDLL 真實導出函數名或序數字串或 #123 序數
ExactSpelling禁止依 CharSet 修飾名稱 (加 A/W)true 精確匹配
SetLastError調用後保留 Win32 錯誤碼供 Marshal.GetLastWin32Error() 讀取true (推薦開啟)
PreserveSig保留原始簽名 (不轉 HRESULT + out retval)true (COM 介面常用)

常見類型映射表

Win32 (C/C++)C# 簽名備註
int, long, DWORD, UINTint, uint4 字節有號/無號
LONG_PTR, DWORD_PTR, HANDLE, HWND, HMODULEIntPtr指標大小:32 位=4B, 64 位=8B,**必須用 IntPtr**
LPSTR, LPCSTR, char*string (CharSet.Ansi)自動轉 ANSI
LPWSTR, LPCWSTR, wchar_t*string (CharSet.Unicode)自動轉 UTF-16
LPTSTR (TCHAR*)string (CharSet.Auto)隨平台自動 ANSI/Unicode
BOOLbool / [MarshalAs(UnmanagedType.Bool)]Win32 BOOL=4B,C# bool=1B,建議加 MarshalAs
構造體 (struct)struct / class + [StructLayout(LayoutKind.Sequential)]欄位順序、對齊必須一致

結構體封送實例

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct OSVERSIONINFOEX {
    public uint dwOSVersionInfoSize;
    public uint dwMajorVersion;
    public uint dwMinorVersion;
    public uint dwBuildNumber;
    public uint dwPlatformId;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
    public string szCSDVersion; // 服務包版本字串
    public ushort wServicePackMajor;
    public ushort wServicePackMinor;
    public ushort wSuiteMask;
    public byte wProductType;
    public byte wReserved;
}

// 呼叫時需先設定 Size,並用 ref 傳遞
OSVERSIONINFOEX osvi = new OSVERSIONINFOEX();
osvi.dwOSVersionInfoSize = (uint)Marshal.SizeOf(typeof(OSVERSIONINFOEX));
bool ok = GetVersionEx(ref osvi);

三大避坑指南

  1. 垃圾回收提前釋放 Handle:若非託管代碼長期持有物件引用,用 GCHandle.Alloc(obj, GCHandleType.Pinned) 或 HandleRef 包裝,防止 GC 移動/回收導致指標失效。
  2. 字串緩衝區大小不足:需字串輸出的 API (如 GetWindowText),先用 StringBuilder 配合 capacity 預分配:var sb = new StringBuilder(256); GetWindowText(hwnd, sb, sb.Capacity);。
  3. 64 位兼容:所有指標、Handle、LONG_PTR **統一用 IntPtr**,切勿用 int/long 硬編碼,否則 64 位下截斷崩潰。

資源推薦

  • pinvoke.net — 最大 Windows API 簽名社群資料庫,可直接複製 C# 宣告。
  • Visual Studio 安裝目錄 Samples\Technologies\Interop\PlatformInvoke\WinAPIs\CS — 官方範例代碼。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved