当前位置: 代码网 > it编程>编程语言>Asp.net > 通过C#调用Windows API的具体方法

通过C#调用Windows API的具体方法

2025年08月11日 Asp.net 我要评论
为什么你需要掌握windows api调用?在开发系统监控工具、性能分析器或自动化管理程序时,windows api 是你与操作系统对话的桥梁。痛点1:.net框架提供的system.environm

为什么你需要掌握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()
获取系统时间getsystemtimegetsystemtimeandpowerstatus()
获取内存信息globalmemorystatusgetmemoryinfo()
获取网络适配器信息getadaptersinfogetnetworkinfo()
获取电源状态getsystempowerstatusgetsystemtimeandpowerstatus()

立即行动

  1. 升级代码:将.net environment替换为原生api获取更详细信息
  2. 重构工具:将现有系统监控工具改为api调用以提升性能
  3. 探索注册表:尝试读取其他系统配置信息(如启动项、服务列表)

以上就是c#调用windows api的具体方法的详细内容,更多关于c#调用windows api的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com