win32 definitions for node-ffi


Keywords
api, ffi, win32, windows, ESM, typescript, ts, comctl32, ffi-napi, kernel32, user32
License
MIT
Install
npm install win32-def@20.4.1

Documentation

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

Ref

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

// 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)

Struct

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