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自带的DStructAPI定义结构体,无需额外引入ref-struct-di依赖,用法基本一致 - 所有传给FFI的回调函数、指针指向的内存块,必须在原生API调用完成前保持有效引用,否则会出现随机崩溃、内存访问违规问题
- 在回调中修改结构体成员时,修改会直接写入原始内存,外层代码可以直接读取到修改后的值
内容的提问来源于stack exchange,提问作者manuell
相关产品推荐
相关产品推荐

