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

Node.js win32-api调用EnumWindows时如何向回调传自定义结构体

问题根因

你的代码存在3个核心问题,导致无法正确读取结构体成员:

  • 回调接收的第二个参数是原始内存指针(Buffer类型),FFI不会自动将其转换为你定义的结构体实例,必须手动包装才能访问成员
  • 结构体赋值时字段拼写错误:将wParam误写为wApram,该字段从未被正确赋值
  • 回调参数类型声明不匹配:EnumWindows要求回调的第二个参数为LPARAM(指针宽度整型),直接声明为自定义结构体指针类型会干扰FFI的类型转换逻辑
正确实现代码
const { DStruct: DS, DTypes: W, U } = require('win32-api');
const user32 = U.load(); 
const ffi = require('ffi-napi');
const ref = require('ref-napi');
const StructDi = require('ref-struct-di');
const Struct = StructDi(ref);

// 定义自定义结构体
const EnumParams = Struct({
    uiMsg:  W.UINT,
    wParam: W.WPARAM,
    lParam: W.LPARAM
});

// 回调第二个参数声明为原生LPARAM类型,和Win32 API签名保持一致
const WndEnumProc = ffi.Callback(
    W.BOOL, [W.HWND, W.LPARAM],
    (hwnd, lparam) => {
        // 将传入的原始指针包装为EnumParams实例,直接操作对应内存
        const ep = new EnumParams(lparam);
        console.log('type of ep is: ' + typeof ep);
        console.log('uiMsg value: ' + ep.uiMsg);
        console.log('wParam value: ' + ep.wParam);
        console.log('lParam value: ' + ep.lParam);
        console.log('First enumerated window is: ' + hwnd);
        return 0;
    }
);

// 初始化结构体实例,注意字段名拼写正确
const EP = new EnumParams();
EP.uiMsg = 123;
EP.wParam = 456;
EP.lParam = 42;

// 持有回调和结构体实例的全局引用,避免被JS引擎GC回收导致内存访问崩溃
global._enumProcRef = WndEnumProc;
global._enumParamsRef = EP;

user32.EnumWindows(WndEnumProc, EP.ref());
运行预期输出
type of ep is: object
uiMsg value: 123
wParam value: 456
lParam value: 42
First enumerated window is: 65914
补充说明
  • 你也可以直接使用win32-api自带的DStruct API定义结构体,无需额外引入ref-struct-di依赖,用法基本一致
  • 所有传给FFI的回调函数、指针指向的内存块,必须在原生API调用完成前保持有效引用,否则会出现随机崩溃、内存访问违规问题
  • 在回调中修改结构体成员时,修改会直接写入原始内存,外层代码可以直接读取到修改后的值

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 04:42:16