通过C#调用Windows API的具体方法
作者:墨夶
在开发系统监控工具、性能分析器或自动化管理程序时,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() |
| 获取系统时间 | GetSystemTime | GetSystemTimeAndPowerStatus() |
| 获取内存信息 | GlobalMemoryStatus | GetMemoryInfo() |
| 获取网络适配器信息 | GetAdaptersInfo | GetNetworkInfo() |
| 获取电源状态 | GetSystemPowerStatus | GetSystemTimeAndPowerStatus() |
立即行动:
- 升级代码:将
.NET Environment替换为原生API获取更详细信息 - 重构工具:将现有系统监控工具改为API调用以提升性能
- 探索注册表:尝试读取其他系统配置信息(如启动项、服务列表)
以上就是C#调用Windows API的具体方法的详细内容,更多关于C#调用Windows API的资料请关注脚本之家其它相关文章!
