通過(guò)C#調(diào)用Windows?API的具體方法
為什么你需要掌握Windows API調(diào)用?
在開發(fā)系統(tǒng)監(jiān)控工具、性能分析器或自動(dòng)化管理程序時(shí),Windows API 是你與操作系統(tǒng)對(duì)話的橋梁。
- 痛點(diǎn)1:.NET框架提供的
System.Environment
類無(wú)法獲取CPU型號(hào)、電池狀態(tài)等深度信息 - 痛點(diǎn)2:注冊(cè)表操作與電源管理需依賴復(fù)雜第三方庫(kù)
- 痛點(diǎn)3:跨平臺(tái)兼容性限制了低級(jí)硬件訪問(wèn)能力
通過(guò)C#調(diào)用Windows API:
- 直接訪問(wèn)系統(tǒng)底層數(shù)據(jù)(如CPU核心數(shù)、內(nèi)存顆粒)
- 實(shí)現(xiàn)注冊(cè)表讀寫與電源狀態(tài)監(jiān)控
- 無(wú)需額外依賴,純?cè)a實(shí)現(xiàn)
一、基礎(chǔ)篇:調(diào)用API的核心技巧
1.1 DllImport聲明與結(jié)構(gòu)體定義
using System; using System.Runtime.InteropServices; // 定義Windows API函數(shù)簽名 [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern uint GetSystemInfo(out SYSTEM_INFO lpSystemInfo); // 對(duì)應(yīng)的結(jié)構(gòu)體定義(按字段順序與API匹配) [StructLayout(LayoutKind.Sequential)] public struct SYSTEM_INFO { public ushort processorArchitecture; // 處理器架構(gòu) public ushort reserved; // 保留字段 public uint pageSize; // 頁(yè)面大小 public IntPtr minimumApplicationAddress; // 應(yīng)用程序最低地址 public IntPtr maximumApplicationAddress; // 應(yīng)用程序最高地址 public IntPtr activeProcessorMask; // 活躍處理器掩碼 public uint numberOfProcessors; // 處理器數(shù)量 public uint processorType; // 處理器類型 public uint allocationGranularity; // 內(nèi)存分配粒度 public ushort processorLevel; // 處理器級(jí)別 public ushort processorRevision; // 處理器修訂號(hào) }
關(guān)鍵細(xì)節(jié):
CharSet.Auto
:自動(dòng)適配ANSI/Unicode編碼LayoutKind.Sequential
:保證結(jié)構(gòu)體字段順序與原生API一致
1.2 調(diào)用示例:獲取系統(tǒng)基本信息
public static void GetSystemHardwareInfo() { SYSTEM_INFO sysInfo; if (GetSystemInfo(out sysInfo) != 0) { Console.WriteLine($"處理器架構(gòu): {sysInfo.processorArchitecture}"); Console.WriteLine($"處理器數(shù)量: {sysInfo.numberOfProcessors}"); Console.WriteLine($"頁(yè)面大小: {sysInfo.pageSize} bytes"); Console.WriteLine($"內(nèi)存分配粒度: {sysInfo.allocationGranularity} bytes"); } else { throw new Win32Exception(Marshal.GetLastWin32Error()); } }
輸出示例:
處理器架構(gòu): 9(x64) 處理器數(shù)量: 8 頁(yè)面大小: 4096 bytes 內(nèi)存分配粒度: 65536 bytes
二、進(jìn)階篇:深度系統(tǒng)信息獲取
2.1 獲取CPU詳細(xì)信息(注冊(cè)表方式)
// 注冊(cè)表API聲明 [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern long RegOpenKeyEx( IntPtr hKey, string subKey, uint ulOptions, RegSAM samDesired, out IntPtr phkResult); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern long RegQueryValueEx( IntPtr hKey, string lpValueName, uint lpReserved, out uint lpType, byte[] lpData, ref uint lpcbData); // 注冊(cè)表根鍵常量 private const int HKEY_LOCAL_MACHINE = -2147483642; // 訪問(wèn)權(quán)限標(biāo)志 [Flags] public enum RegSAM : uint { QueryValue = 0x0001, EnumerateSubKeys = 0x0008 } // 獲取CPU名稱 public static string GetCpuName() { IntPtr hKey; const string keyPath = @"HARDWARE\DESCRIPTION\System\CentralProcessor\0"; // 打開注冊(cè)表鍵 long result = RegOpenKeyEx( (IntPtr)HKEY_LOCAL_MACHINE, keyPath, 0, RegSAM.QueryValue, out hKey); if (result != 0) { throw new Win32Exception((int)result); } // 查詢ProcessorNameString值 uint dataType = 0; uint dataSize = 1024; byte[] dataBuffer = new byte[dataSize]; result = RegQueryValueEx( hKey, "ProcessorNameString", 0, out dataType, dataBuffer, ref dataSize); if (result != 0) { throw new Win32Exception((int)result); } // 轉(zhuǎn)換為字符串并清理無(wú)效字符 return Encoding.Default.GetString(dataBuffer).Trim('\0'); }
實(shí)際應(yīng)用:
Console.WriteLine($"CPU型號(hào): {GetCpuName()}"); // 輸出示例: "Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz"
2.2 獲取系統(tǒng)時(shí)間與電源狀態(tài)
// 獲取系統(tǒng)時(shí)間 [DllImport("kernel32.dll", SetLastError = true)] public static extern void GetSystemTime(ref SYSTEMTIME st); [StructLayout(LayoutKind.Sequential)] public struct SYSTEMTIME { public ushort wYear; public ushort wMonth; public ushort wDayOfWeek; public ushort wDay; public ushort wHour; public ushort wMinute; public ushort wSecond; public ushort wMilliseconds; } // 獲取電源狀態(tài) [DllImport("kernel32.dll", SetLastError = true)] public static extern bool GetSystemPowerStatus(ref SYSTEM_POWER_STATUS powerStatus); [StructLayout(LayoutKind.Sequential)] public struct SYSTEM_POWER_STATUS { public byte ACLineStatus; // 交流電源狀態(tài) public byte BatteryFlag; // 電池標(biāo)志 public byte BatteryLifePercent; // 電池百分比 public byte Reserved1; public uint BatteryLifeTime; // 剩余時(shí)間(秒) public uint BatteryFullLifeTime; // 總?cè)萘浚耄? }
調(diào)用示例:
public static void GetSystemTimeAndPowerStatus() { SYSTEMTIME sysTime = new SYSTEMTIME(); GetSystemTime(ref sysTime); Console.WriteLine($"系統(tǒng)時(shí)間: {sysTime.wYear}-{sysTime.wMonth}-{sysTime.wDay} {sysTime.wHour}:{sysTime.wMinute}:{sysTime.wSecond}"); SYSTEM_POWER_STATUS powerStatus = new SYSTEM_POWER_STATUS(); if (GetSystemPowerStatus(ref powerStatus)) { string acStatus = powerStatus.ACLineStatus == 1 ? "已連接" : "未連接"; string batteryStatus = powerStatus.BatteryFlag switch { 1 => "電量不足", 2 => "正在充電", 4 => "電池未安裝", _ => "未知狀態(tài)" }; Console.WriteLine($"電源狀態(tài): {acStatus}"); Console.WriteLine($"電池狀態(tài): {batteryStatus}"); Console.WriteLine($"剩余電量: {powerStatus.BatteryLifePercent}%"); Console.WriteLine($"剩余時(shí)間: {powerStatus.BatteryLifeTime / 3600}小時(shí){(powerStatus.BatteryLifeTime % 3600) / 60}分鐘"); } }
輸出示例:
系統(tǒng)時(shí)間: 2025-07-19 18:06:48 電源狀態(tài): 已連接 電池狀態(tài): 正在充電 剩余電量: 85% 剩余時(shí)間: 3小時(shí)45分鐘
三、實(shí)戰(zhàn)篇:綜合系統(tǒng)信息收集器
3.1 項(xiàng)目結(jié)構(gòu)設(shè)計(jì)
class Program { static void Main(string[] args) { Console.WriteLine("=== 系統(tǒng)信息收集器 ===\n"); // 獲取硬件信息 GetSystemHardwareInfo(); Console.WriteLine("\n=== CPU信息 ==="); Console.WriteLine($"CPU型號(hào): {GetCpuName()}"); // 獲取時(shí)間與電源狀態(tài) Console.WriteLine("\n=== 系統(tǒng)時(shí)間與電源 ==="); GetSystemTimeAndPowerStatus(); // 獲取內(nèi)存信息 Console.WriteLine("\n=== 內(nèi)存信息 ==="); GetMemoryInfo(); Console.WriteLine("\n=== 網(wǎng)絡(luò)信息 ==="); GetNetworkInfo(); } }
3.2 獲取內(nèi)存信息
// 獲取內(nèi)存信息 [DllImport("kernel32.dll", SetLastError = true)] public static extern bool GlobalMemoryStatus(ref MEMORYSTATUS lpBuffer); [StructLayout(LayoutKind.Sequential)] public struct MEMORYSTATUS { public uint dwLength; public uint dwMemoryLoad; // 內(nèi)存使用百分比 public ulong ullTotalPhys; // 物理內(nèi)存總量 public ulong ullAvailPhys; // 可用物理內(nèi)存 public ulong ullTotalPageFile; // 頁(yè)面文件總量 public ulong ullAvailPageFile; // 可用頁(yè)面文件 public ulong ullTotalVirtual; // 虛擬內(nèi)存總量 public ulong ullAvailVirtual; // 可用虛擬內(nèi)存 } public static void GetMemoryInfo() { MEMORYSTATUS memoryStatus = new MEMORYSTATUS(); memoryStatus.dwLength = (uint)Marshal.SizeOf(memoryStatus); if (!GlobalMemoryStatus(ref memoryStatus)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } Console.WriteLine($"內(nèi)存使用率: {memoryStatus.dwMemoryLoad}%"); Console.WriteLine($"物理內(nèi)存總量: {memoryStatus.ullTotalPhys / 1024 / 1024} MB"); Console.WriteLine($"可用物理內(nèi)存: {memoryStatus.ullAvailPhys / 1024 / 1024} MB"); Console.WriteLine($"虛擬內(nèi)存總量: {memoryStatus.ullTotalVirtual / 1024 / 1024} MB"); Console.WriteLine($"可用虛擬內(nèi)存: {memoryStatus.ullAvailVirtual / 1024 / 1024} MB"); }
3.3 獲取網(wǎng)絡(luò)信息
// 獲取網(wǎng)絡(luò)適配器信息 [DllImport("iphlpapi.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern uint GetAdaptersInfo(IntPtr pAdapterInfo, ref uint pOutBufLen); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct IP_ADAPTER_INFO { public uint ComboIndex; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string AdapterName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string Description; public uint AddressLength; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] Address; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string AddressString; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string DnsName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string DnsSuffix; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string DnsDescription; public uint PhysicalAddressLength; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] PhysicalAddress; public uint Flags; public uint Mtu; public uint IfType; public uint EnableType; public uint OperStatus; public uint Ipv6IfIndex; public uint ZoneIndices; public IntPtr FirstUnicastAddress; public IntPtr FirstAnycastAddress; public IntPtr FirstMulticastAddress; public IntPtr FirstDnsServerAddress; public IntPtr FirstDnsSuffix; } public static void GetNetworkInfo() { uint bufferSize = 15000; IntPtr buffer = Marshal.AllocHGlobal((int)bufferSize); uint result = GetAdaptersInfo(buffer, ref bufferSize); if (result == 0) { IP_ADAPTER_INFO adapterInfo = (IP_ADAPTER_INFO)Marshal.PtrToStructure(buffer, typeof(IP_ADAPTER_INFO)); Console.WriteLine($"適配器名稱: {adapterInfo.AdapterName}"); Console.WriteLine($"描述: {adapterInfo.Description}"); Console.WriteLine($"MAC地址: {BitConverter.ToString(adapterInfo.Address).Replace("-", ":")}"); Console.WriteLine($"IP地址: {adapterInfo.AddressString}"); } else { throw new Win32Exception((int)result); } Marshal.FreeHGlobal(buffer); }
四、性能優(yōu)化與注意事項(xiàng)
4.1 內(nèi)存安全與異常處理
- 緩沖區(qū)溢出:使用
StringBuilder
時(shí)需預(yù)分配足夠容量 - 結(jié)構(gòu)體對(duì)齊:通過(guò)
[StructLayout(LayoutKind.Sequential)]
保證字段順序 - 錯(cuò)誤碼處理:始終檢查API返回值并調(diào)用
Marshal.GetLastWin32Error()
4.2 跨平臺(tái)兼容性
- Windows API僅適用于Windows系統(tǒng),Linux/macOS需改用POSIX接口
- 使用條件編譯區(qū)分平臺(tái):
#if WINDOWS // Windows-specific code #else // Cross-platform code #endif
五、 何時(shí)選擇哪種方法?
需求 | 推薦方法 | 典型示例 |
---|---|---|
獲取CPU型號(hào) | 注冊(cè)表讀?。≧egQueryValueEx) | GetCpuName() |
獲取系統(tǒng)時(shí)間 | GetSystemTime | GetSystemTimeAndPowerStatus() |
獲取內(nèi)存信息 | GlobalMemoryStatus | GetMemoryInfo() |
獲取網(wǎng)絡(luò)適配器信息 | GetAdaptersInfo | GetNetworkInfo() |
獲取電源狀態(tài) | GetSystemPowerStatus | GetSystemTimeAndPowerStatus() |
立即行動(dòng):
- 升級(jí)代碼:將
.NET Environment
替換為原生API獲取更詳細(xì)信息 - 重構(gòu)工具:將現(xiàn)有系統(tǒng)監(jiān)控工具改為API調(diào)用以提升性能
- 探索注冊(cè)表:嘗試讀取其他系統(tǒng)配置信息(如啟動(dòng)項(xiàng)、服務(wù)列表)
以上就是C#調(diào)用Windows API的具體方法的詳細(xì)內(nèi)容,更多關(guān)于C#調(diào)用Windows API的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Unity中的InitializeOnLoad特性實(shí)踐深入解析
這篇文章主要為大家介紹了Unity中的InitializeOnLoad特性實(shí)踐深入解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05時(shí)間戳與時(shí)間相互轉(zhuǎn)換(php .net精確到毫秒)
本文給大家分享的時(shí)間戳與時(shí)間相互轉(zhuǎn)換(php .net精確到毫秒) ,感興趣的朋友一起學(xué)習(xí)吧2015-09-09C#實(shí)現(xiàn)簡(jiǎn)單的文件加密與解密方式
這篇文章主要介紹了C#實(shí)現(xiàn)簡(jiǎn)單的文件加密與解密方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01C# 獲取進(jìn)程退出代碼的實(shí)現(xiàn)示例
這篇文章主要介紹了C# 獲取進(jìn)程退出代碼的實(shí)現(xiàn)示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-02-02