You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 19:48:28