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

 更新时间:2025年08月11日 09:45:37   作者:墨夶  
在开发系统监控工具、性能分析器或自动化管理程序时,Windows API 是你与操作系统对话的桥梁,通过C#调用Windows API可以直接访问系统底层数据、实现注册表读写与电源状态监控以及无需额外依赖,纯原生代码实现,所以本文给大家介绍了具体的调用方法,需要的朋友可以参考下

为什么你需要掌握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的资料请关注脚本之家其它相关文章!

相关文章

  • C#算法之关于大牛生小牛的问题

    C#算法之关于大牛生小牛的问题

    这篇文章主要介绍了C#算法之关于大牛生小牛的问题,是C#非常典型的算法,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-01-01
  • Unity中的InitializeOnLoad特性实践深入解析

    Unity中的InitializeOnLoad特性实践深入解析

    这篇文章主要为大家介绍了Unity中的InitializeOnLoad特性实践深入解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05
  • 时间戳与时间相互转换(php .net精确到毫秒)

    时间戳与时间相互转换(php .net精确到毫秒)

    本文给大家分享的时间戳与时间相互转换(php .net精确到毫秒) ,感兴趣的朋友一起学习吧
    2015-09-09
  • C#提取PDF中指定文本与图片坐标的示例代码

    C#提取PDF中指定文本与图片坐标的示例代码

    这篇文章主要为大家详细介绍了如何使用国产PDF库通过C# 提取PDF中指定文本或图片的坐标位置(X, Y轴),感兴趣的小伙伴可以跟随小编一起学习一下
    2023-12-12
  • C#实现一阶卡尔曼滤波算法的示例代码

    C#实现一阶卡尔曼滤波算法的示例代码

    这篇文章主要介绍了C#实现一阶卡尔曼滤波算法的示例代码,帮助大家更好的理解和学习使用c#,感兴趣的朋友可以了解下
    2021-04-04
  • C#实现简单的文件加密与解密方式

    C#实现简单的文件加密与解密方式

    这篇文章主要介绍了C#实现简单的文件加密与解密方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-01-01
  • C# 获取进程退出代码的实现示例

    C# 获取进程退出代码的实现示例

    这篇文章主要介绍了C# 获取进程退出代码的实现示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-02-02
  • 详解C# FileStream类

    详解C# FileStream类

    这篇文章主要介绍了详解C# FileStream类的相关知识,文中讲解的非常细致,代码供大家参考和学习,感兴趣的朋友可以了解下
    2020-06-06
  • C#多线程与跨线程访问界面控件的方法

    C#多线程与跨线程访问界面控件的方法

    这篇文章主要介绍了C#多线程与跨线程访问界面控件的方法,实例分析了C#多线程与跨线程访问空间的技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-03-03
  • C#数据适配器DataAdapter

    C#数据适配器DataAdapter

    这篇文章介绍了C#中的数据适配器DataAdapter,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-05-05

最新评论