web-dev-qa-db-ja.com

Win32:ウィンドウを上に移動

2つのウィンドウが2つあるWindowsプログラムがあります。

hwnd (main interface)

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

Hwndをダブルクリックすると、hwnd2がポップアップしていくつかのデータを表示する必要があるため、この関数を使用してhwnd2を先頭に表示します。

BringWindowToTop(hwnd2);

hwnd2がトップになりましたが、奇妙なことが1つあります。もう一度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は複数のウィンドウで構成されるメディアプレーヤーです。ウィンドウの1つはビデオ表示用で、他の2つのトラックバーコントロールはプログレスバーとボリュームバー用、1つはコントロールパネル用のツールバーコントロールです。)

(これが役立つ可能性のあるウィンドウが1つあります。hwnd2をクリックしたウィンドウに関係なく、hwndはメニューバーや非クライアント領域など、「マウスがZオーダーでhwndの上にある」のと同じくらい長くポップアップします。)

(このメディアプレーヤーはダイレクトショーで記述されています。私はIVideoWindow :: put_Ownerを使用してビデオウィンドウをビデオ所有者として配置します。ダイレクトショーは内部的にサブビデオウィンドウをビデオウィンドウの子として作成します。このサブビデオウィンドウを除き、私はソースコードを見ることができず、hwnd2で疑わしいものは何もありません。)

その理由を見つけました、それはダイレクトショーのためです。マルチスレッドを使用して実行すると、問題は解決します。しかし、なぜ??

この問題は、(SendMessageではなく)PostMessageを使用して解決できます。

31
KenC

これを試してください、それは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);
19
bowman han

両方とも素晴らしい:

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

しかし、最後のものはウィンドウを常に一番上に置くことを覚えておいてください。

13
Nuno

SwitchToThisWindow が最適です。

8
scottm

SwitchToThisWindow()は非推奨ではありません。
私は本番環境で14年間使用しています。
Windowsのソースコードを見ると、どこからでも呼び出されていることがわかります...

5
john

多くの試行錯誤の後、私はこの問題の次の解決策を見つけました:

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
bronze man

あなたは試しましたSetActiveWindow()

4
ralphtheninja