C# 如何将我的表格粘贴到第三方申请的窗口?

C# 如何将我的表格粘贴到第三方申请的窗口?,c#,winforms,C#,Winforms,我正试图将我的表单粘贴到另一个应用程序(比如Microsoft Outlook)的窗口。当我移动Outlook窗口时,我的窗体仍应粘贴在它的右侧 目前,我正在while(true)循环(使用sleep())中监视Outlook的位置,并调整窗体的位置以适应它 这里有两个问题: 如果sleep()持续时间太短,那么检查Outlook的位置并经常调整我的表单需要很大的性能 如果sleep() 没有本机解决方案吗?您可以使用任何windows钩子函数WH\u GETMESSAGE,WH\u GET

我正试图将我的表单粘贴到另一个应用程序(比如Microsoft Outlook)的窗口。当我移动Outlook窗口时,我的窗体仍应粘贴在它的右侧

目前,我正在
while(true)
循环(使用
sleep()
)中监视Outlook的位置,并调整窗体的位置以适应它

这里有两个问题:

  • 如果
    sleep()
    持续时间太短,那么检查Outlook的位置并经常调整我的表单需要很大的性能
  • 如果
    sleep()

没有本机解决方案吗?

您可以使用任何windows钩子函数
WH\u GETMESSAGE
WH\u GETMESSAGERET
WH\u SYSMSGFILTER
WH\u MSGFILTER

在这种情况下,您可能会对
WM\u MOVE
WM\u MOVING
感兴趣,其中
WM\u MOVE
是在移动窗口后发送的(也称为完成移动),而
WM\u MOVING
是在移动窗口时发送的(因此您将得到很多这样的信息)

从这里开始阅读:


你必须对这个过程有一个钩子,并倾听这个事件

这应该给你一个很好的起点

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        private const uint WINEVENT_OUTOFCONTEXT = 0x0000;
        private const uint EVENT_OBJECT_LOCATIONCHANGE = 0x800B;

        private const uint EVENT_SYSTEM_MOVESIZESTART = 0x000A;
        private const uint EVENT_SYSTEM_MOVESIZEEND = 0x000B;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            this.Width = 100;
            this.Height = 100;
            this.TopMost = true;
            int processId = Process.GetProcessesByName("OUTLOOK")[0].Id;

            //this will also be triggered by mouse moving over the process windows
            //NativeMethods.SetWinEventHook(EVENT_OBJECT_LOCATIONCHANGE, EVENT_OBJECT_LOCATIONCHANGE, IntPtr.Zero, WinEventProc, (uint)processId, (uint)0, WINEVENT_OUTOFCONTEXT);

            NativeMethods.SetWinEventHook(EVENT_SYSTEM_MOVESIZESTART, EVENT_SYSTEM_MOVESIZEEND, IntPtr.Zero, WinEventProc, (uint)processId, (uint)0, WINEVENT_OUTOFCONTEXT);
        }

        private void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
        {
            Rect move = new Rect();

            if (eventType == EVENT_SYSTEM_MOVESIZESTART)
            {
                NativeMethods.GetWindowRect(hwnd, ref move);

                Debug.WriteLine("EVENT_SYSTEM_MOVESIZESTART");
            }
            else if (eventType == EVENT_SYSTEM_MOVESIZEEND)
            {
                NativeMethods.GetWindowRect(hwnd, ref move);

                Debug.WriteLine("EVENT_SYSTEM_MOVESIZEEND");
            }

            this.Left = move.Left;
            this.Top = move.Top;
        }
    }

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

    static class NativeMethods
    {
        [DllImport("user32.dll")]
        public static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);

        public delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);

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

弗雷多的回答是最正确的

我在应用程序中使用了它,但出现了一个异常“callbackoncollecteddelegate”。 要使其正常工作,有必要在属性上附加WinEventProc

...
private NativeMethods.WinEventDelegate winEventProc;
private void Form1_Load(object sender, EventArgs e)
    {
        this.Width = 100;
        this.Height = 100;
        this.TopMost = true;
        int processId = Process.GetProcessesByName("OUTLOOK")[0].Id;

        //this will also be triggered by mouse moving over the process windows
        //NativeMethods.SetWinEventHook(EVENT_OBJECT_LOCATIONCHANGE, EVENT_OBJECT_LOCATIONCHANGE, IntPtr.Zero, WinEventProc, (uint)processId, (uint)0, WINEVENT_OUTOFCONTEXT);
        this.winEventProc = new NativeMethods.WinEventDelegate(WinEventProc);

        NativeMethods.SetWinEventHook(EVENT_SYSTEM_MOVESIZESTART, EVENT_SYSTEM_MOVESIZEEND, IntPtr.Zero, this.winEventProc, (uint)processId, (uint)0, WINEVENT_OUTOFCONTEXT);
    }
...

请参见

不要在睡眠的while循环中进行调整:使用计时器。另外,在设置属性之前,请先测试位置是否不变。您可以使用SetWinEventHook()、EVENT\u OBJECT\u LOCATIONCHANGE notification来执行此操作。在您的链接问题中可能重复的@MA Maddin与我的问题相当,因为我的问题比我的问题早了2年多。@halloei完全正确,先用另一种方式执行此操作,但后来发现了这个元QA:有没有办法监听事件的大小调整?例如,如果用户将Outlook窗体向下拖动上边框,则只有在完成调整大小后,窗体才会重新定位,因此会出现明显的延迟。