2

3 つのアプリケーションを実行している Windows ボックスがあります。アプリケーションが開始されると、各アプリケーションは、特定の方法でオーバーラップするように配置されたボーダレス ウィンドウを作成します。

現時点では、一番下のウィンドウのコントロールをクリックすると、ウィンドウ スタックの一番上に表示されます。

ウィンドウが入力を受け取った場合でも、各ウィンドウがウィンドウ スタック内の順序を維持するようにする必要があります。

ウィンドウの正しい Z オーダーを維持する単純なウィンドウ マネージャーを作成する必要があると考えています。

問題は、特定のウィンドウの位置が変更されたかどうかを知る必要があることです。WM_WINDOWPOSCHANGING メッセージがあることがわかりましたが、このメッセージは位置が変更されたウィンドウに送信されると理解しています。

Z オーダーが変更されたことを何らかの形でウィンドウ マネージャー アプリケーションに通知する必要があります。

すべての WM_ メッセージをキャッチして、そのメッセージが制御したいウィンドウの 1 つに適用されるかどうかを判断する方法はありますか?

4

5 に答える 5

2

実行中の各アプリケーションに DLL を挿入しようとする MSalter のアプローチの代わりに、WH_CBT Windows フックをインストールすることを検討してください。CBTProc で、関心のある 3 つのアプリケーション ウィンドウ ハンドルの HCBT_MOVESIZE を取得したら、0 を返します。

CBTProcおよびSetWindowsHookExに関するドキュメントについては、MSDN を参照してください。

于 2010-02-28T01:36:04.533 に答える
0

John Knoellerの答えに同意すると思います。ウィンドウを特定の z オーダーのままにしたい場合は、この順序を決定し、適切な親子関係を持つウィンドウを作成します。

::SetWindowLong(hwnd_child, GWL_HWNDPARENT, hwnd_parent);

これを行うと、子ウィンドウは常に親の上に表示されます。

それでもメッセージをキャッチする必要がある場合は、各ウィンドウで WM_ACTIVATE をキャッチしてから、そのメッセージをウィンドウ マネージャーに転送してみてください。ウィンドウ マネージャーは、すべてのウィンドウの hwnds にアクセスし、SetWindowPos を使用してそれらを正しく z オーダーします。また、SetWindowPos の代わりに DeferWindowPos を使用して、ウィンドウの z オーダーを一度に変更し、ちらつきを避けることができます。

于 2010-04-29T16:59:20.323 に答える
0

最も簡単な方法は、おそらく 3 つのアプリケーションのそれぞれに DLL を挿入することです。これにより、実際に関心のあるウィンドウ メッセージのサブセットのみを処理する必要があることが保証されます。

EnumWindows()次に、呼び出してすべてのウィンドウを検索し、GetWindowThreadProcessId()それぞれを呼び出して、現在のプロセス (つまり、DLL が挿入されたプロセス) に属しているかどうかを判断することにより、各アプリケーションのメイン ウィンドウを見つけます (完全に自明ではありません。理論的にはもっとある可能性があります) 。 )。

正しい HWND が得られたので、関連する WndProc をフックして、それに送信された WM_WINDOWPOSCHANGING をキャッチできます。

于 2010-02-25T15:12:52.853 に答える
0

上にしたい2つのウィンドウを作成したら、下にしたいウィンドウを にhWndParent値として与えCreateWindowます。下部のウィンドウが前面に表示されると、Windows は常にこれらのウィンドウを前面に表示するため、それらのウィンドウは常に前面に表示されます。

したがって、下のウィンドウがウィンドウ 1 の場合は、最初に作成し、次にウィンドウ 2 と 3 を作成するときに、ウィンドウ 1 のハンドルを hWndParent 値として指定します。ウィンドウマネージャーが残りを行います。

于 2010-02-28T01:01:20.913 に答える
0

SetWindowPos を使用して、ウィンドウを必要な Z オーダーに配置できます。WM_FOCUS メッセージをインターセプトすることをお勧めします (これは、フォーカスを受け取ったときにウィンドウに送信されます)。

あなたの wndProc 関数では、おそらく次のようなことを試すことができます:

LRESULT wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){
    // other stuff..

    switch (msg){
        case WM_FOCUS:
        {
            HWND firstWindow; // get the first window here
            HWND secondWindow; // this would be the second window
            HWND thirdWindow; // this would be the third window
            // TODO: initialize the windows correctly, based on your priority
            SetWindowPos(firstWindow, secondWindow, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE); // position the second window below the first window
            SetWindowPos(secondWindow, thirdWindow, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE); // position the third window below the second window
        }
        return 0;
    }
    // other messages..
}

今はコードをテストできないので、SetWindowPos 引数の順序はよくわかりませんが、これでうまくいくでしょうか?


すべての WM_ メッセージをインターセプトする必要がある場合は、アプリケーションがCreateWindowEx自分自身を呼び出すのではなく (おそらく) 呼び出す Window クラスをお勧めします。例えば:

class Window {
public
    Window(){
        ...
        WNDCLASSEX wc;
        ZeroMemory(&wc, sizeof(WNDCLASSEX));
        wc.cbSize        = sizeof(WNDCLASSEX);
        wc.lpfnWndProc   = wndProc;            // <- Note this one
        ...
    }

    static LRESULT WINAPI wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
        // reference: http://www.gamedev.net/community/forums/topic.asp?topic_id=303854 - Evil Steve  [Moderator]
        Window* parent;

        // Get pointer to window
        if(msg == WM_CREATE){
            parent = (Window*)((LPCREATESTRUCT)lParam)->lpCreateParams;
            SetWindowLongPtr(hwnd,GWL_USERDATA,(LONG_PTR)parent);
        }
        else{
            parent = (Window*)GetWindowLongPtr(hwnd,GWL_USERDATA);
            if(!parent) return DefWindowProc(hwnd,msg,wParam,lParam);
        }
        HWND prev = parent->mWin;
        parent->mWin = hwnd;
        LRESULT ret = parent->wndProc(msg,wParam,lParam);
        parent->mWin = prev;
        return ret;
    }

    virtual LRESULT wndProc(UINT msg, WPARAM wParam, LPARAM lParam){
    }
};

この例では、アプリケーションは Window から継承し、基本的にわずかに変更された wndProc 関数を提供します (HWND がないため、Userdata から取得しない限り、どこかに保存する必要があります)。

  • メッセージを受信するたびに、Window::wndProc(HWND, UINT, WPARAM, LPARAM)関数がそれを取得します。ここで、を含む(ただしこれに限定されない)メッセージのチェックを行うことができますWM_WINDOWPOSCHANGING

  • 他にすべきことは次
    のとおりです。wndProc(UINT, WPARAM, LPARAM)では、 を呼び出す代わりに を呼び出しDefWindowProc(..)
    ますWindow::wndProc(UINT, WPARAM, LPARAM)。次に、代わりにチェックを行うことができます(最初のwndProc関数を詰め込まないように):)

これの欠点は、アプリケーションが他の誰かによって書かれた場合、ウィンドウクラスに準拠する必要があることです。あなたが説明したように、ユーザーはウィンドウマネージャーとやり取りする必要はありませんが、このアプローチでは、ウィンドウマネージャーにユーザーのウィンドウを作成させることが唯一のやり取りになります。
それ以外の場合は、他の回答で説明されているフックを使用する必要があると思います

于 2010-02-25T11:31:20.640 に答える