2016-05-25 12 views
8

Ich möchte alle Top-Level-Fenster (Kinder des Desktops) unter einem bestimmten Punkt auf dem Desktop finden. Ich kann keine API dafür finden.Finden Sie alle Fenster unter einem Punkt

Mein Szenario ist, dass ich ein Fenster über den Bildschirm ziehe und es in ein anderes (bekanntes) Fenster fallen lassen möchte. Ich kann die Grenzen des Zielfensters testen, aber das sagt mir nicht, ob es durch ein anderes (unbekanntes) Fenster verdeckt ist. Die Verwendung von WindowFromPoint und Freunden funktioniert nicht, weil das Fenster, das gezogen wird, notwendigerweise direkt unter der Maus ist. Ich frage mich also, ob ich alle Fenster an der Mausposition abrufen kann, und überprüfe sie, ob eines der Fenster, die ich verfolge, direkt unter dem Fenster liegt, das ich ziehe.

Gibt es eine Möglichkeit, dies ohne Rückgriff auf EnumDesktopWindows/GetWindowRect auf jeden Mauswiderstand zu tun? Oder vielleicht gibt es eine andere Lösung, die ich vermisse.

+1

Wenn Sie davon ausgehen, dass keine neuen Fenster erstellt wird, während Sie ziehen, können Sie die Top-Level-Fenster einmal aufzuzählen bei Beginnen Sie mit dem Ziehen, und verwenden Sie dann das Ergebnis, um bei jeder Mausbewegung während des Ziehens zu testen. –

+0

Das ist eine Optimierung, die es wert ist, untersucht zu werden, danke. –

+0

Sie können vielleicht mit 'GetNextWindow' durchkommen und nur die Fenster über Ihrem Ziel in der Z-Reihenfolge betrachten. – theB

Antwort

4

Wenn Sie freundlich fragen, ignoriert WindowFromPoint Ihr Fenster (das gerade gezogen wird) und das nächste Fenster zurück. Dies ist, was Internet Explorer tut, wenn Sie eine Registerkarte ziehen.

, das zu tun:

  1. Griff WM_NCHITTEST in Fenster gezogen
  2. Return wird HTTRANSPARENT während ziehen. Rufen Sie andernfalls das Standard-Fenster-Proc auf.
  3. WindowFromPointwill ignoreHTTRANSPARENT Fenster, aber nur diejenigen, die zum aufrufenden Thread gehören. Dies sollte kein Problem für Sie sein, da Sie sowieso aus dem Fenstereigenthread WindowFromPoint aufrufen sollten.
  4. Stellen Sie sicher, dass keine untergeordneten Fenster an Punkt an WindowFromPoint übergeben werden, oder behandeln Sie WM_NCHITTEST für diese untergeordneten Fenster.

Fehlerbehebung

  1. -Test GetCurrentThreadID() == GetWindowThreadProcessId(WindowFromPoint(), 0) (wenn Sie noch Ihre Fenster aus WindowFromPoint erhalten), um sicherzustellen, dass Sie von den richtigen Thread sind Aufruf
  2. In WM_NCHITTEST, Test, dass hwnd Parameter gleich, was man bekommt von WindowFromPoint()

Beispiel (der Bereich innerhalb des Rechtecks ​​gibt das zugrunde liegende Fenster aus 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

Vielen Dank. Dies verspricht, wiederholte (lineare Anzahl von Top-Level Windows) API-Aufrufe zu vermeiden. Wird experimentieren und zu dir zurückkommen. –

+0

Danke nochmal. Mit etwas Experimentieren ist das ganz gut gelungen. –

+0

Brauchst du irgendwelche zusätzlichen Schritte, die ich nicht erwähnt habe? – Codeguard

3

Richtig, Sie wissen bereits, was WindowFromPoint() zurückgeben wird, sollte derjenige sein, den Sie ziehen. Dann verwenden Sie GetWindow() mit uCmd = GW_HWNDNEXT, um den darunter in der Z-Reihenfolge zu erhalten. GetWindowRect(), um seine Grenzen zu erhalten, IntersectRect(), um die Überlappung zu berechnen.

Rufen Sie GetWindow() auf, um weitere Fenster zu finden, die möglicherweise überlappt werden. Bis es NULL zurückgibt oder die Überlappung gut genug ist. Wenn nicht, dann bevorzugen Sie normalerweise denjenigen mit dem größten Ergebnisrechteck von IntersectRect().

+0

Nahm dies für eine Drehung und fand, dass ein Treffer beim Testen des Rechtecks ​​nicht ausreicht. Es gibt viele Fenster auf dem Desktop, die abgeholt werden, obwohl sie aus der Sicht des Benutzers nicht sichtbar sind. Zum Beispiel erscheint ein Fenster mit dem Titel 'AXWIN Frame Window' mit unschuldig genug (ex) Styles. Gibt es andere Möglichkeiten, die Sichtbarkeit zu testen? Das Testen des Rechtecks ​​kann auch für geschichtete Fenster fehlschlagen. –

+0

Hinzufügen eines Tests auf IsWindowVisible() –

+0

Danke, das scheint gut zu funktionieren. Das Scannen auf meiner Maschine läuft in einer Millisekunde, was großartig ist. Dennoch scheitert es für Schichtfenster mit transparenten Bereichen. –

Verwandte Themen