Disabling the Window Close Button and System Close menu in a Windows Form

Ran into one of those common scenarios today where you have to dive into P/Invoke land for something that should be a lot easier to do than it is. Requirement was to disable the Window close button while a processing thread was active, re-enable when the processing thread was stopped. Found a nice solution through Google on Cory Smith’s blog. Ported the code to C# and encapsulated as part of the form instead of a separate class with a little clean up of the API declaration types. The basic steps to re-use are below. You could also make this a base class type that derives from Form that you then derive your form classes from, but then you have to deal with the IDE designer going stupid sometimes.

This is the kind of silliness that comes up all the time in real apps that I hope goes away in Longhorn since the OS API is all managed. One would expect to see these kinds of capabilities exposed as part of the Form class or its equivalent in Avalon.

Basic steps are to bring in the APIs and constants as part of the form class and wrap toggling the enabled state of the close command with a property (that should have been a member of the base Form class!!).


// Declare P/Invoke methods


[DllImport(“user32”)]


private

staticextern IntPtr GetSystemMenu(IntPtr hWnd, int revert);
[DllImport(“user32”)]


private

staticexternint EnableMenuItem(IntPtr hWndMenu, int itemID, int enable);
// Declare constants to pass to the methods


private

constint SC_CLOSE = 0xF060;
private

constint MF_ENABLED = 0;
private

constint MF_GREYED = 1;
private

constint MF_BYCOMMAND = 0;
// Declare a flag to track the enabled state


private

bool m_bCloseEnabled = true;
private

System.Windows.Forms.Button btnToggleState; // default for WinForms
public

bool CloseEnabled
{

get
{

// Return the internal flag state
return m_bCloseEnabled;
}

set
{

// Decide on the state to pass based on the value being set
int setting;
if (value) // Enabling
{

setting = MFBYCOMMAND | MFENABLED;

}

else
{

setting = MFBYCOMMAND | MFGREYED;

}

// Make the update
EnableMenuItem(GetSystemMenu(

this.Handle,0),SCCLOSE,setting);
// Update the internal flag state
m
bCloseEnabled =

value;
}

}


Then added a handler for the SizeChanged event to handle minimize/maximize redrawing of the menu to reset the state to the internally maintained state:


private

void OnSizeChanged(object sender, System.EventArgs e)
{

// Reset the state with the internally maintained state
CloseEnabled = m_bCloseEnabled;

}




Then you can simply set the state of the CloseEnabled property whenever you want to change the state of the close button.