如何在Flutter中使用Win32 API和WMI获取Windows设备信息
Flutter Windows端获取静态硬件信息实现方案
不需要从零手写FFI的Win32 API绑定,直接用社区维护的win32纯Dart封装包即可,省去手动映射函数、编写结构体的工作量。
1. 项目依赖配置
打开项目根目录下的pubspec.yaml,添加依赖:
dependencies: flutter: sdk: flutter win32: ^5.0.0 # 替换为pub仓库最新稳定版本 ffi: ^2.1.0
执行flutter pub get完成依赖拉取。
2. 分模块实现信息采集
静态硬件信息分两类接口获取:基础CPU架构/核心数直接调Kernel32层的GetSystemInfo接口,速度最快;BIOS厂商/序列号、CPU插槽/序列号/厂商这类SMBIOS存储的信息,走WMI查询,数据最准确,不会被系统配置篡改。
WMI读取的硬件信息是固件启动时上报的静态值,完全符合静态硬件信息的采集需求,不要从注册表读这类信息,注册表值可能被第三方软件、系统更新修改。
2.1 基础CPU信息采集
直接调用系统API获取逻辑核心数、架构等基础信息,示例代码:
import 'dart:ffi'; import 'package:win32/win32.dart'; Map<String, dynamic> getBasicCpuInfo() { final sysInfo = calloc<SYSTEM_INFO>(); GetSystemInfo(sysInfo); final arch = switch (sysInfo.ref.wProcessorArchitecture) { PROCESSOR_ARCHITECTURE_AMD64 => 'x64', PROCESSOR_ARCHITECTURE_ARM64 => 'ARM64', PROCESSOR_ARCHITECTURE_INTEL => 'x86', _ => '未知架构' }; final res = <String, dynamic>{ 'cpu逻辑核心数': sysInfo.ref.dwNumberOfProcessors, 'cpu架构': arch, '内存页大小': sysInfo.ref.dwPageSize, }; free(sysInfo); return res; }
上述代码中的switch表达式为Dart 3语法,若项目使用Dart 3以下版本,替换为常规if/else分支判断即可。
2.2 BIOS、CPU详细参数采集
通过WQL语句查询对应WMI类即可拿到目标字段:
- 查询
Win32_BIOS类获取BIOS厂商、序列号、版本、发布日期 - 查询
Win32_Processor类获取CPU厂商、名称、物理核心数、插槽参数、处理器ID、主频等信息
示例代码:
import 'dart:ffi'; import 'package:win32/win32.dart'; Map<String, dynamic> getHardwareDetailInfo() { final result = <String, dynamic>{}; final pLocator = calloc<COMObject>(); final pServices = calloc<COMObject>(); try { // 初始化COM环境 var hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); if (FAILED(hr)) throw Exception('COM环境初始化失败'); // 连接WMI服务 hr = CoCreateInstance(CLSID_WbemLocator, nullptr, CLSCTX_INPROC_SERVER, IID_IWbemLocator, pLocator.cast()); if (FAILED(hr)) throw Exception('WbemLocator实例创建失败'); final locator = IWbemLocator(pLocator); hr = locator.ConnectServer( TEXT('ROOT\\CIMV2'), nullptr, nullptr, nullptr, 0, nullptr, nullptr, pServices.cast()); if (FAILED(hr)) throw Exception('WMI服务连接失败'); final services = IWbemServices(pServices); // 读取BIOS信息 final biosEnum = calloc<COMObject>(); hr = services.ExecQuery( TEXT('WQL'), TEXT('SELECT Manufacturer,SerialNumber,SMBIOSBIOSVersion,ReleaseDate FROM Win32_BIOS'), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, nullptr, biosEnum.cast()); if (SUCCEEDED(hr)) { final enumerator = IEnumWbemClassObject(biosEnum); final pObj = calloc<COMObject>(); final returned = calloc<Uint32>(); if (enumerator.Next(WBEM_INFINITE, 1, pObj, returned) == WBEM_S_NO_ERROR) { final obj = IWbemClassObject(pObj); result['bios厂商'] = _readWmiStringProp(obj, TEXT('Manufacturer')); result['bios序列号'] = _readWmiStringProp(obj, TEXT('SerialNumber')); result['bios版本'] = _readWmiStringProp(obj, TEXT('SMBIOSBIOSVersion')); result['bios发布日期'] = _readWmiStringProp(obj, TEXT('ReleaseDate')); obj.Release(); } free(returned); free(pObj); enumerator.Release(); } free(biosEnum); // 读取CPU详细信息 final cpuList = <Map<String, String?>>[]; final cpuEnum = calloc<COMObject>(); hr = services.ExecQuery( TEXT('WQL'), TEXT('SELECT Manufacturer,Name,ProcessorId,NumberOfCores,SocketDesignation,MaxClockSpeed FROM Win32_Processor'), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, nullptr, cpuEnum.cast()); if (SUCCEEDED(hr)) { final enumerator = IEnumWbemClassObject(cpuEnum); final pObj = calloc<COMObject>(); final returned = calloc<Uint32>(); while (enumerator.Next(WBEM_INFINITE, 1, pObj, returned) == WBEM_S_NO_ERROR) { final obj = IWbemClassObject(pObj); cpuList.add({ 'cpu厂商': _readWmiStringProp(obj, TEXT('Manufacturer')), 'cpu名称': _readWmiStringProp(obj, TEXT('Name'))?.trim(), 'cpu处理器ID': _readWmiStringProp(obj, TEXT('ProcessorId')), 'cpu物理核心数': _readWmiStringProp(obj, TEXT('NumberOfCores')), 'cpu插槽参数': _readWmiStringProp(obj, TEXT('SocketDesignation')), 'cpu最大主频(MHz)': _readWmiStringProp(obj, TEXT('MaxClockSpeed')), }); obj.Release(); } free(returned); free(pObj); enumerator.Release(); } free(cpuEnum); result['cpu详细列表'] = cpuList; services.Release(); locator.Release(); return result; } finally { free(pServices); free(pLocator); CoUninitialize(); } } // WMI字符串属性读取辅助函数 String? _readWmiStringProp(IWbemClassObject obj, Pointer<Utf16> propName) { final variant = calloc<VARIANT>(); VariantInit(variant); try { final hr = obj.Get(propName, 0, variant, nullptr, nullptr); if (SUCCEEDED(hr) && variant.ref.vt == VT_BSTR) { return variant.ref.bstrVal.toDartString(); } return null; } finally { VariantClear(variant); free(variant); } }
3. 其他说明
- 上述实现完全基于Dart FFI调用系统原生API,不需要编写C/C++原生插件,打包后不需要额外携带第三方DLL,兼容Windows 10 1607及以上版本,覆盖Flutter Windows桌面的官方支持范围。
- 部分设备读取到的序列号、处理器ID为空,是因为设备厂商在BIOS层面屏蔽了对应字段的公开访问,属于固件限制,不是代码问题。
- 如果只需要基础硬件信息,不需要序列号、插槽这类细分字段,可以直接使用
device_info_plus插件,其Windows端底层同样基于FFI+WMI实现,调用更简单。
内容的提问来源于stack exchange,提问作者Abdul azeez VP
相关产品推荐
相关产品推荐

