Win32: вывести окно наверх - PullRequest
31 голосов
/ 27 мая 2009

У меня есть программа для Windows, в которой есть два окна:

hwnd (main interface)

hwnd2 (toplevel window, no parent, created by hwnd)

Когда я дважды щелкаю на hwnd, мне нужен hwnd2, чтобы всплыть и показать некоторые данные, поэтому я использую эту функцию, чтобы вывести hwnd2 вверх:

BringWindowToTop(hwnd2);

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

SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
                                                                  //doesn't work

BringWindowToTop(hwnd2);    //This is the function brings hwnd2 to top

SetForegroundWindow(hwnd2); //doesn't work

SetWindowPos(hwnd2, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); 
                                                                  //doesn't work

SetWindowPos(hwnd2, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
                                       // hwnd2 "always" on top, not what I want

SetActiveWindow(hwnd2); // doesn't work too (for replying to Magnus Skog, thanks)

SwitchToThisWindow(hwnd2, TRUE);// got the same problem with BringWindowToTop function
SwitchToThisWindow(hwnd2, FALSE);

Как я мог решить эту проблему? Заранее спасибо.

(для ответа на aJ у hwnd2 нет родителя, потому что это должно быть окно верхнего уровня, чтобы оно могло быть впереди / сзади других окон)

(hwnd2 - медиаплеер, состоящий из нескольких окон, одно из которых предназначено для отображения видео, два других элемента управления трекбара для индикатора выполнения и панели громкости, один элемент управления панели инструментов для панели управления.)

(есть один, который может помочь, независимо от того, какое окно я нажимаю на hwnd2, hwnd автоматически появляется как «мышь находится над hwnd в Z-порядке», включая строку меню и не-клиентскую область, и др.)

(Этот медиапроигрыватель записывается в Direct Show. Я использую IVideoWindow :: put_Owner, чтобы поместить видеоокно в качестве владельца видео, Direct Show внутренне создает субэлемент видео как дочерний элемент видеоокна. За исключением этого субэлемента. окно видео, в котором я не вижу исходный код, я не вижу ничего подозрительного в hwnd2.)

Я нашел причину, которая связана с Direct Show. Я использую многопоточность, чтобы выполнить его, и тогда проблема решена. Но ... почему ??

Эта проблема может быть решена с помощью PostMessage (а не SendMessage).

Ответы [ 7 ]

19 голосов
/ 22 декабря 2015

попробуйте это, как говорят, приходит от M $

    HWND hCurWnd = ::GetForegroundWindow();
    DWORD dwMyID = ::GetCurrentThreadId();
    DWORD dwCurID = ::GetWindowThreadProcessId(hCurWnd, NULL);
    ::AttachThreadInput(dwCurID, dwMyID, TRUE);
    ::SetWindowPos(m_hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
    ::SetWindowPos(m_hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
    ::SetForegroundWindow(m_hWnd);
    ::AttachThreadInput(dwCurID, dwMyID, FALSE);
    ::SetFocus(m_hWnd);
    ::SetActiveWindow(m_hWnd);
13 голосов
/ 21 апреля 2012

Оба прекрасно работают:

::SetForegroundWindow(wnd)

или

::SetWindowPos(m_hWnd,       // handle to window
            HWND_TOPMOST,  // placement-order handle
            0,     // horizontal position
            0,      // vertical position
            0,  // width
            0, // height
            SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE// window-positioning options
            );

Но помните, что последний устанавливает окно всегда сверху.

8 голосов
/ 27 мая 2009

SwitchToThisWindow работает лучше всего для меня.

5 голосов
/ 28 мая 2009

SwitchToThisWindow () вообще не рекомендуется.
Я использую его 14 лет в производственной среде.
Посмотрите исходный код Windows, и вы увидите, что он называется везде ...

4 голосов
/ 05 декабря 2017

После многих попыток и ошибок. Я нашел следующее решение этой проблемы:

SendMessage(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0); // restore the minimize window
SetForegroundWindow(hwnd); 
SetActiveWindow(hwnd); 
SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE  | SWP_NOSIZE);
//redraw to prevent the window blank.
RedrawWindow(hwnd, NULL, 0, RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN );

HWND - это ваш Windows HWND. Пожалуйста, не просто копируйте и вставляйте. Вам также нужно использовать GetLastError для проверки ошибки API после каждого вызова API.

У меня есть следующий результат на моей win7:

  • Может восстановить окно свёртывания и нет ошибок.
  • Если окно уже расположено сверху, заголовок окна будет мигать, и ошибки не будет.
  • Если окно закрылось, оно вернет ошибку «0x578 Неверный дескриптор окна.»
  • Это может привести окно к вершине во всех не самых верхних окнах и не возвращать ошибки (например, это будет позади самого верхнего менеджера задач)
  • Это не делает окно самым верхним. Пользователь может сделать другое окно поверх него.
4 голосов
/ 27 мая 2009

Вы пробовали SetActiveWindow () ?

0 голосов
/ 25 июня 2015

// отлично работает!

Var
 WndHandle:HWND;

begin
 WndHandle :=FindWindowEx(0,0,nil,'Calculator');
 PostMessage(WndHandle,WM_SHOWWINDOW,SW_RESTORE,0);
 SetForegroundWindow(WndHandle);
end; 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...