Umgang mit Aerosnap -Nachricht in WndProc
-
26-10-2019 - |
Frage
In meiner C# .NET 4 -Anwendung verwende ich WndProc
Um einige Nachrichten zu verarbeiten, die sich hauptsächlich mit der Änderung der Anwendung von und vom Vollbildmodus befassen.
Im Moment handle ich nur SC_MAXIMIZE
und WM_NCLBUTTONDBLCLK
Um festzustellen, ob das Fenster in oder von einem maximierten Zustand geändert wird (ich weiß, ich brauche keine WndProc, um zu handhaben SC_MAXIMIZE
, aber Form_Resize
schien nicht für a zu feuern WM_NCLBUTTONDBLCLK
Nachricht Wenn ich auf die Titelleiste der Anwendung doppelklicke.
Jetzt bemerkte ich, dass, wenn ich das Fenster zum oberen Rand des Bildschirms schnappe, um es zu maximieren, keine der oben genannten Nachrichten veröffentlicht wird, sodass die Logik nicht angewendet wird, wenn das Fenster über Aero Snap maximiert wird. Ich möchte die Nachricht nur verarbeiten, wenn das Fenster an die Oberseite des Bildschirms und nicht nach rechts oder links geschnappt wird oder wenn ein Fenster von der maximierten Position entnommen wird.
Ich konnte keine der Fenstermeldungen finden, die sich auf Aero Snap beziehen. Kennt jemand irgendwelche Referenzen für diese Nachrichten?
Lösung
Ich vermute, hier gibt es keine besonderen Nachrichten. Aero verwendet wahrscheinlich nur die einfachen Win32 -APIs - ShowWindow (sw_maximize) und ähnlich.
Die Sache, mit den SC_ -Nachrichten zu verstanden, ist, dass dies sind Anfragen aus einem Menü Fragen Sie das Fenster, um die Größe/Wiederherstellung/etc selbst zu ändern, aber dies ist nicht der einzige Mechanismus, um die Größe des Fensters zu ändern. Was wahrscheinlich passiert, ist, dass das DefwndProc dies, wenn ein Fenster sc_maximize erhält, dies implementiert, indem er ShowWindow (SW_MAXIMIMISE) aufruft.
Ihr Bestes ist es, dem zu hören Wm_size Nachricht, die das Fenster empfängt, unabhängig davon, was die Größenänderung ausgelöst hat: Systemmenü, API oder andere Mittel. Insbesondere das LPARAM lässt Sie wissen, ob das Fenster maximiert wurde (size_maximized) oder restauriert (size_restored).
Andere Tipps
Hier ist der Code für die Handhabung Wm_windowposchanging Nachricht für maximieren statt maximieren Wm_size Botschaft. Vielen Dank an die 20 oder mehr Fragen zu, damit ich lesen musste, um alle Teile zu finden, um sie zusammenzustellen und zum Laufen zu bringen. Dies befasst sich mit den Problemen, die ich mit mehreren Monitoren mit unterschiedlichen Auflösungen hatte.
//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;
}