C# - 停靠外部应用程序 - 鼠标事件

C# - Docked External application - Mouse events

我有一个 winform 应用程序 (.NET C#)。 我从这个应用程序启动了另一个进程 (notepad.exe) 并将其停靠到我的 window - 类似于此处的操作方式:Docking Window inside another Window.

现在我的问题是,如何 catch/handle 在此停靠应用程序上进行鼠标事件? 我尝试过的:

对于上下文,我想要实现的是在我的鼠标旁边有一个恒定的工具提示,告诉我鼠标相对于面板的位置。请参阅下面的代码:

ToolTip trackTip;
public Form1
{
  trackTip = new ToolTip();
  transparentPanel1.MouseMove += new MouseEventHandler((object s, System.Windows.Forms.MouseEventArgs e) => trackTip.Hide(this));
  transparentPanel1.MouseLeave += new EventHandler(TransparentPanel1_MouseLeave);
}


void TransparentPanel1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
  String tipText = String.Format("({0}, {1})", e.X, e.Y);
  trackTip.Show(tipText, this, e.Location);
}

我找到了一个 viable solution,但是我非常想避免将代码注入到进程中,我觉得好像必须有更好的解决方案来解决我的特定问题。

如果您能给我任何建议,我将不胜感激。我是 .NET 编程新手。

为了参考,我在这里将两个答案合并为一个:

Getting mouse position in c#

How to get window's position?

利用鼠标的全局位置和window的位置我们可以计算出鼠标的相对位置。下面是一些示例代码,其中包含真正基本的边界处理,并且没有针对句柄关闭等的真正错误处理。但应该可以帮助您入门。

首先,基本上是上述答案的副本,引入 windows API 来获取 window 和鼠标位置:

    [StructLayout(LayoutKind.Sequential)]
    public struct POINT
    {
        public int X;
        public int Y;

        public static implicit operator Point(POINT point)
        {
            return new Point(point.X, point.Y);
        }
    }

    [DllImport("user32.dll")]
    public static extern bool GetCursorPos(out POINT lpPoint);

    public static Point GetCursorPosition()
    {
        POINT lpPoint;
        GetCursorPos(out lpPoint);

        return lpPoint;
    }

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr FindWindow(string strClassName, string strWindowName);

    [DllImport("user32.dll")]
    public static extern bool GetWindowRect(IntPtr hwnd, ref Rect rectangle);

    public struct Rect
    {
        public int Left { get; set; }
        public int Top { get; set; }
        public int Right { get; set; }
        public int Bottom { get; set; }
    }

然后是两者之间的一些数学运算:

    public Point GetRelativeMousePosition(IntPtr windowPtr)
    {
        Rect windowPostion = new Rect();
        GetWindowRect(windowPtr, ref windowPostion);
        var mousePosition = GetCursorPosition();

        var result = new Point();
        result.X = mousePosition.X - windowPostion.Left;
        result.Y = mousePosition.Y - windowPostion.Top;

        // set some boundaries so we can't go outside.
        if (result.X < 0)
            result.X = 0;

        var maxWidth = windowPostion.Right - windowPostion.Left;
        if (result.X > maxWidth)
            result.X = maxWidth;

        if (result.Y < 0)
            result.Y = 0;

        var maxHeight = windowPostion.Bottom - windowPostion.Top;
        if (result.Y > maxHeight)
            result.Y = maxHeight;

        return result;
    }

然后把它们放在一起:

    private void Sample()
    {
        Process[] processes = Process.GetProcessesByName("notepad");
        Process lol = processes[0];
        var ptr = lol.MainWindowHandle; // getting this reference is expensive. Better to store and reuse if possible.
        var relativePoint = GetRelativeMousePosition(ptr);
        Console.WriteLine($"relative mouse x:{relativePoint.X} y:{relativePoint.Y}");
    }