5

在我的 C# .NET 4 应用程序中,我WndProc用来处理一些消息,主要是处理将应用程序大小调整为全屏和全屏。

现在我只是在处理SC_MAXIMIZEWM_NCLBUTTONDBLCLK确定窗口是否被调整为最大化状态或从最大化状态(我知道我不需要 WndProc 来处理SC_MAXIMIZE,但是当我双击时Form_Resize似乎没有触发消息WM_NCLBUTTONDBLCLK应用程序的标题栏。

现在我注意到,如果我将窗口 Aero Snap 到屏幕顶部以最大化它,则上述消息都不会发布,因此当通过 Aero Snap 最大化窗口时不会应用某些逻辑。如果窗口被捕捉到屏幕顶部而不是右侧或左侧,或者如果窗口未从最大化位置捕捉,我只想处理该消息。

我找不到任何与 Aero Snap 相关的窗口消息。有谁知道这些消息的任何参考?

4

2 回答 2

6

我猜这里没有任何特殊信息;Aero 可能只是使用普通的 Win32 API - ShowWindow(SW_MAXIMIZE)和类似的。

SC_ 消息要理解的是,这些是来自菜单的请求,要求窗口调整大小/恢复/等本身,但这不是改变窗口大小的唯一机制。可能发生的情况是,当窗口获得 SC_MAXIMIZE 时,DefWndProc 通过调用 ShowWindow(SW_MAXIMIZE) 来实现这一点。

最好的办法是收听窗口接收到的WM_SIZE消息,无论是什么触发了大小更改:系统菜单、API 或其他方式。特别是,lParam 会让您知道窗口是最大化 (SIZE_MAXIMIZED) 还是恢复 (SIZE_RESTORED)。

于 2012-02-17T02:25:50.560 回答
2

这是处理WM_WINDOWPOSCHANGING消息的代码最大化而不是WM_SIZE消息。感谢关于 SO 的 20 个或更多问题,我必须阅读这些问题才能找到将其组合在一起并使其正常工作的所有内容。这解决了我在使用不同分辨率的多台显示器时遇到的问题。

//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;
}
于 2014-03-06T05:52:33.083 回答