Search code examples
node.jswinapinode-ffi

How to use a custom struct with EnumWindows in the win32-api node module


Using the node module win32-api and the node module ffi-napi, I am able to successfully call the Win32 API EnumWindows.

The working code is as follow:

const { DStruct: DS, DTypes: W, U } = require('win32-api');
const user32 = U.load(); 
const ffi = require('ffi-napi');

const WndEnumProc = ffi.Callback(
    W.BOOL, [W.HWND, W.LPARAM],
    (hwnd, lparam) => {
        console.log('First enumerated window is: ' + hwnd);
        return 0;
    }
);

user32.EnumWindows( WndEnumProc, 0 );

The output is (note that I return 0 in the callback to stop the enumeration):

First enumerated window is: 65914

Now, I want to use the LPARAM parameter of EnumWindows to pass a "pointer" to a custom struct to the callback.

If I was using C, the structure would be like that:

struct EnumParams {
    UINT uiMsg;
    WPARAM wParam;
    LPARAM lParam;
}

Question: How to declare, define, pass, and use a custom struct with a ffi callback?

What I tried:

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
});

const WndEnumProc = ffi.Callback(
    W.BOOL, [W.HWND, ref.refType(EnumParams)],
    (hwnd, ep) => {
        console.log('type of ep is: ' + typeof ep);
        console.log('type of ep.uiMsg is: ' + typeof ep.uiMsg);
        console.log('First enumerated window is: ' + hwnd);
        return 0;
    }
);

var EP = new EnumParams;
EP.uiMsg = 0;
EP.wApram = 0;
EP.lParam = 42;

user32.EnumWindows( WndEnumProc, EP.ref() );

Output:

type of ep is: object
type of ep.uiMsg is: undefined
First enumerated window is: 65914

As I you can see, I can't access member of my struct in the callback. Maybe it's the way I define/use...


Solution

  • With help from the author of win32-api, I now have a working version:

    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
    });
    
    var EP = new EnumParams;
    EP.uiMsg = 0;
    EP.wParam = 0;
    EP.lParam = 42;
    
    const refType = EP.ref().ref().type;
    
    const WndEnumProc = ffi.Callback(
        W.BOOL, [W.HWND, W.LPARAM],
        (hwnd, ep) => {
            const buf = Buffer.alloc(4); // node 32 bits...
            buf.writeInt32LE(ep, 0);
            buf.type = refType;
            const EPObject = buf.deref().deref();
            console.log( 'EPObject.lParam is: ' + EPObject.lParam );
            console.log('First enumerated window is: ' + hwnd);
            return 0; // Stop enumeration at the first window
        }
    );
    
    user32.EnumWindows( WndEnumProc, EP.ref().address() );
    

    And the output is:

    EPObject.lParam is: 42
    First enumerated window is: 196734