2016-05-25 10 views
8

デスクトップ上の特定のポイントの下にあるすべてのトップレベルウィンドウ(デスクトップの子)を検索したい。私はこのためのAPIを見つけることができません。ポイントの下にあるすべてのウィンドウを見つける

私のシナリオでは、ウィンドウをドラッグして別の(既知の)ウィンドウにドロップしたいというシナリオです。ターゲットウィンドウの境界をテストしてもOKですが、別の(未知の)ウィンドウによって隠されているかどうかはわかりません。 WindowFromPointを使用すると、友だちは機能しません。ドラッグされているウィンドウがマウスの真下にあるからです。だから私はマウスの位置ですべてのウィンドウを取得することができますか、私が追跡しているウィンドウの1つが私がドラッグしているウィンドウの直下にあるかどうかを確認するためにそれらを見直すのだろうかと思います。

すべてのマウスドラッグでEnumDesktopWindows/GetWindowRectに頼らずにこれを行う方法はありますか?あるいは、私にはもう一つの解決策がありません。

+1

あなたがドラッグしている間は、新しいウィンドウが作成されませんという仮定を加えた場合は、一度トップレベルウィンドウを列挙することができますドラッグ操作の開始点を指定し、その結果を使用して、ドラッグ中にマウスが移動するたびにテストします。 –

+0

それは調査する価値のある最適化です、ありがとうございます。 –

+0

'GetNextWindow'を使って、Zオーダーのあなたのターゲットの上にあるウィンドウを見るだけで逃げることができます。 – theB

答えて

4

親切に質問すると、WindowFromPointはあなたのウィンドウ(現在ドラッグされているウィンドウ)を無視し、次のウィンドウを返します。これは、タブをドラッグしたときにInternet Explorerが実行する動作です。その行うには

:ウィンドウに

  1. がハンドルWM_NCHITTESTは、ドラッグ中に戻りHTTRANSPARENT
  2. をドラッグされています。それ以外の場合は、デフォルトのウィンドウprocを呼び出します。
  3. WindowFromPointwill ignoreHTTRANSPARENTウィンドウですが、呼び出しスレッドに属するものだけです。とにかくウィンドウ所有者スレッドからWindowFromPointを呼び出す必要があるため、これは問題ではありません。
  4. WindowFromPointに渡されたポイントに子ウィンドウがないことを確認するか、これらの子ウィンドウに対してもWM_NCHITTESTを処理します。

トラブルあなたはhwndパラメータが何を得る等しいことを正しいスレッド

  • WM_NCHITTESTで、テストから呼び出していることを確認するために

    1. テストGetCurrentThreadID() == GetWindowThreadProcessId(WindowFromPoint(), 0)(あなたはまだWindowFromPointからあなたの窓を取得する場合)からWindowFromPoint()

    (長方形内の面積がWindowFromPointから基礎となるウィンドウを返す):

    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 
    { 
        static const RECT s_TransparentRect = {100, 100, 200, 200}; 
    
        switch (message) 
        { 
        case WM_NCCREATE: 
         SetTimer(hWnd, 1, 100, 0); 
         break; 
        case WM_TIMER: 
         { 
          POINT cursorPos; 
          GetCursorPos(&cursorPos); 
    
          TCHAR buffer[256]; 
          _snwprintf_s(buffer, _countof(buffer), _TRUNCATE, _T("WindowFromPoint: %08X\n"), (int)WindowFromPoint(cursorPos)); 
          SetWindowText(hWnd, buffer); 
         } 
         break; 
        case WM_PAINT: 
         { 
          PAINTSTRUCT ps; 
          BeginPaint(hWnd, &ps); 
          Rectangle(ps.hdc, s_TransparentRect.left, s_TransparentRect.top, s_TransparentRect.right, s_TransparentRect.bottom); 
          EndPaint(hWnd, &ps); 
         } 
         break; 
        case WM_NCHITTEST: 
         { 
          POINT cursorPos; 
          GetCursorPos(&cursorPos); 
          MapWindowPoints(HWND_DESKTOP, hWnd, &cursorPos, 1); 
    
          if (PtInRect(&s_TransparentRect, cursorPos)) 
           return HTTRANSPARENT; 
         } 
         break; 
        } 
    
        return DefWindowProc(hWnd, message, wParam, lParam); 
    } 
    
  • +0

    ありがとうございました。これは、繰り返される(トップレベルウィンドウの数が線形)API呼び出しを避けることを約束します。実験してお返しします。 –

    +0

    もう一度ありがとうございます。いくつかの実験で、これはかなりうまくなりました。 –

    +0

    私は言及しなかった追加の手順が必要でしたか? – Codeguard

    3

    あなたは、戻ってきたWindowFromPoint()が何をドラッグしているのか知っています。次に、uCmd = GW_HWNDNEXTのGetWindow()を使用して、Zオーダーでその下にあるものを取得します。 GetWindowRect()はその境界を取得し、IntersectRect()はオーバーラップを計算します。

    GetWindow()を呼び出して、重複している可能性のあるウィンドウをさらに探してください。それがNULLを返すか、重なりが十分になるまで。そうでなければ、通常、IntersectRect()からの最大の結果矩形を持つものを優先します。

    +0

    これをスピンして、矩形のヒットテストでは不十分であることがわかりました。デスクトップには、ユーザーの視点から見えないにもかかわらず、取得されるウィンドウがたくさんあります。たとえば、タイトルが「AXWINフレームウィンドウ」のウィンドウが表示され、無意味な(ex)スタイルがあります。可視性をテストする他の手段がありますか?矩形のテストは、レイヤードウィンドウでも失敗する可能性があります。 –

    +0

    IsWindowVisible()のテストを追加してください –

    +0

    ありがとう、それはうまくいくようです。私のマシンでのスキャンは、サブミリ秒で実行されます。これは素晴らしい方法です。それでも透明領域を持つレイヤードウィンドウでは失敗します。 –

    関連する問題