通過(guò)C#調(diào)用Windows?API的具體方法
為什么你需要掌握Windows API調(diào)用?
在開(kāi)發(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";
// 打開(kāi)注冊(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è)表讀取(RegQueryValueEx) | 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)文章
使用C#編寫簡(jiǎn)單的圖形化的可發(fā)送附件的郵件客戶端程序
這篇文章主要介紹了使用C#編寫一個(gè)圖形化的可發(fā)送附件的郵件客戶端程序的方法,文中的示例同樣是基于支持smtp協(xié)議的郵件服務(wù)器,需要的朋友可以參考下2016-02-02
C#中如何使用Winform實(shí)現(xiàn)炫酷的透明動(dòng)畫界面
這篇文章講解了如何使用Winform實(shí)現(xiàn)炫酷的透明動(dòng)畫界面,Winform相對(duì)于Wpf使用更簡(jiǎn)單一些,系統(tǒng)要求更低,需要了解的朋友可以參考下2015-07-07
C#使用對(duì)象序列化類庫(kù)MessasgePack
這篇文章介紹了C#使用對(duì)象序列化類庫(kù)MessasgePack的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06
C# 計(jì)算標(biāo)準(zhǔn)偏差相當(dāng)于Excel中的STDEV函數(shù)實(shí)例
下面小編就為大家?guī)?lái)一篇C# 計(jì)算標(biāo)準(zhǔn)偏差相當(dāng)于Excel中的STDEV函數(shù)實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-01-01

