【问题标题】:Handling AeroSnap message in WndProc在 WndProc 中处理 AeroSnap 消息
【发布时间】:2012-02-17 01:07:18
【问题描述】:

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

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

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

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

【问题讨论】:

  • 我也想知道这一点......但是我一直无法弄清楚。

标签: c# winapi aero window-messages


【解决方案1】:

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

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

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

【讨论】:

  • 这是正确的。 Aero Snap 不会发送任何特殊通知。它使用标准的WM_MOVING/WM_MOVEWM_SIZING/WM_SIZE 消息。如果您在没有调用DefWindowProc 的情况下处理这些,Aero Snap 将不适用于您的窗口。是的,您可以收听WM_SIZE,但通常使用WM_WINDOWPOSCHANGED 可能会更好。这是一个“新”功能,是在 Windows 3.1 中引入的。 :-) Relevant reading.
  • POSCHANGED 的问题是你可以得到它来进行 any 移动/大小更改,包括在“捕捉”之前移动窗口时,所以你需要做更多的过滤。而且我不知道您是否可以根据其参数确定最大化“捕捉” - 没有明显的“窗口已最大化”指示器。使用 WM_SIZE,检查 lParam 就完成了!
  • 是的,你需要做一些过滤。这基本上是不可避免的,您必须过滤 WM_SIZE 以确保您只处理由 Aero Snap 发起的调整大小事件。关键是您所有的处理代码都在一个地方。我真的看不出你的WM_WINDOWPOSCHANGED消息处理程序中的switch语句和你的窗口过程中处理WM_MOVEWM_SIZE等的switch语句之间的区别。我想很好权力带来重大责任;任何一个都可以。
  • 您能建议什么过滤可以与 WM_WINDOWPOSCHANGED 一起使用吗?它似乎在较低级别上工作,因此您知道确切的窗口位置以及是否有框架,但“最大化”的高级语义似乎不存在。因此,如果您想专门检查最大化/恢复事件,WM_SIZE 似乎是最好的事件。 (在回答之前我确实查看了 WM_WINDOWPOSCHANGED,并认为它不是解决这个特定问题的正确工具;WM_SIZE 似乎更适合/更简单。)
  • 这个答案是不正确的,除了WM_SIZE可以用来检测新尺寸的小部分。 “捕捉”和“最大化”不是一回事:IsZoomed(hwnd) 返回 false。窗口的系统菜单显示Maximize 和Minimize 均已启用,但Restore 未启用,因为该窗口处于正常/已恢复状态。 WM_SIZE 是用 SIZE_RESTORED 接收的,而不是 SIZE_MAXIMIZED。
【解决方案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;
}

【讨论】:

  • 赞成纯粹是因为您的评论“所有帮助处理这个 COM 废话”...
猜你喜欢
  • 2010-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-30
  • 1970-01-01
  • 2012-02-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多