Code Monkey home page Code Monkey logo

node-win32-api's Introduction

win32-api

FFI Definitions of Windows win32 api for node-ffi-napi

GitHub tag License Available platform ci Build status codecov Conventional Commits lerna

Migrate to v13

See migrate13

Initialization

npm run bootstrap

Packages

Package Version
win32-api main-svg
win32-def def-svg

What can I do with this?

Calling win32 native functions come from user32.dll, kernel32.dll, comctl32.dll by Node.js via node-ffi-napi

Installing

npm install win32-api

Usage

DLL Wrapper

import { 
  user32FindWindowEx, 
  winspoolGetDefaultPrinter,
} from 'win32-api/fun'

// Retrieves the printer name of the default printer for the current user on the local computer
const printerName = await winspoolGetDefaultPrinter()

const child = spawn('notepad.exe')
const hWnd = await user32FindWindowEx(0, 0, 'Notepad', null)

Find window and set window title

// **Find calc's hWnd, need running a calculator program manually at first**

/**
 * Exposed modules:
 * Comctl32: Comctl32 from lib/comctl32/api
 * Kernel32: kernel32 from lib/kernel32/api
 * User32: user32 from lib/user32/api
 */
import { Kernel32, User32 } from 'win32-api/promise'
import ref from 'ref-napi'

const knl32 = Kernel32.load()
const user32 = User32.load()

// const user32 = load(['FindWindowExW'])  // load only one api defined in lib/{dll}/api from user32.dll

const title = 'Calculator\0'    // null-terminated string
// const title = '计算器\0'    // null-terminated string 字符串必须以\0即null结尾!

const lpszWindow = Buffer.from(title, 'ucs2')
const hWnd = await user32.FindWindowExW(0, 0, null, lpszWindow)

assert((typeof hWnd === 'string' && hWnd.length > 0) || hWnd > 0)
console.log('buf: ', hWnd)

// Change title of the Calculator
const res = await user32.SetWindowTextW(hWnd, Buffer.from('Node-Calculator\0', 'ucs2'))
if ( ! res) {
  console.log('SetWindowTextW failed')
}
else {
  console.log('window title changed')
}
import ref from 'ref-napi'

// so we can all agree that a buffer with the int value written
// to it could be represented as an "int *"
const buf  = Buffer.alloc(4)
buf.writeInt32LE(12345, 0)

const hex = ref.hexAddress(buf)
console.log(typeof hex)
console.log(hex)  // ← '7FA89D006FD8'

buf.type = ref.types.int  // @ts-ignore

// now we can dereference to get the "meaningful" value
console.log(ref.deref(buf))  // ← 12345
// use of types and windef:
import ref from 'ref-napi'
import { DModel as M } from 'win32-api'
import { Kernel32, User32 } from 'win32-api/promise'

const knl32 = Kernel32.load()
const user32 = User32.load()

const lpszClass = Buffer.from('guard64\0', 'ucs2')
const hInstanceBuffer = ref.alloc(W.HANDLE_PVOID)
const hInstanceAddr = ref.address(hInstanceBuffer)

await knl32.GetModuleHandleExW(0, lpszClass, hInstanceAddr)
// <Buffer@0x00000094D3968EC0 00 00 a4 60 ff 7f 00 00, type: { indirection: 2, name: 'uint64*' }>
console.log(hInstanceBuffer)
console.log(hInstanceBuffer.readInt32LE(0))     // -> 1621360640           (60A40000)
console.log(hInstanceBuffer.readBigUInt64LE())  // -> 140734814748672n (7FFF60A40000)
// struct usage with ref-struct
import { retrieveStructFromPtrAddress, StructFactory } from 'win32-api'
import {
  DModel as M,
  DTypes as W,
  DStruct as DS,
} from 'win32-api'

// https://msdn.microsoft.com/en-us/library/windows/desktop/dd162805(v=vs.85).aspx
const point = StructFactory<M.POINT>(DS.POINT)
point.x = 100
point.y = 200
console.log(point)
import { StructFactory } from 'win32-api'
import {
  DModel as M,
  DTypes as W,
  DStruct as DS,
} from 'win32-api'


// https://docs.microsoft.com/zh-cn/windows/win32/api/wingdi/ns-wingdi-display_devicew 
const dd: M.DISPLAY_DEVICEW = StructFactory(DS.DISPLAY_DEVICEW)
dd.cb = dd.ref().byteLength
console.log(dd)
// https://github.com/waitingsong/node-win32-api/blob/main/packages/win32-api/test/user32/51.user32.EnumDisplayDevicesW.test.ts

Async Find window and set window title

// **Find calc's hWnd, need running a calculator program manually at first**
import * as ref from 'ref-napi'

import {
  DModel as M,
  DTypes as W,
  DStruct as DS,
} from 'win32-api'
import { Kernel32, User32 } from 'win32-api/promise'


const knl32 = Kernel32.load()
const user32 = User32.load()

const lpszClass = Buffer.from('CalcFrame\0', 'ucs2')
// win10
const calcLpszWindow = Buffer.from('Calculator\0', 'ucs2')
// for win7/8
const calcLpszClass = Buffer.from('CalcFrame\0', 'ucs2')

const child = spawn('calc.exe')
const hWnd = await user32.FindWindowExW(0, 0, null, calcLpszWindow) // win10
const hWnd = await user32.FindWindowExW(0, 0, calcLpszClass , null) // win7/8
assert((typeof hWnd === 'string' && hWnd.length > 0) || hWnd > 0, 'found no calc window')

const title = 'Node-Calculator'
const len = title.length

const ret = await user32.SetWindowTextW(hWnd, Buffer.from(title + '\0', 'ucs2'))
assert(ret, 'SetWindowTextW() failed')

const buf = Buffer.alloc(len * 2)
await user32.GetWindowTextW(hWnd, buf, len + 1)
const str = buf.toString('ucs2').replace(/\0+$/, '')
assert(str === title.trim(), `title should be changed to "${title}", bug got "${str}"`)

child.kill() // seems not work under win10

Demo

Dependencies Troubleshooting

Compile successfully with

  • Node.js v18, Python v3.9 and VS2019, VS2022
  • Node.js v16, Python v3.9 and VS2019, VS2022
  • Node.js v14, Python v3.7 and VS2019

If installation of node-gyp fails: Check out node-gyp and node-gyp-on-windows, windows-build-tools

Relevant

License

MIT

Languages

node-win32-api's People

Contributors

dependabot[bot] avatar githoniel avatar mottil avatar niikoo avatar njanderson avatar thenoim avatar venryx avatar waitingsong avatar zenflow avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

node-win32-api's Issues

SendMessageW stalls entire node app

If the target process is unable to handle the message, which always happens eventually either when the target isn't controlled by you, or the system is under load, or the target has crashed - the sending node app will then wait infinitely for SendMessageW to return, and it never does.

I went through win32-api's src and SendMessageTimeoutW is missing, if time permits I would very much appreciate if someone added it, because it would solve exactly these issues in a very critical part of my stack.

Also willing to pay a bounty for whoever adds it!

Thank you

SetParent

SetParent from winuser is missing. I tried to add it myself, but there is a silent failure when trying to add the tests. The parent is not set. Does anyone have any tips for how to diagnose the problem? Does anyone have any ideas?

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

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?

Could not find a declaration file for module 'win32-api/promise'

Hello I need some help
I get this error when I try to tsc

electron/native/win32.ts:3:24 - error TS7016: Could not find a declaration file for module 'win32-api/promise'. 'C:/my-workspace/demo/electron-demo/node_modules/win32-api/dist  Try `npm i --save-dev @types/win32-api` if it exists or add a new declaration (.d.ts) file containing `declare module 'win32-api/promise';`

3 import { User32 } from 'win32-api/promise';

image

nodejs=16.16.0
typescript=4.9.4
win32-api=20.2.0

My tsconfig.json
↓↓↓

{
  "compilerOptions": {
    "target": "ESNext",
    "useDefineForClassFields": true,
    "lib": ["DOM", "DOM.Iterable", "ESNext"],
    "allowJs": false,
    "skipLibCheck": true,
    "esModuleInterop": false,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "ESNext",
    "moduleResolution": "NodeNext",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",
    "baseUrl": "./",
    "paths": {
      "@/*": [
        "src/*"
      ]
    },
  },
  "include": ["src", "electron"],
}

Why use Buffers instead of plain integers for handles?

I notice that the user32 functions in this library, such as FindWindowExW return Buffers as the window handles.

However, I've seen other implementation of these functions in ffi just use simple integers -- for example, at bottom of this answer: https://stackoverflow.com/a/40733935/2441655

Question 1: Since simple integers are easier to log and pass around in Javascript, why does this library use Buffers instead?

There must be some advantage to it, but I'd like to know what it is so I can weigh whether to keep using this library or make a variant that just uses simple integers/js-numbers as handles.

==========

Oh also, how do you create a new "Buffer handle" if you have a handle in integer/js-number form?

I assumed one could just do:

var handle = [function that gets window handle, as simple integer/js-number].
var handleBuffer = Buffer.alloc(4)
handleBuffer.writeInt32LE(handle, 0);

However, whenever I pass that handleBuffer object to the ffi functions, it ignores them/acts like they're invalid. So I must be creating them wrong.

Question 2: Is there a straight-forward way of creating handle-buffers based on an integer-handle?

support like GetAltTabInfoA EnumDesktopWindows function

I am try get all in alt-Tab windws 's hwnd and titles

i am watch Window API from you doc link GetAltTabWindowA EnumDesktopWindows ...
but in the const use32= U.load() it have this function lack GetAltTabWindowA EnumDesktopWindows
hope to achieve

image

image

Second

This is my function for test I know about it shallow
I know use32.EnumWindows(foo,null) has a argument trouble but in the EnumWindows function that have a callback EnumWindowsProc function and Type: WNDENUMPROC
I want to ask how to put function into the EnumWIndows and how to use ref correctly or it' has better way to get All alt-Tab windows
image

this is error
image

awsome! universal support possible?

Can you make it generic so that any dll can be used?

there is a software called dependencywalker, i am assume you made use of some similar principle to get the functions of the dll's, but if it can be made universal to get all functions of any dll and make them usable via intellisense it would save you adding the dll's manually i guess.

just an idea, don't know if it is possible or too much work 😄

How to send WM_COPYDATA message with a string

With node-win32-api, I tried to send a WM_COPYDATA message to another win32 application with window, but it failed, the win32 application didn't receive the messsage. But when I send WM_QUIT and WM_COMMAND mesage, it worked very well
image

And when I used another win32 applciation to send the WM_COPYDATA message, it can received the message and the string
send WM_COPYDATA :
image
received the message:
image

Do you know how to send WM_COPYDATA with a string by node-win32-api?
Or do you know is there any other method that I can send a string to another win32 application in NodeJS?
Thank you in advance.

Cannot find module 'node: assert' Require stack

I installed win32-API version => "win32-api": "^20.1.0".
My Node version is 14.18.5.

The Notepad file is open on my PC.

Screenshot 2022-11-24 163247

try {
          console.log("Preload -- Try part called")
          const Win32 = require('win32-api/promise');
          const User32 = Win32.User32.load(['FindWindowExW', 'SetWindowPos']);
          var className = "Notepad"
          const SWP_NOMOVE = 0x0002, SWP_NOACTIVATE = 0x0010;
 
          module.exports = {
               ResizeWindow: async function ResizeWindow(className) {
                    const lpszClass = Buffer.from(className + '\0', 'ucs2')
                    const hWnd = await User32.FindWindowExW(0, 0, lpszClass, null); 
                    User32.SetWindowPos(hWnd, 0, 0, 0, 600, 600, SWP_NOMOVE | SWP_NOACTIVATE); 
               }
          };
} catch(e){
       console.log("Preload -- Catch part called")
       console.log("Exception ::",e)
}

Screenshot 2022-11-24 162636

When trying this code in electron it gives this => "Cannot find module 'node: assert' Require stack" error.

Screenshot 2022-11-24 162702

I've tried to find the solution. but haven't found anything yet.
Anyone any idea about this?

Bug in "Async Find window and set window title"

The sample titled "Async Find window and set window title" in README.md contains the code:

const buf = Buffer.alloc(title.length * 2)
u32.GetWindowTextW.async(hWnd, buf, buf.byteLength, err3 => {

But the Win32 API GetWindowTextW wants a character count as third parameter, not a byte count. In unicode a character is two bytes.

So the code should be (imho):

const buf = Buffer.alloc(title.length * 2)
u32.GetWindowTextW.async(hWnd, buf, title.length, err3 => {

requires Node 12, but dependencies ffi -> ref not compatible with Node 12?!?

I'm new to the npm ecosystem so maybe I am missing something totally obvious.

I try to install win32-api, but I get errors because ref won't build. Google searches tell me that ref is incompatible, as yet, with Node 12. So I backed out to Node 10, but then find that win32-api depends on ECMAScript modules, added in Node 12.

I found lxe/ref#node-12 and its friends, and they install OK, but the install of win32-api still tries to install the old ref.

I found ffi-napi and its friends, and they install OK, but the install of win32-api still tries to install ffi and thus the old ref.

What am I missing?

Can GetRawInputData be added ?

Would it be possible to add input related functions such as GetRawInputData, GetRawInputDeviceList and GetRawInputDeviceInfo ?

Anyhow, this is a very great package, keep up the good work !

HANDLE

I try to make a simple window with this module and use the example for this. The problem is, I can't use the WNDCLASSEX Struct because of the HANDLE type.
I only get this:
TypeError: could not determine a proper "type" from: "HANDLE"

const wClass = new Struct(DStruct.WNDCLASSEX)()

import_winspool.apiDef.WritePrinter is not a function

import {
winspoolGetDefaultPrinter,
winspoolOpenPrinter,
} from "win32-api/fun";

import { apiDef } from "win32-api/winspool";

I obtained the printer and handle through WinspoolGetDefPrinter and WinspoolOpenPrinter, but when calling apiDef WritePrinter doesn't get a function, can you tell me why

Cannot find module 'win32-def/struct.def'

Change "types": "src/index.ts" to "types": "./dist/index.d.ts" in win32-api/package.json, the error below disappear, but why.

$ npm run build && chcp 65001 && electron ./dist/main.js
npm WARN config global `--global`, `--local` are deprecated. Use `--location=global` instead.

> [email protected] build
> tsc

node_modules/win32-api/src/index.ts:25:26 - error TS2307: Cannot find module 'win32-def/struct.def' or its corresponding type declarations.

25 export * as DStruct from 'win32-def/struct.def'
                            ~~~~~~~~~~~~~~~~~~~~~~
node_modules/win32-api/src/index.ts:27:25 - error TS2307: Cannot find module 'win32-def/common.def' or its corresponding type declarations.

Adding Kernel32's GetSystemTime

Hey!
I am working on adding GetSystemTime, which involves my first adding to your node-win32-def project to add the FILETIME, PFILETIME, and LPFILETIME types. There are node extensions (see system-information) that use WMIC to perform tons of queries, but I would imagine we could get better performance by invoking these functions directly without having to deal with starting a console, executing WMIC, and returning. I plan to start with exposing GetSystemTime and seeing what other functions are currently exposed through executing a terminal session of WMIC.

Is this work that you would pull into your project?

Thanks,
Nick

TypeScript Compile Error

Hello,

I am getting this error when trying to use the win32-api in a typescript file and then compiling it with tsc.

"node_modules/win32-def/dist/lib/ffi.model.d.ts:26:18 - error TS2430: Interface 'FFIBuffer' incorrectly extends interface 'Buffer'.
The types of 'ref(...).readObject' are incompatible between these types.
Type '(offset?: number | undefined) => string' is not assignable to type '(buffer: Buffer, offset?: number | undefined) => Object'.
Types of parameters 'offset' and 'buffer' are incompatible.
Type 'Buffer' is not assignable to type 'number'.

26 export interface FFIBuffer extends Buffer {"

Below is my typescript class. I was basically just trying to run the sample to rename the calculator app. Any suggestions?

Thanks,
Bobby

import { FModel, K, U } from 'win32-api'
import { HANDLE } from 'win32-def/dist/lib/win.model';

export class WinAutomationService {
private knl32: FModel.ExpandFnModel<K.Win32Fns>;
private user32: FModel.ExpandFnModel<U.Win32Fns>;

constructor() {
    this.knl32 = K.load();
    this.user32 = U.load();
}

public setTitle() {
    const title: string = 'Calculator\0';

    const lpszWindow = Buffer.from(title, 'ucs2');
    const hWnd: HANDLE = this.user32.FindWindowExW(0, 0, null, lpszWindow);

    if (typeof hWnd === 'number' && hWnd > 0
        || typeof hWnd === 'bigint' && hWnd > 0
        || typeof hWnd === 'string' && hWnd.length > 0) {
        console.log('buf: ', hWnd)

        // Change title of the Calculator
        const res = this.user32.SetWindowTextW(hWnd, Buffer.from('Node-Calculator\0', 'ucs2'))

        if (!res) {
            console.log('SetWindowTextW failed')
        }
        else {
            console.log('window title changed')
        }
    }
}

}

Also here are all the node modules in my project if there happens to be a conflict here

+-- @electron-forge/[email protected]
+-- @electron-forge/[email protected]
+-- @electron-forge/[email protected]
+-- @electron-forge/[email protected]
+-- @electron-forge/[email protected]
+-- @types/[email protected]
+-- @types/[email protected]
+-- [email protected]
+-- [email protected]
+-- [email protected]
+-- [email protected]
+-- [email protected]
+-- [email protected]
+-- [email protected]
+-- [email protected]
+-- [email protected]
`-- [email protected]

How to make an application invisible in the background?

I am using the following code to call a windows application

var { spawn } = require('child_process');
const local_path = "C:\\Users\\PC\\\Documents\\";
const query = exec("start /B game.exe", { cwd: `${local_path}`,windowsHide: true });
const pid = query.pid;

how can i use win32-api?

Debug Monitor output

I am looking for Kernel32 OutputDebugString. How do we extend this library to provide this very useful function?

demo如果修改为异步方式则会出现函数已被释放问题

将最后的消息循环改成如下代码,则会出现问题

function loop() {

    // message loop
    const msg = new Struct(DS.MSG)();
    const point = new Struct(DS.POINT)();

    msg.pt = point.ref();

    let count = 0;
    const countLimit = 200;
    const start = new Date().getTime();
    const ttl = 30; // sec
    user32.GetMessageW(msg.ref(), null, 0, 0)
    user32.TranslateMessageEx(msg.ref());
    user32.DispatchMessageW(msg.ref());

    setTimeout(() => {
        loop();
    }, 20);
}

loop();
Error: ffi fatal: callback has been garbage collected!
    at Object.proxy [as DispatchMessageW] (E:\dev\nodesrc\testWin\node_modules\ffi\lib\_foreign_function.js:59:14)
    at loop (E:\dev\nodesrc\testWin\index.js:94:12)
    at Timeout.setTimeout [as _onTimeout] (E:\dev\nodesrc\testWin\index.js:96:9)
    at ontimeout (timers.js:475:11)
    at tryOnTimeout (timers.js:310:5)
    at Timer.listOnTimeout (timers.js:270:5)

compatible with regular JavaScript?

Is this compatible with regular or plain JavaScript? or is there a plain JavaScript version? if so can you show an example because I'm not familiar with typescript, coffeescript, all the pointless JavaScript variations, etc. and I prefer normal / regular / original JavaScript.

Demo crashes after some callbacks called, without any error output

After WndProc callback being called about 200 times, the whole process crashed without any error output.

The last several callback messages seems no exception:

WndProc callback:  32 661470 33554433
Sending LRESULT: 0

WndProc callback:  512 0 5505193
Sending LRESULT: 0

WndProc callback:  132 0 9240778
Sending LRESULT: 1

WndProc callback:  32 661470 33554433
Sending LRESULT: 0

WndProc callback:  512 0 5505192
Sending LRESULT: 0

WndProc callback:  132 0 9306312
Sending LRESULT: 1

WndProc callback:  32 661470 33554433
Sending LRESULT: 0

WndProc callback:  512 0 5570726
Sending LRESULT: 0

WndProc callback:  132 0 9371848
Sending LRESULT: 1

X:\path\to\the\project>

BTW, this is not the first time I've faced such a problem, any win32 APIs with callback have this weird behavior after some calls.

I've tried holding the reference of callback function with process.on('exit', function() { WndProc; }), but nothing worked at all.

Running tasks in vscode on Windows

Executing npm run build currently fails on Windows, since it calls npm run clean, which calls rm -rf dist/*, which fails since Windows doesn't have the rf command.

A simple solution is to add shx as a dev-dependency, then replace rm -rf dist/* with shx rm -rf dist/*.

[QUESTION] 请问有什么方式可以替换包内ref-napi和ffi-napi依赖吗

背景

  • electron
  • electron无法正常构建ffi-napi(社区共有的问题),所以用的是第三方改好的包@lwahonen/ffi-napi
  • win32-api包用的是ffi-napi,所以electron项目用不了

需求

  • 如何解决这个情况

我的想法

  • 通过webpack那ffi-napi替换成@lwahonen/ffi-napi,我试了webpack.resolve.alias,但这个好像不能替换node_modules里
  • 手动替换包内api,然后打包或者有引入,这个方法是在太麻烦了

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.