目录
- 为什么你需要掌握Windows API调用?
- 一、基础篇:调用API的核心技巧
- 1.1 DllImport声明与结构体定义
- 1.2 调用示例:获取系统基本信息
- 二、进阶篇:深度系统信息获取
- 2.1 获取CPU详细信息(注册表方式)
- 2.2 获取系统时间与电源状态
- 三、实战篇:综合系统信息收集器
- 3.1 项目结构设计
- 3.2 获取内存信息
- 3.3 获取网络信息
- 四、性能优化与注意事项
- 4.1 内存安全与异常处理
- 4.2 跨平台兼容性
- 五、 何时选择哪种方法?
为什么你需要掌握Windows API调用?
在开发系统监控工具、性能分析器或自动化管理程序时,Windows API 是你与操作系统对话的桥梁。
- 痛点1:.NET框架提供的
System.Environment
类无法获取CPU型号、电池状态等深度信息 - 痛点2:注册表操作与电源管理需依赖复杂第三方库
- 痛点3:跨平台兼容性限制了低级硬件访问能力
通过C#调用Windows API:
- 直接访问系统底层数据(如CPU核心数、内存颗粒)
- 实现注册表读写与电源状态监控
- 无需额外依赖,纯原生代码实现
一、基础篇:调用API的核心技巧
1.1 DllImport声明与结构体定义
using System; using System.Runtime.InteropServices; // 定义Windows API函数签名 [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern uint GetSystemInfo(out SYSTEM_INFO lpSystemInfo); // 对应的结构体定义(按字段顺序与API匹配) [StructLayout(LayoutKind.Sequential)] public struct SYSTEM_INFO { public ushort processorArchitecture; // 处理器架构 public ushort reserved; // 保留字段 public uint pageSize; // 页面大小 public IntPtr minimumApplicationAddress; // 应用程序最低地址 public IntPtr maximumApplicationAddress; // 应用程序最高地址 public IntPtr activeProcessorMask; // 活跃处理器掩码 public uint nuandroidmberOfProcessors; // 处理器数量 public uint processorType; // 处理器类型 public uint allocationGranularity; // 内存分配粒度 public ushort processorLevel; // 处理器级别 public ushort processorRevision; // 处理器修订号 }
关键细节:
CharSet.Auto
:自动适配ANSI/Unicode编码LayoutKind.Sequential
:保证结构体字段顺序与原生API一致
1.2 调用示例:获取系统基本信息
public static void GetSystemHardwareInfo() { SYSTEM_INFO sysInfo; if (GetSystemInfo(out sysInfo) != 0) { Console.WriteLine($"处理器架构: {sysInfo.processorArchitecture}"); Console.WriteLine($"处理器数量: {sysInfo.numberOfProcessors}"); Console.WriteLine($"页面大小: {sysInfo.pageSize} bytes"); Console.WriteLine($"内存分配粒度: {sysInfo.allocationGranularity} bytes"); } else { throw new Win32Exception(Marshal.GetLastWin32Error()); } }
输出示例:
处理器架构: 9(x64) 处理器数量: 8 页面大小: 4096 bytes 内存分配粒度: 65536 bytes
二、进阶篇:深度系统信息获取
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; // 访问权限标志 [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); } // 转换为字符串并清理无效字符 return Encoding.Default.GetString(dataBuffer).Trim('\0'); }
实际应用:
Console.WriteLine($"CPU型号: {GetCpuName()}"); // 输出示例: "Intel(R) Core(TM) i7-9750H CPU @ 2.60GHzjs"
2.2 获取系统时间与电源状态
// 获取系统时间 [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; } // 获取电源状态 [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; // 交流电源状态 public byte BATteryFlag; // 电池标志 public byte BatteryLifePercent; // 电池百分比 public byte Reserved1; public uint BatteryLifeTime; // 剩余时间(秒) public uint BatteryFullLifeTime; // 总容量(秒) }
调用示例:
public static void GetSystemTimeAndPowerStatus() { SYSTEMTIME sysTime = new SYSTEMTIME(); GetSystemTime(ref shttp://www.devze.comysTime); Console.WriteLine($"系统时间: {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 => "电池未安装", _ => "未知状态" }; Console.WriteLine($"电源状态: {acStatus}"); Console.WriteLine($"电池状态: {batteryStatus}"); Console.WriteLine($"剩余电量: {powerStatus.BatteryLifePercent}%"); Console.WriteLine($"剩余时间: {powerStatus.BatteryLifeTime / 3600}小时{(powerStatus.BatteryLifeTime % 3600) / 60}分钟"); } }
输出示例:
系统时间: 2025-07-19 18:06:48 电源状态: 已连接 电池状态: 正在充电 剩余电量: 85% 剩余时间: 3小时45分钟
三、实战篇:综合系统信息收集器
3.1 项目结构设计
class Program { static void Main(string[] args) { Console.WriteLine("=== 系统信息收集器 ===\n"); // 获取硬件信息 GetSystemHardwareInfo(); Console.WriteLine("\n=== CPU信息 ==="); Console.WriteLine($"CPU型号: {GetCpuName()}"); // 获取时间与电源状态 Console.WriteLine("\n=== 系统时间与电源 ==="); GetSystemTimeAndPowerStatus(); // 获取内存信息 Console.WriteLine("\n=== 内存信息 ==="); GetMemoryInfo(); Console.WriteLine("\n=== 网络信息 ==="); GetNetworkInfo(); } }
3.2 获取内存信息
// 获取内存信息 [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; // 内存使用百分比 public ulong ullTotalPhys; // 物理内存总量 public ulong ullAvailPhys; // 可用物理内存 public ulong ullTotalPageFile; // 页面文件总量 public ulong ullAvailPageFile; // 可用页面文件 public ulong ullTotalVirtual; // 虚拟内存总量 public ulong ullAvailVirtual; // 可用虚拟内存 } 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($"内存使用率: {memoryStatus.dwMemoryLoad}%"); Console.WriteLine($"物理内存总量: {memoryStatus.ullTotalPhys / 1024 / 1024} MB"); Console.WriteLine($"可用物理内存: {memoryStatus.ullAvailPhys / 1024 / 1024} MB"); Console.WriteLine($"虚拟内存总量: {memoryStatus.ullTotalVirtual / 1024 / 1024} MB"); Console.WriteLine($"可用虚拟内存: {memoryStatus.ullAvailVirtual / 1024 / 1024} MB"); }
3.3 获取网络信息
// 获取网络适配器信息 [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 bufferphpSize); 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); }
四、性能优化与注意事项
4.1 内存安全与异常处理
- 缓冲区溢出:使用
StringBuilder
时需预分配足够容量 - 结构体对齐:通过
[StructLayout(LayoutKind.Sequential)]
保证字段顺序 - 错误码处理:始终检查API返回值并调用
Marshal.GetLastWin32Error()
4.2 跨平台兼容性
- Windows API仅适用于Windows系统,linux/macOS需改用POSIX接口
- 使用条件编译区分平台:
#if WINDOWS // Windows-specific code #else // Cross-platform code #endif
五、 何时选择哪种方法?
需求 | 推荐方法 | 典型示例 |
---|---|---|
获取CPU型号 | 注册表读取(RegQueryValueEx) | GetCpuName() |
获取系统时间 | GetSystemTime | GetSystemTimeAndPowerStatus() |
获取内存信息 | GlobalMemoryStatus | GetMemoryInfo() |
获取网络适配器信息 | GetAdaptersInfo | GetNetworkInfo() |
获取电源状态 | GetSystemPowerStatus | GetSystemTimeAndPowerStatus() |
立即行动:
- 升级代码:将
.NET Environment
替换为原生API获取更详细信息 - 重构工具:将现有系统监控工具改为API调用以提升性能
- 探索注册表:尝试读取其他系统配置信息(如启动项、服务列表)
以上就是C#调用Windows API的具体方法的详细内容,更多关于C#调用Windows API的资料请关注编php程客栈(www.devze.com)其它相关文章!
精彩评论