开发者

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

目录
  • 为什么你需要掌握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()
    获取系统时间GetSystemTimeGetSystemTimeAndPowerStatus()
    获取内存信息GlobalMemoryStatusGetMemoryInfo()
    获取网络适配器信息GetAdaptersInfoGetNetworkInfo()
    获取电源状态GetSystemPowerStatusGetSystemTimeAndPowerStatus()

    立即行动

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

    以上就是C#调用Windows API的具体方法的详细内容,更多关于C#调用Windows API的资料请关注编php程客栈(www.devze.com)其它相关文章!

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜