waitingsong / node-win32-api

win32 api
MIT License
430 stars 55 forks source link

Need help. How to use a Custom Struct with EnumWindows? #37

Closed somanuell closed 2 years ago

somanuell commented 2 years ago

My code:

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 WndEnumProc = ffi.Callback(
    W.BOOL, [W.HWND, ref.refType(EnumParams)],
    (hwnd, ep) => {
        // HERE I AM UNABLE TO USE ep members! How To?
        return 1;
    }
);

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

In the WndEnumProc callback, ep.uiMsg is undefined How to declare the callback, how to call EnumWindows passing a pointer to my custom struct, and finally how to use the menbers in the callback?

somanuell commented 2 years ago

FYI, I asked on stackoverflow

waitingsong commented 2 years ago

wait a moment

somanuell commented 2 years ago

ok, THANKS!

waitingsong commented 2 years ago

The 2nd param LPARAM of user32.EnumWindows() should be number, not buffer. try this:

  1. retrieve the ptr address of reference of the struct object
  2. retrieve the struct object via retrieveStructFromPtrAddress()
         const point = new Struct(DS.POINT)() as M.POINT_Struct
         const adress = point.ref().address()
         enumWindows(enumWindowsProc, adress)

https://github.com/waitingsong/node-win32-api/blob/502069c27350b0963adfffe4668235f52ad66a35/packages/win32-api/test/70.user32.test.ts#L57

          const point = retrieveStructFromPtrAddress<M.POINT_Struct>(lParam, DS.POINT)
          if (point) {
            console.log({ px: point.x, py: point.y })
            tmpMap.set(lParam, point)
          }

https://github.com/waitingsong/node-win32-api/blob/502069c27350b0963adfffe4668235f52ad66a35/packages/win32-api/test/70.user32.test.ts#L116

waitingsong commented 2 years ago
const Params = {
    uiMsg:  W.UINT,
    wParam: W.WPARAM,
    lParam: W.LPARAM
};
const WndEnumProc = ffi.Callback(
    W.BOOL, [W.HWND, ref.refType(EnumParams)],
    (hwnd, lParam) => {
          const obj = retrieveStructFromPtrAddress(lParam, Params)
          if (obj) {
            console.log({ obj })
          }
    }
);

user32.EnumWindows( WndEnumProc, EP.ref().address() );
somanuell commented 2 years ago

I still get 'undefined'. My code:

// testew.js
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
});

function MyretrieveStructFromPtrAddress( address, dataStructConst ) {

    const object = new Struct(dataStructConst)();
    const refType = object.ref().ref().type;      
    const buf = Buffer.alloc(4); // 32 bits...
    buf.writeInt32LE(address, 0);
    buf.type = refType;
    const ret = buf.deref().deref();
    return ret;

}   

const WndEnumProc = ffi.Callback(
    W.BOOL, [W.HWND, W.LPARAM],
    (hwnd, ep) => {
        const obj = MyretrieveStructFromPtrAddress(ep, EnumParams);
        console.log( 'ep.lParam is: ' + obj.lParam );
        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().address );
node.exe testew.js
ep.lParam is: undefined
First enumerated window is: 196734
waitingsong commented 2 years ago
user32.EnumWindows( WndEnumProc, EP.ref().address );

should be

user32.EnumWindows( WndEnumProc, EP.ref().address() );
somanuell commented 2 years ago

Sorry, same result with .address();

New end for testew.js:

const lParam = EP.ref().address();
console.log( 'lParam is: ' + lParam );
user32.EnumWindows( WndEnumProc, lParam );

New output:

lParam is: 107600200
ep.lParam is: undefined
First enumerated window is: 196734

Did you try node.exe testex.js?

somanuell commented 2 years ago

Ok, I have a Working Version: I slightly modified the MyretrieveStructFromPtrAddress by removing the dataStructConst parameter, because with it console.log( 'Address of object is: ' + object.ref().address() ); would give me 0...

The new MyretrieveStructFromPtrAddress is now:

function MyretrieveStructFromPtrAddress( address ) {

    const object = new EnumParams;
    console.log( 'Address of object is: ' + object.ref().address() );
    const refType = object.ref().ref().type;      
    const buf = Buffer.alloc(4);
    buf.writeInt32LE(address, 0);
    buf.type = refType;
    const ret = buf.deref().deref();
    return ret;

}   

and then the output is:

lParam is: 108455520
Address of object is: 108454824
ep.lParam is: 42
First enumerated window is: 196734

Now, I would like to have a more efficient version of MyretrieveStructFromPtrAddress, that is a version that would not alloc a new EnumParams structure at each call... I will try that myself.

Again Thanks!

somanuell commented 2 years ago

First Working Version without an EnumParams allocation for each enumerated window:

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.wApram = 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);
        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;
    }
);

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

node.exe testew.js gives:

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

There is still a Buffer.alloc(4); at the beginning of the callback...

waitingsong commented 2 years ago

win 64bit should Buffer.alloc(8); and buf.writeInt64LE()

somanuell commented 2 years ago

No. I use a 32 bits node.exe, so that's 4 and 32.