Я столкнулся с тем же самым в некотором коде, с которым работал, и обнаружил, что не могу внедрить управляемый .DLL в процесс.
Не желая писать неуправляемую DLL на C ++, которая использовала бы SetWindowsHook, я выбрал комбинацию SetWinEventHook
, которая сигнализирует, когда окно начинается и заканчивается событием перемещения, и Timer
, чтобы опросить окно во время его перемещения, чтобы это появление следования за окном, пока оно движется.
Вот (очень упрощенная) версия класса, которая может это сделать (просто замените TODO кодом для перемещения окна или создания события).
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);
}