C# 在C中侦听另一个窗口调整事件大小#

C# 在C中侦听另一个窗口调整事件大小#,c#,resize,hook,C#,Resize,Hook,我正在实现一个小应用程序(观察者),它需要将自己“连接”到另一个窗口(观察者)的底部。后者不是应用程序内部的窗口 此时,我通过获取窗口的hWnd并在线程中定期查询观察到的窗口的位置来解决问题,并相应地移动观察者窗口 然而,这是一个非常不雅观的解决方案。我想做的是倾听观察窗口的调整大小事件,以便观察者仅在必要时作出反应 我认为我应该使用一个钩子,我找到了很多方法来实现它,但是我对C WinAPI的缺乏知识阻碍了我理解需要创建哪个钩子以及如何创建钩子(pinvoke/parameters/etc)

我正在实现一个小应用程序(观察者),它需要将自己“连接”到另一个窗口(观察者)的底部。后者不是应用程序内部的窗口

此时,我通过获取窗口的hWnd并在线程中定期查询观察到的窗口的位置来解决问题,并相应地移动观察者窗口

然而,这是一个非常不雅观的解决方案。我想做的是倾听观察窗口的调整大小事件,以便观察者仅在必要时作出反应

我认为我应该使用一个钩子,我找到了很多方法来实现它,但是我对C WinAPI的缺乏知识阻碍了我理解需要创建哪个钩子以及如何创建钩子(pinvoke/parameters/etc)

我敢肯定,这是一个非常琐碎的问题,一些熟悉C/C++和WinAPI的人会在手边找到答案;)

谢谢

一个钩子可能就足够了,这将允许您监视所有发送到感兴趣窗口的消息

<>你问如何用C++创建一个全局钩子,还是你乐意在C++中创建钩子,然后与.NET交互?第二个选择是我要走的路线

基本上在我的脑海里,我会做以下的事情

1-在C中创建全局钩子,并将函数导出到
InstallHook
UninstallHook
,可以使用Interop从C应用程序调用这些函数。InstallHook在C#应用程序中获取窗口的hwnd

2-如果您的案例中有您感兴趣的消息,如
WM#u SIZE
,请让已安装的hook函数将自定义消息发布到调用
InstallHook
中提供的C#窗口

3-在C#应用程序中,从钩子接收已发布消息的窗口将重写以处理自定义消息


这是一种方法的概述。

扩展了Chris Taylor的答案:您可以使用包含
Hook
类的

编辑:使用ManagedWinApi。在代码中的某个地方:

Hook MyHook = new Hook(HookType.WH_CALLWNDPROC, false, false);
MyHook.Callback += MyHookCallback;
MyHook StartHook();
对于回调,请参考和:


我建议您使用WinEvents:

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

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

另请参见:

我在使用的某些代码中遇到了相同的问题,并发现我无法将托管.DLL注入进程

< >不想编写使用StWistWOWSRead的C++非托管DLL,我用“代码> StWiNeVeSooOK 定时器< /代码>在移动窗口时轮询窗口,使窗口在移动时呈现窗口。 下面是一个可以做到这一点的类的(非常简化的)版本(只需将TODO替换为移动窗口或引发事件的代码)


标题和标签中只提到了C。你用的是C#还是C?@Yuvi,我猜他想听听C#中的一个“事件”,它是在另一个应用程序中触发的,而不是在他的“域”。@Yuvi我提到C#,因为我的基本程序是用C#编写的。对于商务应用程序来说,使用C++是不太舒服的;的确,我偶然发现了ManagedWinAPi,但这些文档并不像我希望的那样自我解释,因为我在WinAPI中的无能。我正在研究这些例子以得到它。据我所知,我并不真正需要一个全局系统hoow,因为直接连接到窗口就足够了。我只需要得到有关调整大小/移动事件的通知。理想情况下,这应该发生在C#事件中。我需要弄清楚的是如何将这些点连接起来,因此任何建议都是非常受欢迎的,特别是熟悉ManagedWinApi的人。谢谢!这非常清楚。我会尽快测试它。作为参考,这里是CWPSTRUCT,您建议的代码仅用于C#项目中的窗口。我需要挂一个外窗。通过谷歌搜索,我明白这在C#中似乎是不可能的,除非Magadewinapi有办法做到这一点。我试图将钩子构造函数中的全局参数设置为true,但我的会话失败了。有什么建议吗?@Steve这个钩子适用于同一个应用程序中的windows(它们不必是C#windows)。至于跨进程钩子,我不确定它是如何与“全局”一起工作的(到目前为止还不需要它)。由于安全原因,您在较新的Windows版本中可能也会遇到问题…@SteveVedovelli是否为您提供了其他答案?我正在寻找和你一样的东西——当外部窗口被调整大小时,可以钩住它进行处理。我确信这是可行的。我刚刚利用SetWinEventHook编写了一个程序。非常方便用户共享!谢谢!
public delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);

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

    private readonly IntPtr m_target;

    // Needed to prevent the GC from sweeping up our callback
    private readonly WinEventDelegate m_winEventDelegate;
    private IntPtr m_hook;

    private Timer m_timer;

    public DockingHelper(string windowName, string className)
    {
        if (windowName == null && className == null) throw new ArgumentException("Either windowName or className must have a value");

        m_target = FindWindow(className, windowName);
        ThrowOnWin32Error("Failed to get target window");

        m_threadId = GetWindowThreadProcessId(m_target, out m_processId);
        ThrowOnWin32Error("Failed to get process id");

        m_winEventDelegate = WhenWindowMoveStartsOrEnds;
    }

    [DllImport("user32.dll", SetLastError = true)]
    private static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);

    [DllImport("user32.dll", SetLastError = true)]
    private static extern bool UnhookWinEvent(IntPtr hWinEventHook);

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

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport("user32.dll", SetLastError = true)]
    private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

    private void ThrowOnWin32Error(string message)
    {
        int err = Marshal.GetLastWin32Error();
        if (err != 0)
            throw new Win32Exception(err, message);
    }

    private RECT GetWindowLocation()
    {
        RECT loc;
        GetWindowRect(m_target, out loc);
        if (Marshal.GetLastWin32Error() != 0)
        {
            // Do something useful with this to handle if the target window closes, etc.
        }
        return loc;
    }

    public void Subscribe()
    {
        // 10 = window move start, 11 = window move end, 0 = fire out of context
        m_hook = SetWinEventHook(10, 11, m_target, m_winEventDelegate, m_processId, m_threadId, 0);
    }

    private void PollWindowLocation(object state)
    {
        var location = GetWindowLocation();
        // TODO: Reposition your window with the values from location (or fire an event with it attached)
    }

    public void Unsubscribe()
    {
        UnhookWinEvent(m_hook);
    }

    private void WhenWindowMoveStartsOrEnds(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
    {
        if (hwnd != m_target) // We only want events from our target window, not other windows owned by the thread.
            return;

        if (eventType == 10) // Starts
        {
            m_timer = new Timer(PollWindowLocation, null, 10, Timeout.Infinite);
            // This is always the original position of the window, so we don't need to do anything, yet.
        }
        else if (eventType == 11)
        {
            m_timer.Dispose();
            m_timer = null;
            var location = GetWindowLocation();
            // TODO: Reposition your window with the values from location (or fire an event with it attached)
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct RECT
    {
        public int Left, Top, Right, Bottom;
    }

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