【问题标题】:Drag and Drop like Winspector Spy像 Winspector Spy 一样拖放
【发布时间】:2011-01-19 09:47:04
【问题描述】:

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

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

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

【问题讨论】:

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


    【解决方案1】:

    进口: 使用 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);
    }
    

    现在您有了窗把手,从那里开始有无限可能。

    注意:上面的链接(windows 钩子)只有在鼠标按下时才起作用,并且当鼠标抬起时钩子结束

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        【解决方案3】:

        当鼠标不在窗口上方时,您通常不会收到鼠标消息。但是您需要这样做才能进行拖放操作。因此,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

        【讨论】:

          【解决方案4】:

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

          【讨论】:

            【解决方案5】:

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

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

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

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

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

            在 MouseUp 事件中关闭矩形绘制窗体的 Close() 方法。

            【讨论】:

              【解决方案6】:

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

              以上所有文章都在 CodeProject 上。

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2023-03-19
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2014-05-04
                • 1970-01-01
                相关资源
                最近更新 更多