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

Dart FFI调用FindWindowA返回0无法获取文件资源管理器窗口句柄

问题描述

以下Dart代码预期获取文件资源管理器的窗口句柄,但在文件资源管理器窗口正常打开的情况下,函数始终返回0:

import 'package:ffi/ffi.dart';
import 'dart:ffi';

void main() {
  DynamicLibrary dl = DynamicLibrary.open('user32.dll');
  final func = dl.lookupFunction<
      IntPtr Function(Pointer<Utf16>?, Pointer<Utf16>?),
      int Function(Pointer<Utf16>?, Pointer<Utf16>?)
    >('FindWindowA');

  print(func(nullptr, 'File Explorer'.toNativeUtf16()));
}

已验证的现象:

  • C++程序中调用FindWindowA,传入参数NULL和'File Explorer'时可正常返回预期句柄
  • Dart环境中直接给第一个参数传null会抛出错误Invalid argument(s): argument value for ':ffi_param1' is null,因此代码中使用nullptr作为第一个入参
根本原因

核心问题是调用的Win32 API版本和传入的字符串编码不匹配:

  • Win32窗口查找API分两个版本:后缀为A的FindWindowA是ANSI版本,要求传入单字节ANSI编码的字符串;后缀为W的FindWindowW是宽字符版本,要求传入UTF-16(双字节)编码的字符串。
  • 代码中通过toNativeUtf16()生成的是UTF-16编码的字符串指针,却传给了只接受ANSI字符串的FindWindowA,API解析传入的字符串时识别不到正确的窗口标题,自然查找失败返回0。
  • 第一个参数使用nullptr的写法是正确的,不存在问题。
解决方案

优先选择使用FindWindowW宽字符版本,匹配UTF-16编码的字符串,这也是现代Windows系统原生支持的API版本,不需要内部做编码转换,不会出现非英文标题乱码问题,性能更好。
修正后的可运行代码如下:

import 'package:ffi/ffi.dart';
import 'dart:ffi';

void main() {
  DynamicLibrary dl = DynamicLibrary.open('user32.dll');
  // 查找宽字符版本的FindWindowW函数
  final findWindow = dl.lookupFunction<
      IntPtr Function(Pointer<Utf16>?, Pointer<Utf16>?),
      int Function(Pointer<Utf16>?, Pointer<Utf16>?)
    >('FindWindowW');

  // 分配native内存存储UTF-16编码的窗口标题
  final windowTitle = 'File Explorer'.toNativeUtf16();
  // 传入nullptr代表不限制窗口类,匹配标题为File Explorer的窗口
  final hwnd = findWindow(nullptr, windowTitle);
  print(hwnd);

  // 手动释放native堆上分配的字符串内存,避免内存泄漏
  calloc.free(windowTitle);
}

如果一定要使用FindWindowA,需要将传入的字符串转为ANSI编码的native指针,不推荐这种写法,遇到中文等非ASCII字符的窗口标题时很容易出现乱码导致查找失败。

内容的提问来源于stack exchange,提问作者Sanmay Kant

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 13:06:23