获取和更改窗体信息

    最近项目中遇到一个问题,即在某些特殊条件下禁止用户最大化窗体(窗体的最大化按钮禁止掉)。实际上这个功能如果在 .net Framework 2.0 或之前的版本中是很容易的,只要设置 Form 的一个属性即可。不过项目使用的是 WPF 技术。这个败家的 WPF 却不提供类似的功能。顺便提一句:WPF 没有提供很多在 .net Framework 2.0 中已经提供的,对程序员来说很实用的功能。不知道是 MS 实现不了呢,还是觉得这些功能根本没有必要提供。
    在网上查了一下,发现实现这个需求还是比较简单的,无论是 WPF 生成的窗体,还是 C# 生成的窗体。只不过 WPF 要实现有点麻烦而已。
    实现这个功能需要两个 API —— GetWindowLong 和 SetWindowLong。
    The GetWindowLong function retrieves information about the specified window. The function also retrieves the 32-bit ( long) value at the specified offset into the extra window memory. If you are retrieving a pointer or a handle, this function has been superseded by the GetWindowLongPtr function. (Pointers and handles are 32 bits on 32-bit Microsoft Windows and 64 bits on 64-bit Windows.) To write code that is compatible with both 32-bit and 64-bit versions of Windows, use GetWindowLongPtr.

    The SetWindowLong function changes an attribute of the specified window. The function also sets the 32-bit (long) value at the specified offset into the extra window memory. Note  This function has been superseded by the SetWindowLongPtr function. To write code that is compatible with both 32-bit and 64-bit versions of Microsoft Windows, use the SetWindowLongPtr function.

    这两个函数中的其它参数就不多说了,这里简单说明一下 nIndex 的意义:Specifies the zero-based offset to the value to be retrieved. Valid values are in the range zero through the number of bytes of extra window memory, minus four; for example, if you specified 12 or more bytes of extra memory, a value of 8 would be an index to the third 32-bit integer. To retrieve any other value, specify one of the following values.(MSDN)

    这个参数值列在下面(后三个值对于对话框有效),具体的意义请参看 MSDN。

#define GWL_WNDPROC         (-4)
#define GWL_HINSTANCE       (-6)
#define GWL_HWNDPARENT      (-8)
#define GWL_STYLE           (-16)
#define GWL_EXSTYLE         (-20)
#define GWL_USERDATA        (-21)
#define GWL_ID              (-12)
#define DWL_MSGRESULT   0
#define DWL_DLGPROC     4
#define DWL_USER        8

    好了,可以开始更改窗体的属性了。不过在更改之前,还有一个工作要做:获取窗体的句柄。C#(或VC++)中,获取指定窗体的句柄简直就是易如反掌,不过在 WPF 下,就不那么容易了,需要一个过渡:

    IntPtr hWnd = new WindowInteropHelper(this).Handle;

    可以获取窗体的显示样式了:

    int nStyle = GetWindowLong(hWnd, GWL_STYLE);

    根据我们的需求,禁止最大化按钮可以被点击,做如下操作即可:

    nStyle &= ~WS_MAXIMIZEBOX;

    重新将更改后的显示样式设置回窗体即可:

    SetWindowLong(hWnd, GWL_STYLE, nStyle);

    好了,似乎工作已经结束了。可惜,运行之后会发现,功能已经实现了,不过窗体上显示的最大化按钮的状态却没有更新。实际上,还需要调用另一个 API —— SetWindowPos 来实现这个功能。

    The SetWindowPos function changes the size, position, and Z order of a child, pop-up, or top-level window. Child, pop-up, and top-level windows are ordered according to their appearance on the screen. The topmost window receives the highest rank and is the first window in the Z order.(MSDN)

    这个函数的语法为:

Syntax

BOOL SetWindowPos(      

    HWND hWnd,     HWND hWndInsertAfter,     int X,     int Y,     int cx,     int cy,     UINT uFlags );

    前几个参数的意义请参看 MSDN。最后一个参数指定了窗体大小和位置的标志。这些标志可以联合使用,进行或操作,具体的意义请参看 MSDN。

#define SWP_NOSIZE          0x0001
#define SWP_NOMOVE          0x0002
#define SWP_NOZORDER        0x0004
#define SWP_NOREDRAW        0x0008
#define SWP_NOACTIVATE      0x0010
#define SWP_FRAMECHANGED    0x0020  /* The frame changed: send WM_NCCALCSIZE */
#define SWP_SHOWWINDOW      0x0040
#define SWP_HIDEWINDOW      0x0080
#define SWP_NOCOPYBITS      0x0100
#define SWP_NOOWNERZORDER   0x0200  /* Don't do owner Z ordering */
#define SWP_NOSENDCHANGING  0x0400  /* Don't send WM_WINDOWPOSCHANGING */

#define SWP_DRAWFRAME       SWP_FRAMECHANGED
#define SWP_NOREPOSITION    SWP_NOOWNERZORDER

#if(WINVER >= 0x0400)
#define SWP_DEFERERASE      0x2000
#define SWP_ASYNCWINDOWPOS  0x4000
#endif /* WINVER >= 0x0400 */

    好了,可以刷新窗体显示样式了:

    SetWindowPos(hWnd, IntPtr.Zero, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED);

    OK,一切大功告成!

    从这个例子可以看出,WPF 的功能还很不完善。虽然 WPF 的界面做的可以说的美轮美奂,不过未来发展的路还很漫长。同时从另一个侧面反应出,Windows 的 API 还是解决问题的根本方法。看来无论什么时候,对 Windows API 的掌握还是很重要的。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值