使用.NET在Windows Vista及更高版本中捕获WndProc消息

thi*_*-Me 0 c# windows wndproc windows-messages windows-7

我有一个.net 2.0 Windows窗体应用程序.

我已经重写了WndProc方法来捕获表单上的用户活动

例如:

const int HTCLOSE           = 0x0014;
bool m_bCloseButtonActive   = false;

if (m.Msg == WM_NCHITTEST)
{
    base.WndProc(ref m);
    m_bCloseButtonActive = (m.Result.ToInt32() == HTCLOSE);
}
Run Code Online (Sandbox Code Playgroud)

基于m_bClos​​eButtonActive的值,我采取进一步的行动.

我现在面临的问题是我的表单没有关闭,因为它无法捕获操作系统Vista及更高版本(甚至是Windows 7)中的关闭按钮单击事件.

即条件m.Result.ToInt32()== HTCLOSE永远不会出现,当我单击关闭按钮时,我的表单永远不会关闭.

我的应用程序适用于以前的操作系统(Windows 2000,XP,XP Embedded).另外一个有趣的事情是它在我指定时有效

Application.VisualStyleState = System.Windows.Forms.VisualStyles.VisualStyleState.ClientAreaEnabled;
Run Code Online (Sandbox Code Playgroud)

有什么想法在这里发生.这是与桌面Windows管理器相关的东西,我的应用程序无法捕获关闭按钮单击事件.

提前致谢

Dav*_*nan 6

在我看来,命中测试消息并不适合这样做.例如,如果用户通过系统菜单或通过Alt + F4快捷方式关闭表单,该怎么办?

我认为你应该回复WM_SYSCOMMAND消息wParam == SC_CLOSE.

Windows Aero在处理非客户端区域方面有着根本的不同,这解释了它在2000/XP和禁用DWM时的工作原理.但是WM_SYSCOMMAND在所有版本的Windows中使用都可以.

请注意,您需要WM_SYSCOMMAND非常仔细地阅读MSDN文档,因为消息参数包含需要屏蔽的额外信息.要检测关闭按钮,您需要这样的代码:

const int WM_SYSCOMMAND = 0x0112;
const int SC_CLOSE = 0xF060;

protected override void WndProc(ref Message m)
{
    if (m.Msg == WM_SYSCOMMAND)
        if ((m.WParam.ToInt32() & 0xFFF0) == SC_CLOSE)
            MessageBox.Show("close button pressed");
    }
    base.WndProc(ref m);
}
Run Code Online (Sandbox Code Playgroud)

如果要在用户关闭表单时更改行为,为什么不处理该Closing事件?