从 Node-JS 将焦点设置到 Windows 应用程序
Posted
技术标签:
【中文标题】从 Node-JS 将焦点设置到 Windows 应用程序【英文标题】:Setting focus to a Windows application from Node-JS 【发布时间】:2017-01-18 03:58:05 【问题描述】:我有一个在 Windows 上运行的 NodeJS 应用程序,当用户执行特定操作时,它需要显示并将焦点切换到正在运行的 Windows 应用程序。我一直在使用 node-ffi 包进行 Windows API 调用,但无法使其始终如一地切换焦点。这是我正在使用的代码。它成功获取了正在运行的计算器应用程序的 HWND,但随后尝试将焦点切换到该 HWND,但它仅在某些时候有效:
var ffi = require('ffi');
var intPtr = ref.refType('long');
var user32 = new ffi.Library('user32',
'FindWindowA': ['long', [ 'string', 'string']],
'SetForegroundWindow': ['bool', ['long']],
'BringWindowToTop': ['bool', ['long']],
);
var winToSetOnTop = user32.FindWindowA(null,"calculator")
var res = user32.ShowWindow(winToSetOnTop, 9);
res = user32.SetForegroundWindow(winToSetOnTop);
res = user32.BringWindowToTop(winToSetOnTop);
这种命令组合似乎是我尝试过的最一致的命令,但它并不总是有效。如果我想切换焦点的窗口被最小化,它总是会弹出到顶部。如果窗口没有最小化,而只是在另一个窗口后面,它只会间歇性地显示。我不确定如何始终如一地让正在运行的 Windows 应用程序始终移动到顺序的顶部,即使它当前已最小化。
【问题讨论】:
你说两个,它总是适用于最小化的窗口,以及它不能始终如一地工作。哪一个是真的? 您不检查错误。阅读 SetForegroundWindow 的文档,尤其是条件列表。 @IInspectable 它将始终将最小化的窗口带到顶部。如果一个窗口没有最小化,而只是在另一个窗口的后面,它只会间歇性地把它带到顶部。 【参考方案1】:我制定了以下解决方案,该解决方案在所有情况下都能很好地将窗口置于顶部。首先,它将获取 Calculator 应用程序正在运行的实例的窗口句柄,然后将其带到顶部并聚焦。
var ffi = require('ffi-napi')
var user32 = new ffi.Library('user32',
'GetTopWindow': ['long', ['long']],
'FindWindowA': ['long', ['string', 'string']],
'SetActiveWindow': ['long', ['long']],
'SetForegroundWindow': ['bool', ['long']],
'BringWindowToTop': ['bool', ['long']],
'ShowWindow': ['bool', ['long', 'int']],
'SwitchToThisWindow': ['void', ['long', 'bool']],
'GetForegroundWindow': ['long', []],
'AttachThreadInput': ['bool', ['int', 'long', 'bool']],
'GetWindowThreadProcessId': ['int', ['long', 'int']],
'SetWindowPos': ['bool', ['long', 'long', 'int', 'int', 'int', 'int', 'uint']],
'SetFocus': ['long', ['long']]
);
var kernel32 = new ffi.Library('Kernel32.dll',
'GetCurrentThreadId': ['int', []]
);
var winToSetOnTop = user32.FindWindowA(null, "calculator")
var foregroundHWnd = user32.GetForegroundWindow()
var currentThreadId = kernel32.GetCurrentThreadId()
var windowThreadProcessId = user32.GetWindowThreadProcessId(foregroundHWnd, null)
var showWindow = user32.ShowWindow(winToSetOnTop, 9)
var setWindowPos1 = user32.SetWindowPos(winToSetOnTop, -1, 0, 0, 0, 0, 3)
var setWindowPos2 = user32.SetWindowPos(winToSetOnTop, -2, 0, 0, 0, 0, 3)
var setForegroundWindow = user32.SetForegroundWindow(winToSetOnTop)
var attachThreadInput = user32.AttachThreadInput(windowThreadProcessId, currentThreadId, 0)
var setFocus = user32.SetFocus(winToSetOnTop)
var setActiveWindow = user32.SetActiveWindow(winToSetOnTop)
【讨论】:
在哪里可以找到有关 user32 api 的更多信息? @PauloHenrique Wiki 条目en.wikipedia.org/wiki/Windows_USER 提供了一些关于 user32.dll 的高级信息。如需更深入地了解,您可以查看 Windows API 下的 MSDN。我的解决方案中使用的大多数函数的文档都可以在“Windows”部分找到:msdn.microsoft.com/en-us/library/windows/desktop/…。否则,WINAPI 编程是一个很深的黑洞,要了解更多信息,我会找到一个介绍性指南,其中有很多,以便了解一些 Windows 操作系统概念、数据结构等。 提供给FindWindowA
的值是进程的TITLE。
对AttachThreadInput
的调用非常不合适。如果有的话,您必须在调用SetForegroundWindow
之前调用它之前(以建立该调用成功的先决条件)。调用AttachThreadInput
有fairly severe consequences。这一切似乎都是基于猜测。如果你不知道为什么你的代码有效,那它就不会。这里也是如此。
@Luke: FindWindow 获取窗口标题和/或窗口类名。这些都与进程名称无关。以上是关于从 Node-JS 将焦点设置到 Windows 应用程序的主要内容,如果未能解决你的问题,请参考以下文章
如何在 lambda 中使用 node-js 将我的文件添加到现有的 zip 文件夹?