Win32 SetForegroundWindow ненадежный
У меня довольно сложная серия приложений, которые зависят от возможности переключения приложений на передний план.
Моя проблема заключается в том, что каждые 5 или 6 раз при переключении приложений на передний план просто не удается отправить приложение вперед. GetLastError не сообщает о каких-либо проблемах. Часто я вижу правильное приложение на переднем плане, а затем отображается предыдущее приложение.
У меня есть приложение-менеджер, для которого у меня есть источник, он порождает и контролирует около 4 приложений, для которых у меня нет источника. одно из приложений, которое оно порождает/контролирует, также является менеджером, который запускает/контролирует около 5 приложений.
Это своего рода дизайн киоска, поэтому у пользователя даже нет клавиатуры или мыши, просто сенсорного экрана.
Я пробовал каждую комбинацию вызовов Win32 для управления ими. Я просто из идей.
Моя первая попытка:
SetWindowPos(hApp, HWND_TOPMOST, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE);
SetWindowPos(hApp, HWND_NOTOPMOST, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE);
Моя вторая попытка:
SetForegroundWindow(hApp);
SetActiveWindow(hApp);
SetFocus(hApp);
моя третья попытка: DWORD dwThreadID = GetWindowThreadProcessId (hApp, NULL); AttachThreadInput (dwThreadID, GetCurrentThreadId(), true);
SetForegroundWindow(hApp);
SetActiveWindow(hApp);
SetFocus(hApp);
AttachThreadInput( dwThreadID, GetCurrentThreadId(), false);
моя четвертая попытка:
DWORD dwThreadID = GetWindowThreadProcessId(hApp, NULL);
AttachThreadInput( dwThreadID, GetCurrentThreadId(), true);
SetWindowPos(hApp, HWND_TOPMOST, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE);
SetWindowPos(hApp, HWND_NOTOPMOST, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE);
SetForegroundWindow(hApp);
SetActiveWindow(hApp);
SetFocus(hApp);
AttachThreadInput( dwThreadID, GetCurrentThreadId(), false);
Я чувствую, что мне не хватает важной информации, когда дело доходит до переключения окон. Я знаю, что только процесс переднего плана может переключать окна, но по мере того, как моя основная программа диспетчера запускается и запускает все остальные процессы, которые мне нужно контролировать, я чувствую, что она должна быть способна перемещать эти окна. Любые предложения или советы приветствуются.
Ответы
Ответ 1
Ваш AttachThreadInput() взломать (я думаю) известный способ победить фокус, крадущий контрмеры в Windows. Вы используете неправильный дескриптор, хотя хотите присоединить к потоку, который в настоящее время имеет фокус. Что не будет hApp, вам не понадобится этот код в противном случае.
Используйте GetForegroundWindow(), чтобы получить дескриптор окна с фокусом.
AttachThreadInput(
GetWindowThreadProcessId(GetForegroundWindow(), NULL),
GetCurrentThreadId(), TRUE
);
Хотя я думаю, что второй аргумент должен быть идентификатором потока hApp. Потому что вы не хотите, чтобы я правильно понял ваше собственное окно. Не уверен, что это может сработать.
Ответ 2
У меня была такая же проблема, и я не хотел испортить нити. При экспериментировании я заметил простой взлом, чтобы сделать работу SetForegroundWindow() ожидаемым образом. Вот что я сделал:
- Свернуть это окно, если оно еще не сведено к минимуму
- Восстановить свернутое окно
- Вызов SetForegroundWindow(), и ваше окно будет наверху
Ответ 3
Некоторые окна заблокированы с помощью setforeground (...),
вам нужно их разблокировать. Эта последовательность полезна в любом окне:
HWND needTopWindow=FindWindow(TEXT("classname"), TEXT("window name"));
имя класса и имя окна, которое вы можете получить с помощью runorexspy, например.
nanoware.cz
if(!::IsWindow(needTopWindow)) return;
BYTE keyState[256] = {0};
//to unlock SetForegroundWindow we need to imitate Alt pressing
if(::GetKeyboardState((LPBYTE)&keyState))
{
if(!(keyState[VK_MENU] & 0x80))
{
::keybd_event(VK_MENU, 0, KEYEVENTF_EXTENDEDKEY | 0, 0);
}
}
::SetForegroundWindow(needTopWindow);
if(::GetKeyboardState((LPBYTE)&keyState))
{
if(!(keyState[VK_MENU] & 0x80))
{
::keybd_event(VK_MENU, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
}
DWORD dwThreadID = GetWindowThreadProcessId(needTopWindow, NULL);
AttachThreadInput( dwThreadID, GetCurrentThreadId(), true);
SetWindowPos(needTopWindow, HWND_TOPMOST, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE);
SetWindowPos(needTopWindow, HWND_NOTOPMOST, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE);
SetForegroundWindow(needTopWindow);
SetActiveWindow(needTopWindow);
SetFocus(needTopWindow);
AttachThreadInput( dwThreadID, GetCurrentThreadId(), false);
Ответ 4
У нас была аналогичная проблема пару лет назад. Мы могли бы решить его следующим вызовом функции:
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0, SPIF_UPDATEINIFILE);
Попробуй. См. Документацию здесь.
Ответ 5
Самое простое решение в С# для вывода окна на передний план:
Как только у вас есть дескриптор окна, вы можете просто вызвать:
SetWindowPos(handle, new IntPtr(0), 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
ShowWindow(handle, 5);
SetForegroundWindow(handle);
// If it is minimized, show the window
if (IsIconic(handle))
{
ShowWindow(handle, 3);
}
где
const int SWP_NOMOVE = 0x0002;
const int SWP_NOSIZE = 0x0001;
const int SWP_SHOWWINDOW = 0x0040;
Ответ 6
Попробуйте сначала нажать другие окна приложения на фон.
Также немного странно, что вы используете SetWindowPos (SWP), чтобы нажимать окно на передний план, а затем выталкивайте его из подписи, прежде чем использовать SetForegroundWindow, чтобы вернуть его обратно. Лично я всегда использовал SWP-метод без каких-либо проблем... но я всегда подталкивал и другие окна на дно.
Ответ 7
Вам также необходимо учитывать вероятность минимизации окна. Если окно или различное приложение сведены к минимуму, то SetForegroundWindow (hApp) не будет работать. Чтобы быть в безопасности, используйте ShowWindow (hApp, 9); Я предпочитаю значение 9. Посмотрите на его документацию и выберите то, что вам подходит.