3

特定のウィンドウがデスクトップの境界内にあるかどうかを判断するコードを書きました。
どういうわけか、うまくいきません。デスクトップの内側か外側かに関係なく、すべてのウィンドウに対してfalseが返されます。ここで何かがひどく間違っていますが、このコードを 3 時間見つめた後でも、どこに問題があるのか​​ わかりません。PMSG の WPARAM で送信されたポインターから RECT 構造体を読み取ろうとすると、AccessViolationException が発生します。なぜこうなった?

私のコードは次のようになり、常に false を返します。

static bool IsInBounds(HWND window)
{
    DEVMODE d;
    d.dmSize = sizeof(DEVMODE);
    BOOL b = EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &d);
    if(b == FALSE)
    {
        PostMessage(FindWindow(NULL, L"Window #1"), RegisterWindowMessage(L"FMSG"), (WPARAM)window, NULL);
    }
    RECT R;
    GetWindowRect(window, &R);
    POINT p = POINT();
    p.x = (LONG)d.dmPelsWidth;
    p.y = (LONG)d.dmPelsHeight;
    PostMessage(FindWindow(NULL, L"Window #1"), RegisterWindowMessage(L"PMSG"), (WPARAM)&R, d.dmPelsWidth);
    if(R.right < 0 || R.bottom < 0 || R.left > (LONG)d.dmPelsWidth || R.top > (LONG)d.dmPelsHeight)
    {
        return false;
    }
    return true;
}

編集: IsInBounds を呼び出した後、エラー番号 1400 (無効なウィンドウ ハンドル) が返されましたが、フック コールバックから戻る前にIsWindow(window)、ハンドルがまだ有効かどうかを確認するために を呼び出しました。真実は、実際には有効なハンドルです! GetWindowRect が無効なハンドルだと言うのはどうしてでしょうか?

編集:私は、監視されたように MonitorFromWindow を試しましたが、NULL を返し、GetLastError を呼び出すとエラー番号が発生しました。もうおなじみの1400。MonitorFromWindow が暗黙的に GetWindowRect を呼び出しているようです。サイズは気にしませんが、ハンドルからウィンドウ座標を取得する別の方法はありますか?

4

3 に答える 3

4

PostMessage(FindWindow(NULL, L"Window #1"), RegisterWindowMessage(L"PMSG"), (WPARAM)&R, d.dmPelsWidth);「ウィンドウ #1」が別のプロセスにある場合は機能しません。RECT ポインター クロス プロセスを渡すだけではいけません。ポインター クロス プロセスよりも大きなものを渡す必要がある場合は、WM_COPYDATA を使用してください。クロス プロセスではない場合でも、SendMessage ではなく PostMessage を使用しているという事実は、メッセージが処理されるまでに RECT がおそらく範囲外であることを意味します。

EnumDisplaySettings を使用するのは少しやり過ぎです。MONITOR_DEFAULTTONULLを指定した MonitorFromWindow で十分です。

于 2011-01-22T17:46:21.370 に答える
3

(1) わかりやすい

RECT rDesk = { 0 };
GetBystemParametersInfo(SPI_GETWORKAREA, 0, &rDesk, 0);
RECT rWnd;
GetWindowRect(wnd, &rWnd);
POINT pttl = { rWnd.left, rWnd.top);
POINT ptbr = { rWnd.right, rWnd.bottom);
if (PtInRect(&rDesk, pttl) && PtInRect(&rDesk, ptbr)) 
   // ....

SPI_GETWORKAREA は、(タスクバーなどを含む画面ではなく) デスクトップ領域を照会しますGetMonitorInfo 。複数のモニターをサポートするには、GetSystemParametersInfo を置き換えます。

(2) GetWindowRect
ターゲット ウィンドウは昇格されたプロセスに属しているか、または別のセキュリティ コンテキストで実行されているプロセスに属しているか。

(3) その他の注意事項
には、 そのRegisterMessageような一意でない名前を使用しないでください。結局のところ、システム全体で機能します。名前に GUID を埋め込むようにしています。

PostMessage は既に言及されています。これは非同期であり、ポインターをクロスプロセスで渡すことができます。

ウィンドウハンドルを他の無関係なウィンドウに渡す必要がある理由がわかりません。

于 2011-01-22T21:19:12.613 に答える
2

PostMessage()は非同期であり、関数のローカル変数へのポインターを送信しています ( RECT R)。そのローカル変数は、受信者がメッセージの処理に取り掛かるまでになくなる可能性が最も高いです。

また、戻り値をチェックして、GetWindowRect()失敗していないことを確認する必要があります。

EnumDisplaySettings()もう1つ、失敗した場合はおそらく戻る必要があります。16 行目のテストは、入力されていなければDEVMODE d意味がありません。

于 2011-01-22T17:59:22.413 に答える