Обработка сообщения AeroSnap в WndProc
В моем приложении C# .NET 4 я использую WndProc
обрабатывать некоторые сообщения, в основном связанные с изменением размера приложения на весь экран и обратно.
Сейчас я просто справляюсь SC_MAXIMIZE
а также WM_NCLBUTTONDBLCLK
чтобы определить, изменяется ли окно до или из развернутого состояния (я знаю, что мне не нужен WndProc для обработки SC_MAXIMIZE
, но Form_Resize
не похоже на огонь WM_NCLBUTTONDBLCLK
сообщение, когда я дважды щелкаю по строке заголовка приложения.
Теперь я заметил, что если я Aero Snap окно в верхней части экрана, чтобы развернуть его, ни одно из вышеперечисленных сообщений не публикуется, поэтому определенная логика не применяется, когда окно развернуто через Aero Snap. Я хочу обработать сообщение только в том случае, если окно привязано к верхней части экрана, а не вправо или влево, или если окно отсоединено от максимизированной позиции.
Я не смог найти ни одного сообщения окна, связанного с Aero Snap. Кто-нибудь знает какие-либо ссылки на эти сообщения?
2 ответа
Я предполагаю, что здесь нет никаких специальных сообщений; Aero, скорее всего, просто использует простые API Win32 - ShowWindow (SW_MAXIMIZE) и тому подобное.
Что нужно понять в сообщениях SC_, так это то, что это запросы из меню, запрашивающие у окна изменение размера / восстановления / и т.д., но это не единственный механизм изменения размера окон. Вероятно, происходит то, что когда окно получает SC_MAXIMIZE, DefWndProc реализует это, вызывая ShowWindow(SW_MAXIMIZE).
Лучше всего слушать сообщение WM_SIZE, которое получает окно, независимо от того, что вызвало изменение размера: системное меню, API или другие средства. В частности, lParam сообщит вам, было ли окно развернуто (SIZE_MAXIMIZED) или восстановлено (SIZE_RESTORED).
Вот код для обработки сообщения WM_WINDOWPOSCHANGING для Максимизировать вместо сообщения WM_SIZE. Спасибо за 20 или более вопросов по SO, которые мне пришлось прочитать, чтобы найти все кусочки, чтобы собрать и заставить работать. Это решает проблемы, которые у меня были с несколькими мониторами, использующими разные разрешения.
//register the hook
public static void WindowInitialized(Window window)
{
IntPtr handle = (new WindowInteropHelper(window)).Handle;
var hwndSource = HwndSource.FromHwnd(handle);
if (hwndSource != null)
{
hwndSource.AddHook(WindowProc);
}
}
//the important bit
private static IntPtr WindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case 0x0046: //WINDOWPOSCHANGING
var winPos = (WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(WINDOWPOS));
var monitorInfo = new MONITORINFO();
IntPtr monitorContainingApplication = MonitorFromWindow(hwnd, MonitorDefaultToNearest);
GetMonitorInfo(monitorContainingApplication, monitorInfo);
RECT rcWorkArea = monitorInfo.rcWork;
//check for a framechange - but ignore initial draw. x,y is top left of current monitor so must be a maximise
if (((winPos.flags & SWP_FRAMECHANGED) == SWP_FRAMECHANGED) && (winPos.flags & SWP_NOSIZE) != SWP_NOSIZE && winPos.x == rcWorkArea.left && winPos.y == rcWorkArea.top)
{
//set max size to the size of the *current* monitor
var width = Math.Abs(rcWorkArea.right - rcWorkArea.left);
var height = Math.Abs(rcWorkArea.bottom - rcWorkArea.top);
winPos.cx = width;
winPos.cy = height;
Marshal.StructureToPtr(winPos, lParam, true);
handled = true;
}
break;
}
return (IntPtr)0;
}
//all the helpers for dealing with this COM crap
[DllImport("user32")]
internal static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi);
[DllImport("user32")]
internal static extern IntPtr MonitorFromWindow(IntPtr handle, int flags);
private const int MonitorDefaultToNearest = 0x00000002;
[StructLayout(LayoutKind.Sequential)]
public struct WINDOWPOS
{
public IntPtr hwnd;
public IntPtr hwndInsertAfter;
public int x;
public int y;
public int cx;
public int cy;
public int flags;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class MONITORINFO
{
public int cbSize = Marshal.SizeOf(typeof(MONITORINFO));
public RECT rcMonitor;
public RECT rcWork;
public int dwFlags;
}
[StructLayout(LayoutKind.Sequential, Pack = 0)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}