2010-02-21 90 views
5

我想知道是否有人可以提供有關如何在Winspector Spy中實現窗口選擇器的見解。基本上,我想提供一個面板,可以將鼠標拖放到另一個進程窗口(或子窗口),並從HWND中取出某個面板。理想情況下,我會在C#中執行此操作,但如果只能通過封裝C API來實現,那麼我可以用C++來完成。拖放像Winspector Spy

我搞砸了DragDrop事件,並在C#中的鼠標下調用DoDragDrop,但並不確定如果這可以給我我想要的。只需獲取鼠標的全局X/Y位置並在該位置找到最頂層的窗口,會更容易嗎?有沒有一個API可以自動爲我給出x,y參數?

編輯:剛發現WindowFromPoint對於後一個問題

回答

5

當鼠標不在窗口上時,您通常不會收到鼠標消息。但是你需要爲了做拖放操作。所以,Windows提供了一種稱爲鼠標捕獲的機制。爲了防止鼠標捕捉被濫用,您只能在按下按鈕的消息上捕捉鼠標。捕獲完成後,無論鼠標在屏幕上的什麼位置,您都可以獲得鼠標移動消息,直到您釋放捕獲或Windows看到相應的按鈕向上消息。

這樣做的C++代碼看起來是這樣的

case WM_LBUTTONDOWN: 
    { 
    SetCapture(hwnd); 
    } 
    break; 

case WM_MOUSEMOVE: 
    if (GetCapture() == hwnd) 
     { 
     POINT pt = {GET_MOUSE_X(lParam), GET_MOUSE_Y(lParam)); 
     ClientToScreen(hwnd, &pt); 
     HWND hwndAtPoint = WindowFromPoint(pt); 
     // Show info for hwndAtPoint.... 
     } 
    break; 

    case WM_LBUTTONUP: 
    if (GetCapture() == hwnd) 
     { 
     ReleaseCapture(); 
     } 
    break; 

    case WM_CANCELMODE: 
    // this is a request from Windows that leave my modal state 
    if (GetCapture() == hwnd) 
     ReleaseCapture(hwnd); 
    break; 

    case WM_CAPTURECHANGED: 
    // notification that I lost capture (I released it or it was taken from me) 
    break;  

GetAncestor功能可以幫助從窗口走在點,爲擁有它的頂層窗口。 GetWindow可用於在窗口樹周圍走動。

在.NET中,控制類有做同樣的事情看 http://msdn.microsoft.com/en-us/library/system.windows.forms.control.capture.aspx

+0

這太棒了 - 非常感謝。 – 2010-02-21 21:44:36

0

進口: 使用System.Runtime.InteropServices;

我的建議是,當鼠標在你的窗體上時,處理鼠標移動/鼠標上移事件(使用窗口鉤子在窗體外捕獲鼠標,看這裏:http://support.microsoft.com/kb/318804),當鼠標按鈕釋放,讓屏幕上的鼠標位置,並得到光標後的窗口,使用您提供這樣的鏈接:

[DllImport("user32.dll")] 
public static extern IntPtr WindowFromPoint(Point lpPoint); 
[DllImport("user32.dll")] 
public static extern bool GetCursorPos(out Point lpPoint); 
public static IntPtr GetWindowUnderCursor() 
{ 
    Point ptCursor = new Point(); 
    if (!(PInvoke.GetCursorPos(out ptCursor))) 
     return IntPtr.Zero; 
    return WindowFromPoint(ptCursor); 
} 

現在,你有你的窗口句柄,從那裏的可能性是無限的。

注意:上面的鏈接,(窗鉤)如果按下鼠標出現在表單上,​​當鼠標被提起

0

簡單掛鉤結束才起作用。您只需在鼠標上設置鼠標捕捉,即使它們位於您自己的窗口之外,也可以獲得所有鼠標消息。然後在鼠標上,使用WindowFromPoint。

我對.NET不熟悉,但使用Win32 API時,您使用SetCapture來設置鼠標捕獲。

0

你可以看一下C++源Winspy++,類似於Winspector間諜另一個窗口檢查程序捕獲性質。不過,我不知道任何這樣的開源C#程序。

2

您需要考慮如何首先在窗口周圍繪製矩形,這會影響到代碼的其餘部分。最簡單的方法是使用將其TransparencyKey設置爲其BackColor和FormBorderStyle設置爲None的Form。在Paint事件中繪製一個矩形,其大小與表單的ClientRectangle相同,從而爲您提供一個可見的矩形,其中一切都是透明的。設置窗體的位置和大小屬性以匹配您找到的窗口。

現在從鼠標位置找到窗口。你不能使用WindowFromPoint(),它不考慮禁用的窗口。你需要使用EnumWindows()。在回調中,調用GetWindowRect()並檢查鼠標是否位於矩形內。一定要忽略你的矩形繪圖窗口。

當你得到一個匹配時,現在使用GW_HWNDPREV重複調用GetWindow()來找到與你找到的窗口重疊的窗口。繼續檢查矩形並保持忽略矩形窗口。

這最終會讓您成爲鼠標光標所在的頂層窗口。現在使用ChildWindowFromPoint()檢查鼠標是否在子窗口上,如果有的話。如有必要,創建您的矩形圖形式,並將其與所找到的窗口大小和位置相同。

從MouseMove事件中調用此代碼,例如顯示一個公牛眼圖形的PictureBox。在其MouseDown事件中將其Capture屬性設置爲true。

在MouseUp事件中關閉矩形圖形式的Close()方法。