I need to check when a new process with a new visible main window handle is started (as the mouse hook of my app is lost on some applications and is restored only on a short internal restart).
I have tried to use EnumWindows
and EnumDesktopWindows
but those give me many many windows and child windows I do not need. I only need the visible main window handles. Therefore (and to find out if they are belonging to a new process) I decided to directly check the processes within an own update-check-thread. But this approach (as well as to permanently check EnumWindows) is extremely cpu consuming (1-3 % at Ryzen 5600X) and in my opinion, completely overblown.
Therefore I'd like to know if there is any other, slick approach to find out whenever any new process is started or window is opened to only execute the check when it is necessary.
CodePudding user response:
Polling is never a good solution.
If you are already hooking, why not use WH_SHELL
, WH_CBT
or SetWinEventHook()
?
CodePudding user response:
I solved it by using/extracting the ApplicationWatcher
from this Package with minor adjustments to run it within .NET v4.5.2 and to get rid of all unnecessary things.
The application event hook only works for apps/windows which are started after the event hook has been launched which is sufficient for my purposes. If one needs all existing windows as well, you once need to add all existing windows to the activeWindows
property of the ApplicationWatcher
class.
Furthermore, the WindowsActivated
event seems to be bugged. Herefore, you need to adjust the following things:
Within the ApplicationWatcher
class
private void WindowActivated(WindowData wnd) {
if (_ActiveWindows.ContainsKey(wnd.HWnd)) {
if (!_LastEventWasLaunched) { // < if condition adjusted
ApplicationStatus(_ActiveWindows[wnd.HWnd], ApplicationEvents.Activated);
}
}
_LastEventWasLaunched = false;
}
and within the ShellHook
class
protected override void WndProc(ref Message m) {
if (m.Msg == _wmShellHook) {
switch ((User32.ShellEvents)m.WParam) {
...
case User32.ShellEvents.HSHELL_RUDEAPPACTIVATED: // < line added
case User32.ShellEvents.HSHELL_WINDOWACTIVATED:
if (WindowActivated != null) {
WindowActivated.Invoke(this, m.LParam);
}
break;
}
}
base.WndProc(ref m);
}
Works like a charme and my CPU usage went down to 0 %.