像Winspector Spy一样拖放

时间:2010-02-21 19:08:42

标签: c# c++ winapi drag-and-drop

我想知道是否有人能够深入了解如何在Winspector Spy中实现窗口选择器。基本上,我想提供一个我可以鼠标按下的面板,拖动到另一个进程窗口(或子窗口)并从中获取类似HWND的内容。理想情况下,我会在C#中执行此操作,但如果只能通过包装C API来实现,那么我可以在C ++中完成。

我搞乱了DragDrop事件并在C#中用鼠标向下调用DoDragDrop,但我不确定这是否能给我我想要的东西。获取鼠标的全局X / Y位置并找到该位置的最顶层窗口会更容易吗?在给定x,y参数的情况下,是否存在自动执行此操作的API?

编辑:刚刚发现后一个问题的WindowFromPoint

6 个答案:

答案 0 :(得分: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中,Control类有一个Capture属性,可以看到同样的事情 http://msdn.microsoft.com/en-us/library/system.windows.forms.control.capture.aspx

答案 1 :(得分:2)

您需要先考虑如何在窗口周围绘制矩形,这会影响代码的其余部分。最简单的方法是使用将其TransparencyKey设置为其BackColor和FormBorderStyle设置为None的Form。在Paint事件中绘制一个矩形,其大小与窗体的ClientRectangle相同,可以获得一个可见的矩形,其他一切都是透明的。设置表单的Location和Size属性以匹配您找到的窗口。

现在从鼠标位置找到窗口。您不能使用WindowFromPoint(),它不考虑禁用的窗口。你需要使用EnumWindows()。在回调中,调用GetWindowRect()并检查鼠标是否位于矩形内。一定要忽略你的矩形绘图窗口。

当您获得匹配时,现在使用GW_HWNDPREV重复调用GetWindow()以查找与您找到的窗口重叠的窗口。继续检查矩形并不断忽略矩形窗口。

这最终会让您获得鼠标光标所在的顶级窗口。现在使用ChildWindowFromPoint()来检查鼠标是否在子窗口上(如果有)。如有必要,创建矩形绘图表单,并为其指定与找到的窗口相同的大小和位置。

从显示公牛图形的PictureBox的MouseMove事件中调用此代码。在MouseDown事件中将其Capture属性设置为true。

在MouseUp事件中关闭矩形绘图表单的Close()方法。

答案 2 :(得分:1)

由于您已使用C#对此进行了标记,因此我可以为您正在尝试完成的此项工作添加一两个链接,并希望能够为您提供如何实现此目标的必要信息:

以上所有文章都在CodeProject上。

希望这有帮助, 最好的祝福, 汤姆。

答案 3 :(得分:0)

进口: 使用System.Runtime.InteropServices;

我的建议,当鼠标在你的表单上时,处理鼠标移动/鼠标向上事件(使用Windows钩子捕获表单外的鼠标,看看这里: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);
}

现在你有了窗户把手,从那里可以无穷无尽。

注意:上面的链接(窗口挂钩)只有在窗体上出现鼠标时才会起作用,当鼠标抬起时钩子会结束

答案 4 :(得分:0)

简单。您只需在鼠标按下时设置鼠标捕获,即使它们在您自己的窗口之外,您也可以获得所有鼠标消息。然后在鼠标上,使用WindowFromPoint。

我不熟悉.NET,但使用Win32 API,您可以使用SetCapture设置鼠标捕获。

答案 5 :(得分:0)

您可以查看Winspy++的C ++源代码,这是另一个类似于Winspector Spy的窗口检查程序。不过,我不知道这样的任何开源C#程序。