没有Windows内部的广泛操纵,这是不可能的,您需要克服它。
在日常使用计算机的过程中,有时很重要的一点是您必须先执行一项操作,然后操作系统才能执行另一项操作。为此,它需要将焦点锁定在某些窗口上。在Windows中,对这种行为的控制很大程度上留给了您所使用的各个程序的开发人员。
当涉及到此主题时,并非每个开发人员都会做出正确的决定。
我知道这很令人沮丧和烦恼,但您也不能吃蛋糕。在您的日常生活中,可能有很多情况都很好,您可以将焦点移到某个UI元素或某个应用程序上,要求焦点保持锁定状态。但是,在决定谁现在是领先者方面,大多数应用程序在某种程度上是相等的,并且系统永远不可能是完美的。
前一阵子,我为解决这个问题一劳永逸地进行了广泛的研究(失败了)。我的研究结果可以在烦人的项目页面上找到。
该项目还包括一个应用程序,该应用程序通过调用以下方法反复尝试获取焦点:
switch( message ) {
case WM_TIMER:
if( hWnd != NULL ) {
// Start off easy
// SetForegroundWindow will not move the window to the foreground,
// but it will invoke FlashWindow internally and, thus, show the
// taskbar.
SetForegroundWindow( hWnd );
// Our application is awesome! It must have your focus!
SetActiveWindow( hWnd );
// Flash that button!
FlashWindow( hWnd, TRUE );
}
break;
从该片段中可以看出,我的研究还集中在我不喜欢的用户界面行为的其他方面。
我试图解决此问题的方法是将DLL加载到每个新进程中,并挂接导致另一个窗口被激活的API调用。
最后一部分很简单,这要归功于出色的API挂钩库。我使用了非常好的mhook库:
#include "stdafx.h"
#include "mhook-2.2/mhook-lib/mhook.h"
typedef NTSTATUS( WINAPI* PNT_QUERY_SYSTEM_INFORMATION ) (
__in SYSTEM_INFORMATION_CLASS SystemInformationClass,
__inout PVOID SystemInformation,
__in ULONG SystemInformationLength,
__out_opt PULONG ReturnLength
);
// Originals
PNT_QUERY_SYSTEM_INFORMATION OriginalFlashWindow =
(PNT_QUERY_SYSTEM_INFORMATION)::GetProcAddress(
::GetModuleHandle( L"user32" ), "FlashWindow" );
PNT_QUERY_SYSTEM_INFORMATION OriginalFlashWindowEx =
(PNT_QUERY_SYSTEM_INFORMATION)::GetProcAddress(
::GetModuleHandle( L"user32" ), "FlashWindowEx" );
PNT_QUERY_SYSTEM_INFORMATION OriginalSetForegroundWindow =
(PNT_QUERY_SYSTEM_INFORMATION)::GetProcAddress(
::GetModuleHandle( L"user32" ), "SetForegroundWindow" );
// Hooks
BOOL WINAPI
HookedFlashWindow(
__in HWND hWnd,
__in BOOL bInvert
) {
return 0;
}
BOOL WINAPI
HookedFlashWindowEx(
__in PFLASHWINFO pfwi
) {
return 0;
}
BOOL WINAPI
HookedSetForegroundWindow(
__in HWND hWnd
) {
// Pretend window was brought to foreground
return 1;
}
BOOL APIENTRY
DllMain(
HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
) {
switch( ul_reason_for_call ) {
case DLL_PROCESS_ATTACH:
Mhook_SetHook( (PVOID*)&OriginalFlashWindow, HookedFlashWindow );
Mhook_SetHook( (PVOID*)&OriginalFlashWindowEx, HookedFlashWindowEx );
Mhook_SetHook( (PVOID*)&OriginalSetForegroundWindow, HookedSetForegroundWindow );
break;
case DLL_PROCESS_DETACH:
Mhook_Unhook( (PVOID*)&OriginalFlashWindow );
Mhook_Unhook( (PVOID*)&OriginalFlashWindowEx );
Mhook_Unhook( (PVOID*)&OriginalSetForegroundWindow );
break;
}
return TRUE;
}
从我当时的测试来看,这非常有效。除了将DLL加载到每个新进程中的部分。正如人们可能想象的那样,这一点也不为过。那时我使用了AppInit_DLLs方法(这还远远不够)。
基本上,这很好。但是我从来没有时间写一些可以将我的DLL 正确注入新进程的东西。花在这上面的时间大大掩盖了偷窃焦点给我带来的烦恼。
除了DLL注入问题之外,还有一种窃取焦点的方法,我在Google Code的实现中没有涉及。一位同事实际上做了一些其他研究,并介绍了该方法。在SO上讨论了该问题:https : //stackoverflow.com/questions/7430864/windows-7-prevent-application-from-losing-focus