Це неможливо без обширних маніпуляцій із внутрішніми системами Windows, і вам потрібно це подолати.
Бувають моменти щоденного використання комп’ютера, коли дійсно важливо зробити одну дію, перш ніж операційна система дозволить зробити іншу. Для цього потрібно заблокувати фокус на певних вікнах. У Windows контроль над такою поведінкою значною мірою залишається розробникам окремих програм, якими ви користуєтесь.
Не кожен розробник приймає правильні рішення, коли йдеться про цю тему.
Я знаю, що це дуже засмучує і дратує, але ти не можеш торт і їсти його теж. Напевно, є багато випадків у вашому повсякденному житті, коли ви прекрасно справляєтеся з тим, що фокус переміщується на певний елемент інтерфейсу або програму, яка вимагає, щоб фокус залишався заблокованим. Але більшість застосувань дещо рівні, коли справа стосується того, щоб вирішити, хто зараз ведучий, і система ніколи не може бути ідеальною.
Деякий час тому я робив великі дослідження щодо вирішення цього питання раз і назавжди (і не вдалося). Результат мого дослідження можна знайти на сторінці проекту роздратування .
Проект також включає додаток, який неодноразово намагається захопити фокус, зателефонувавши:
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