通過C#調(diào)用Windows?API的具體方法
更新時間:2025年08月11日 09:45:37 作者:墨夶
在開發(fā)系統(tǒng)監(jiān)控工具、性能分析器或自動化管理程序時,Windows?API?是你與操作系統(tǒng)對話的橋梁,通過C#調(diào)用Windows?API可以直接訪問系統(tǒng)底層數(shù)據(jù)、實現(xiàn)注冊表讀寫與電源狀態(tài)監(jiān)控以及無需額外依賴,純原生代碼實現(xiàn),所以本文給大家介紹了具體的調(diào)用方法,需要的朋友可以參考下
為什么你需要掌握Windows API調(diào)用?
在開發(fā)系統(tǒng)監(jiān)控工具、性能分析器或自動化管理程序時,Windows API 是你與操作系統(tǒng)對話的橋梁。
- 痛點1:.NET框架提供的
System.Environment類無法獲取CPU型號、電池狀態(tài)等深度信息 - 痛點2:注冊表操作與電源管理需依賴復(fù)雜第三方庫
- 痛點3:跨平臺兼容性限制了低級硬件訪問能力
通過C#調(diào)用Windows API:
- 直接訪問系統(tǒng)底層數(shù)據(jù)(如CPU核心數(shù)、內(nèi)存顆粒)
- 實現(xiàn)注冊表讀寫與電源狀態(tài)監(jiān)控
- 無需額外依賴,純原生代碼實現(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);
// 對應(yīng)的結(jié)構(gòu)體定義(按字段順序與API匹配)
[StructLayout(LayoutKind.Sequential)]
public struct SYSTEM_INFO
{
public ushort processorArchitecture; // 處理器架構(gòu)
public ushort reserved; // 保留字段
public uint pageSize; // 頁面大小
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; // 處理器級別
public ushort processorRevision; // 處理器修訂號
}
關(guān)鍵細節(jié):
CharSet.Auto:自動適配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($"頁面大小: {sysInfo.pageSize} bytes");
Console.WriteLine($"內(nèi)存分配粒度: {sysInfo.allocationGranularity} bytes");
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
輸出示例:
處理器架構(gòu): 9(x64) 處理器數(shù)量: 8 頁面大小: 4096 bytes 內(nèi)存分配粒度: 65536 bytes
二、進階篇:深度系統(tǒng)信息獲取
2.1 獲取CPU詳細信息(注冊表方式)
// 注冊表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);
// 注冊表根鍵常量
private const int HKEY_LOCAL_MACHINE = -2147483642;
// 訪問權(quán)限標志
[Flags]
public enum RegSAM : uint
{
QueryValue = 0x0001,
EnumerateSubKeys = 0x0008
}
// 獲取CPU名稱
public static string GetCpuName()
{
IntPtr hKey;
const string keyPath = @"HARDWARE\DESCRIPTION\System\CentralProcessor\0";
// 打開注冊表鍵
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)換為字符串并清理無效字符
return Encoding.Default.GetString(dataBuffer).Trim('\0');
}
實際應(yīng)用:
Console.WriteLine($"CPU型號: {GetCpuName()}");
// 輸出示例: "Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz"
2.2 獲取系統(tǒng)時間與電源狀態(tài)
// 獲取系統(tǒng)時間
[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; // 電池標志
public byte BatteryLifePercent; // 電池百分比
public byte Reserved1;
public uint BatteryLifeTime; // 剩余時間(秒)
public uint BatteryFullLifeTime; // 總?cè)萘浚耄?
}
調(diào)用示例:
public static void GetSystemTimeAndPowerStatus()
{
SYSTEMTIME sysTime = new SYSTEMTIME();
GetSystemTime(ref sysTime);
Console.WriteLine($"系統(tǒng)時間: {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($"剩余時間: {powerStatus.BatteryLifeTime / 3600}小時{(powerStatus.BatteryLifeTime % 3600) / 60}分鐘");
}
}
輸出示例:
系統(tǒng)時間: 2025-07-19 18:06:48 電源狀態(tài): 已連接 電池狀態(tài): 正在充電 剩余電量: 85% 剩余時間: 3小時45分鐘
三、實戰(zhàn)篇:綜合系統(tǒng)信息收集器
3.1 項目結(jié)構(gòu)設(shè)計
class Program
{
static void Main(string[] args)
{
Console.WriteLine("=== 系統(tǒng)信息收集器 ===\n");
// 獲取硬件信息
GetSystemHardwareInfo();
Console.WriteLine("\n=== CPU信息 ===");
Console.WriteLine($"CPU型號: {GetCpuName()}");
// 獲取時間與電源狀態(tài)
Console.WriteLine("\n=== 系統(tǒng)時間與電源 ===");
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; // 頁面文件總量
public ulong ullAvailPageFile; // 可用頁面文件
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)化與注意事項
4.1 內(nèi)存安全與異常處理
- 緩沖區(qū)溢出:使用
StringBuilder時需預(yù)分配足夠容量 - 結(jié)構(gòu)體對齊:通過
[StructLayout(LayoutKind.Sequential)]保證字段順序 - 錯誤碼處理:始終檢查API返回值并調(diào)用
Marshal.GetLastWin32Error()
4.2 跨平臺兼容性
- Windows API僅適用于Windows系統(tǒng),Linux/macOS需改用POSIX接口
- 使用條件編譯區(qū)分平臺:
#if WINDOWS // Windows-specific code #else // Cross-platform code #endif
五、 何時選擇哪種方法?
| 需求 | 推薦方法 | 典型示例 |
|---|---|---|
| 獲取CPU型號 | 注冊表讀?。≧egQueryValueEx) | GetCpuName() |
| 獲取系統(tǒng)時間 | GetSystemTime | GetSystemTimeAndPowerStatus() |
| 獲取內(nèi)存信息 | GlobalMemoryStatus | GetMemoryInfo() |
| 獲取網(wǎng)絡(luò)適配器信息 | GetAdaptersInfo | GetNetworkInfo() |
| 獲取電源狀態(tài) | GetSystemPowerStatus | GetSystemTimeAndPowerStatus() |
立即行動:
- 升級代碼:將
.NET Environment替換為原生API獲取更詳細信息 - 重構(gòu)工具:將現(xiàn)有系統(tǒng)監(jiān)控工具改為API調(diào)用以提升性能
- 探索注冊表:嘗試讀取其他系統(tǒng)配置信息(如啟動項、服務(wù)列表)
以上就是C#調(diào)用Windows API的具體方法的詳細內(nèi)容,更多關(guān)于C#調(diào)用Windows API的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Unity中的InitializeOnLoad特性實踐深入解析
這篇文章主要為大家介紹了Unity中的InitializeOnLoad特性實踐深入解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-05-05
時間戳與時間相互轉(zhuǎn)換(php .net精確到毫秒)
本文給大家分享的時間戳與時間相互轉(zhuǎn)換(php .net精確到毫秒) ,感興趣的朋友一起學(xué)習(xí)吧2015-09-09

