I have a NodeJS application running on Windows that needs to display and switch the focus to a running Windows application when a user does a certain action. I have been using the node-ffi package to make windows API calls but have not been able to make it switch focus consistently. Here is the code I am using. It successfully gets the HWND of a running Calculator app, but then tries to switch focus to that HWND and it only works sometimes:
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);
This combination of commands seems to work most consistently of the ones I have tried, but it does not work all the time. If the window I want to switch focus to is minimized it will always pop to the top. If the window is not minimized, but just behind another window, it will only be shown intermittently. I am not sure how to consistently to get a running windows application to always move to the top of the order, even if it is currently minimized.
I have a NodeJS application running on Windows that needs to display and switch the focus to a running Windows application when a user does a certain action. I have been using the node-ffi package to make windows API calls but have not been able to make it switch focus consistently. Here is the code I am using. It successfully gets the HWND of a running Calculator app, but then tries to switch focus to that HWND and it only works sometimes:
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);
This combination of commands seems to work most consistently of the ones I have tried, but it does not work all the time. If the window I want to switch focus to is minimized it will always pop to the top. If the window is not minimized, but just behind another window, it will only be shown intermittently. I am not sure how to consistently to get a running windows application to always move to the top of the order, even if it is currently minimized.
Share Improve this question asked Sep 9, 2016 at 23:37 KeithTheBipedKeithTheBiped 8821 gold badge10 silver badges22 bronze badges 3- You say both, that it always works for minimized windows as well as, that it doesn't work consistently. Which one is true? – IInspectable Commented Sep 10, 2016 at 0:18
- You don't check for errors. Read the docs for SetForegroundWindow especially the list of conditions. – David Heffernan Commented Sep 10, 2016 at 7:21
- @IInspectable It will always bring a minimized window to the top. If a window is not minimized, but is only behind another window, it will only bring it to the top intermittently. – KeithTheBiped Commented Sep 12, 2016 at 14:30
1 Answer
Reset to default 19I've worked out the following solution which works well in all circumstances to bring a window to the top. First it will get the window handle to a running instance of the Calculator application, then it will bring it topmost and focus it.
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)