Skip to content

koffi-遍历桌面返回所有窗口的句柄

例子 desktop.js

js
const koffi = require("koffi");

// 加载user32.dll
const user32 = koffi.load("user32.dll");

// 定义 HANDLE 和 HWND
const HANDLE = koffi.pointer("HANDLE", koffi.opaque());
const HWND = koffi.alias("HWND", HANDLE);

// 定义 EnumWindowsProc 回调函数的签名
const EnumWindowsProc = koffi.proto(
  "bool __stdcall EnumWindowsProc(HWND hwnd, long lParam)"
);

const EnumWindows = user32.func("__stdcall", "EnumWindows", "bool", [
  koffi.pointer(EnumWindowsProc),
  "int",
]);

let cb1 = koffi.register((hwnd, lParam) => {
  console.log("[hwnd, lParam]", hwnd, lParam);
  return true;
}, koffi.pointer(EnumWindowsProc));

EnumWindows(cb1, 0);

koffi.unregister(cb1);

console.log("EnumWindowsProc", EnumWindowsProc);

desktop.js 执行结果

powershell
PS C:\Users\Administrator\Desktop\koffi-sample> node .\desktop.js
[hwnd, lParam] [External: 180040] 0
[hwnd, lParam] [External: 1d071c] 0
[hwnd, lParam] [External: 101dc] 0
[hwnd, lParam] [External: 10190] 0
[hwnd, lParam] [External: 140474] 0
[hwnd, lParam] [External: 40974] 0
...
[hwnd, lParam] [External: 10104] 0
[hwnd, lParam] [External: 200a8] 0
[hwnd, lParam] [External: 200ac] 0
[hwnd, lParam] [External: 200b2] 0
[hwnd, lParam] [External: 3003c] 0
[hwnd, lParam] [External: 1016e] 0
[hwnd, lParam] [External: 3006e] 0
[hwnd, lParam] [External: b04a8] 0
[hwnd, lParam] [External: 407b0] 0
EnumWindowsProc [External: 1a3f3d38388]
PS C:\Users\Administrator\Desktop\koffi-sample>

下面是代码 desktop.js 带有详细中文注释的版本,帮助理解每个部分的作用以及它的返回值:

javascript
// 引入 koffi 库,用于调用本地系统库函数
const koffi = require("koffi");

// 加载 user32.dll,这是 Windows 系统用于管理窗口的系统库
const user32 = koffi.load("user32.dll");

// 定义 HANDLE 类型,表示一个通用的句柄,使用不透明的指针类型
const HANDLE = koffi.pointer("HANDLE", koffi.opaque());
// 定义 HWND 类型作为 HANDLE 的别名,特别表示窗口句柄
const HWND = koffi.alias("HWND", HANDLE);

// 定义 EnumWindowsProc 回调函数的签名,这是 EnumWindows 函数将调用的函数类型
const EnumWindowsProc = koffi.proto(
  "bool __stdcall EnumWindowsProc(HWND hwnd, long lParam)"
);

// 声明 EnumWindows 函数,这是 user32.dll 中的一个函数,用于枚举所有顶层窗口
const EnumWindows = user32.func("__stdcall", "EnumWindows", "bool", [
  koffi.pointer(EnumWindowsProc), // 回调函数的指针
  "int", // 附加参数,传递给回调函数
]);

// 注册一个回调函数,用于 EnumWindows 调用
let cb1 = koffi.register((hwnd, lParam) => {
  // 在控制台打印每个窗口的句柄和 lParam 值
  console.log("[hwnd, lParam]", hwnd, lParam);
  return true; // 返回 true 继续枚举窗口,返回 false 则停止枚举
}, koffi.pointer(EnumWindowsProc));

// 调用 EnumWindows 函数,传递注册的回调函数和 lParam 值 0
EnumWindows(cb1, 0);

// 注销回调函数,清理资源
koffi.unregister(cb1);

// 打印 EnumWindowsProc 函数的指针信息
console.log("EnumWindowsProc", EnumWindowsProc);

执行结果解释

  • 执行 node .\desktop.js 命令时,控制台打印出的信息包括多个窗口句柄和 lParam 值。这些值是 EnumWindows 函数枚举到的顶层窗口的句柄,其中 lParam 总是 0,因为在调用时传递的是 0。
  • [External: xxxxxx] 格式的输出表示窗口句柄,这是一个指向内存地址的指针。
  • 最后打印的 EnumWindowsProc [External: xxxxxxxxx] 表示回调函数指针的内部表示。

返回值

  • EnumWindows 函数:返回值是 bool 类型,如果函数成功枚举所有窗口,通常返回 true。如果在枚举过程中回调函数返回了 false,则提前终止枚举并返回 false
  • 回调函数 cb1:每次调用时返回 true,表示继续枚举窗口。如果要停止枚举窗口,可以改为返回 false

这个例子演示了如何使用 koffi 库与 Windows 的系统函数交互,特别是如何操作窗口句柄并在 Node.js 环境中执行系统级操作。

希望返回 hwnd 的值为 int32 类型

desktop.js

js
const koffi = require("koffi");

// 加载user32.dll
const user32 = koffi.load("user32.dll");

// 定义 HANDLE 和 HWND
const HANDLE = koffi.pointer("HANDLE", koffi.opaque());
const HWND = koffi.alias("HWND", HANDLE);

// 定义 EnumWindowsProc 回调函数的签名
const EnumWindowsProc = koffi.proto(
  "bool __stdcall EnumWindowsProc(HWND hwnd, long lParam)"
  "bool __stdcall EnumWindowsProc(int32, int32)"
);

const EnumWindows = user32.func("__stdcall", "EnumWindows", "bool", [
  koffi.pointer(EnumWindowsProc),
  "int",
]);

let cb1 = koffi.register((hwnd, lParam) => {
  console.log("[hwnd, lParam]", hwnd, lParam);
  return true;
}, koffi.pointer(EnumWindowsProc));

EnumWindows(cb1, 0);

koffi.unregister(cb1);

console.log("EnumWindowsProc", EnumWindowsProc);

代码执行结果

powershell
PS C:\Users\Administrator\Desktop\koffi-sample> node .\desktop.js
[hwnd, lParam] 1572928 0
[hwnd, lParam] 1902364 0
[hwnd, lParam] 66012 0
[hwnd, lParam] 65936 0
[hwnd, lParam] 1311860 0
[hwnd, lParam] 264564 0
[hwnd, lParam] 65796 0
[hwnd, lParam] 131240 0
...
[hwnd, lParam] 1377560 0
[hwnd, lParam] 65902 0
[hwnd, lParam] 196718 0
[hwnd, lParam] 722088 0
[hwnd, lParam] 264112 0
EnumWindowsProc [External: 1f4a5b35908]
PS C:\Users\Administrator\Desktop\koffi-sample>

以下是带中文注释的代码解释:

这段代码通过 koffi 库在 Node.js 环境中调用 Windows 系统库 user32.dll 的功能,用于枚举所有顶层窗口的句柄。

javascript
// 引入 koffi 库以便调用 Windows 的系统库函数
const koffi = require("koffi");

// 加载 Windows 的 user32.dll,这个库包含操作窗口的函数
const user32 = koffi.load("user32.dll");

// 定义 HANDLE 类型和 HWND 类型,HANDLE 是通用句柄,HWND 是窗口句柄
const HANDLE = koffi.pointer("HANDLE", koffi.opaque());
const HWND = koffi.alias("HWND", HANDLE);

// 定义 EnumWindowsProc 回调函数的签名,使用 int32 替代 HWND 类型来表示窗口句柄
const EnumWindowsProc = koffi.proto(
  "bool __stdcall EnumWindowsProc(int32, int32)" // 签名中使用 int32 表示窗口句柄和附加参数
);

// 定义 EnumWindows 函数,此函数用于枚举所有顶层窗口
const EnumWindows = user32.func("__stdcall", "EnumWindows", "bool", [
  koffi.pointer(EnumWindowsProc), // 指向回调函数的指针
  "int", // 传递给回调函数的附加参数
]);

// 注册回调函数,当 EnumWindows 调用此函数时,打印窗口句柄和 lParam
let cb1 = koffi.register((hwnd, lParam) => {
  console.log("[hwnd, lParam]", hwnd, lParam); // 打印窗口句柄和附加参数
  return true; // 返回 true 继续枚举,返回 false 则停止枚举
}, koffi.pointer(EnumWindowsProc));

// 调用 EnumWindows 函数,开始枚举窗口
EnumWindows(cb1, 0);

// 注销回调函数,释放资源
koffi.unregister(cb1);

// 打印回调函数的签名信息,显示为外部引用
console.log("EnumWindowsProc", EnumWindowsProc);

注释说明

  • 代码修改了回调函数的参数类型,从 HWND 改为 int32,这意味着窗口句柄被处理为普通的 32 位整数,而非特定的指针类型。这样做的目的是为了简化数据处理或适应特定的编程需求。
  • 回调函数打印窗口句柄和 lParam,窗口句柄现在是以整数形式直接打印,而不是作为外部或不透明的指针。

代码执行结果

  • 执行结果显示了多个窗口的句柄和传递的参数(始终为 0),窗口句柄以整数形式展示,符合 int32 类型的期望表现。
  • 这种方式使得处理窗口句柄的数据更为直接,适用于需要以数值方式操作或记录窗口句柄的场景。