C# 在C中侦听另一个窗口调整事件大小#
我正在实现一个小应用程序(观察者),它需要将自己“连接”到另一个窗口(观察者)的底部。后者不是应用程序内部的窗口 此时,我通过获取窗口的hWnd并在线程中定期查询观察到的窗口的位置来解决问题,并相应地移动观察者窗口 然而,这是一个非常不雅观的解决方案。我想做的是倾听观察窗口的调整大小事件,以便观察者仅在必要时作出反应 我认为我应该使用一个钩子,我找到了很多方法来实现它,但是我对C WinAPI的缺乏知识阻碍了我理解需要创建哪个钩子以及如何创建钩子(pinvoke/parameters/etc) 我敢肯定,这是一个非常琐碎的问题,一些熟悉C/C++和WinAPI的人会在手边找到答案;) 谢谢一个钩子可能就足够了,这将允许您监视所有发送到感兴趣窗口的消息 <>你问如何用C++创建一个全局钩子,还是你乐意在C++中创建钩子,然后与.NET交互?第二个选择是我要走的路线 基本上在我的脑海里,我会做以下的事情 1-在C中创建全局钩子,并将函数导出到C# 在C中侦听另一个窗口调整事件大小#,c#,resize,hook,C#,Resize,Hook,我正在实现一个小应用程序(观察者),它需要将自己“连接”到另一个窗口(观察者)的底部。后者不是应用程序内部的窗口 此时,我通过获取窗口的hWnd并在线程中定期查询观察到的窗口的位置来解决问题,并相应地移动观察者窗口 然而,这是一个非常不雅观的解决方案。我想做的是倾听观察窗口的调整大小事件,以便观察者仅在必要时作出反应 我认为我应该使用一个钩子,我找到了很多方法来实现它,但是我对C WinAPI的缺乏知识阻碍了我理解需要创建哪个钩子以及如何创建钩子(pinvoke/parameters/etc)
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);
}