为什么你需要掌握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 numberofprocessors; // 处理器数量 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.60ghz"
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 systime); 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 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); }
四、性能优化与注意事项
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的资料请关注代码网其它相关文章!
发表评论