Подтвердить что ты не робот

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);

Я чувствую, что мне не хватает важной информации, когда дело доходит до переключения окон. Я знаю, что только процесс переднего плана может переключать окна, но по мере того, как моя основная программа диспетчера запускается и запускает все остальные процессы, которые мне нужно контролировать, я чувствую, что она должна быть способна перемещать эти окна. Любые предложения или советы приветствуются.

4b9b3361

Ответ 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. Посмотрите на его документацию и выберите то, что вам подходит.