为什么你需要掌握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的资料请关注代码网其它相关文章!
发表评论