Saturday, July 12, 2008

Disable Close option on system menu for Windows Forms

This article decsribes about how to disable a close option of system menu for a windows form with C#.This can be done by calling win API functions.

First let me explain what 'System menu' is ?

System menu:
-----------------
In windows o/s for any opened window a button is added in the task bar.When clicked on the button the window will be opened if it is minimised and vice versa.When right clicked on task bar button a menu will be opened,technically this menu is know as 'System menu',also called as Window menu'.This menu can also be accesed by by right clicking on title bar of the window & clicking on the icon on title bar of windThis consists menu options like 'Close','Minimise','Maximise','Size','Move','Restore'.All these terms are self explanatory.Check out the image below.


The present article explains about how disable any option in system menu.
Win API provides set of methods to deal with menu & submenus.These methods can be used to modify the menu's.
Following are the winAPI functions needed for requirement
1)GetSystemMenu ---- get access to system menu.
2)EnableMenuItem --- modifies system menu.


To call this methods from C# code .Net framework provides a way called 'Platform Invoke'.

PlatformInvoke:

Platform Invoke concept allows to call methods from managed code which are in unmanaged DLL's. For more information on this ckeck out
"http://msdn.microsoft.com/en-us/library/aa288468.aspx"

To call a method in managed code first that method to be declered with [DLLImport] attribure.This attribute should be applied to methods which are declared in managed code & actually implemented in unmanaged DLL.The code looks like this .

[DllImport("user32.dll")] private static extern IntPtr GetSystemMenu(IntPtr Hmenu, bool Brevert);

Parameters Info:
---first parameter of above function is a handle to window.
---Second parameter must be 'false' so that the menu can be modified.

Note:DllImport atribute takes Dll name as parameter.In our case its 'user32.dll'

[DllImport("user32.dll")] private static extern bool EnableMenuItem(IntPtr Hmenu, uint Uposition, uint UEnable);

Parameters Info:
--Fisrt parameter is the handle to system menu.Its return value of the method 'GetSystemMenu'
--Second parameter specifies the which menu item to be modified.Value of the parameter also depends upon the value of 'UEnable' parameter.
--third parameter is combination of values which indicates whether the menu item is enabled, disabled, or grayed.The combination of possible vales are MF_BYCOMMAND or MF_BYPOSITION and MF_ENABLED, MF_DISABLED, or MF_GRAYED.

MF_BYCOMMAND
Indicates that uIDEnableItem gives the identifier of the menu item. If neither the MF_BYCOMMAND nor MF_BYPOSITION flag is specified, the MF_BYCOMMAND flag is the default flag.
MF_BYPOSITION
Indicates that uIDEnableItem gives the zero-based relative position of the menu item.
MF_DISABLED
Indicates that the menu item is disabled, but not grayed, so it cannot be selected.
MF_ENABLED
Indicates that the menu item is enabled and restored from a grayed state so that it can be selected.
MF_GRAYED
Indicates that the menu item is disabled and grayed so that it cannot be selected.
values for the above constants can be found in winuser.h header file in windows platform SDK.

These declarations to be made in global area of the code part of the form(like form.cs).
After declaring the methods required the next step is to call that method in approptiate place.In this case form load event is appropriate place to call the methods.

//Code in form load
EnableMenuItem(GetSystemMenu(this.Handle, false), SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);

Values for the constants
-------------------------
private const int MF_BYPOSITION = 0x00400;
private const int MF_GRAYED = 0x000001;
private const int MF_ENABLED = 0x000000;
private const int MF_BYCOMMAND = 0x00000;
private const int SC_CLOSE = 0xF060;
private const int SC_SIZE = 0xF000;
private const int SC_MOVE = 0xF010;
private const int SC_MAXIMIZE = 0xF030;

After running the code system menu for the form looks something like this.

No comments: