Обработка сообщения 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;
}
Другие вопросы по тегам