# VBForums CodeBank > CodeBank - Visual Basic .NET >  Disable Close Button and Prevent Form Being Moved

## jmcilhinney

C# version here.

*SystemMenuManager class* - A helper class that you can add an instance of to a form and remove the Move item from the system menu, which renders the form immoveable by the user, and/or disable or remove the Close item, which also disables the Close button on the title bar.  When the Close item is disabled or removed the Alt+F4 key combination is also disabled.  To use this class just add a single line of code similar to this to your form:
VB.NET Code:
Private myMenuManager As New SystemMenuManager(Me, False, SystemMenuManager.MenuItemState.Greyed)
Note that it does not affect any other items on the system menu as these should be accessed through properties of the form itself.  Also, the Move item can only be removed as disabling it or greying it out seem to have no effect.

EDIT: I've taken the code from post #39 and incorporated it into a class that I've attached to this post.  You can use this class to make your form immovable like so:
vb.net Code:
Private immobiliser As New FormImmobiliser(Me)
EDIT (8-Jan-2009): I've updated the code for the FormImmobiliser class so it's now a bit simpler and it also addresses a few issues that the old code had.

----------


## RobDog888

Nice code John. Good job.  :Wink:  Its about time MS added the EnableMenuItem API.  :Wink: 

Probably would be better if it was a prublic function in a class somewhere so you can call it throughout your project.  :Smilie:

----------


## jmcilhinney

Thanks Rob.  You give good rep.  :Wink:   I've come from a C++ background so the succincter (sic) the code the better.  I love that C code that does about fifty things in one line and there are more dots and arrows than other characters.  :Sick:

----------


## RobDog888

> Thanks Rob.  You give good rep.   I've come from a C++ background so the succincter (sic) the code the better.  I love that C code that does about fifty things in one line and there are more dots and arrows than other characters.


I know what you mean. I hate to write many lines of simple code when you can usually nest function calls inside of each other, etc.  :Thumb: 's again.

----------


## RobDog888

Hey, John. What about using MF_DISABLED instead of MF_GRAYED?

----------


## RobDog888

I tested it both ways and its not the same. The MF_GRAYED disables the 'x' AND the system menu Close item, but the MF_DISABLED constant only disables the 'x' and leaves the Close system menu item looking enabled but is actualy disabled.

----------


## Pythagoras

How about disabling the ALT+F4?

----------


## RobDog888

To disable that keypress sequence I believe you would have to create a WndProc to handle the message stream for that form and intercept the WM_CLOSE message and beable to determine from the lPram and wPram that it is not closing via the code but rather attempting to close from the ALT+F4.  :Wink:

----------


## anna7

thanks for this code! I needed it  :Thumb:  


Bye,  :wave:  

Anna

----------


## anna7

i have one small problem. When I maximize o minimize the form, close button turns enabled.  :Confused:

----------


## JuggaloBrotha

> i have one small problem. When I maximize o minimize the form, close button turns enabled.


in the form's ReSize event put jmcilhinney's code in so it'll re-disable the form's titlebar close button

----------


## anna7

ok! Now run perfectly  :Smilie:

----------


## jmcilhinney

Attached is a helper class that you can use to affect the Move and Close item on a form's system menu.  If you remove the Move item the user cannot move the form by dragging it.  If you grey-out, disable or remove the Close item the Close button on the title bar will be disabled and so will the Alt+F4 key combination.  To use it you need just one line of code.  Just create an instance in your form like this:
VB Code:
Private menuManager As New SystemMenuManager(Me, False, SystemMenuManager.MenuItemState.Greyed)
and everything else is done for you.  Note that if you disable the Close item then you must provide an alternative method of closing the form.  Note also that this class addresses the issue that anna7 picked up earlier.  It implements the solution that JuggaloBrotha suggested internally.

Edit:
Attachment removed.  See post #1.

----------


## JuggaloBrotha

awsome, thanx jmcilhinney  it looks good, i may start using it for some of my app's   :Smilie:

----------


## nothingofvalue

Thanks JMC, 
Excellent and easy to use, even for me.

----------


## cubemonkey

Why doesnt my window load center screen with this? Its half off.

----------


## conipto

Real clean code.  Nice commenting, and works great.

Bill

----------


## rabid lemming

I thought I would post this for other users as I found it helpful. If you want to disable the close button of a form that is an MdiChild of another form. That is to say if at run time you have a form that loads inside another form using the 


VB Code:
Me.MdiParent = TheParentOrMainForm.ActiveForm

Where "TheParentOrMainForm" is the name of the form you want the current form youre adding this code to, to appear inside of.

Well to do that firstly add a new class and name it "SystemMenuManager" to your project. Copy the code from the file attachment above in this thread replacing any code already their.

Then add a timer component to your form from the tools menu

Add this to you child form in the code


VB Code:
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
  Me.MdiParent = TheParentOrMainForm.ActiveForm
        Dim myMenuManager As New SystemMenuManager(Me, False, SystemMenuManager.MenuItemState.Greyed)
    End Sub

Also if you want to only remove the close button but allow the form to be movable

set the Flase to True like so


VB Code:
(Me, True, SystemMenuManager.MenuItemState.Greyed)

I hope this helps other users. Dont forget to remove the maximize and minimizes controls in the design view of your form. In the properties window set the MaximizeBox and MinimizesBox properties to false

This will basically allow you to disable a forms close button using the above topic method even if the form is a MdiChild of another form and allow you to still move the form about 

I hope this makes sense and is easy to follow. And mostly I hope some one finds it as helpful as I did   :Thumb:

----------


## jmcilhinney

Hey, hey, hey!  Don't be commenting anything out.  The second argument to the constructor you're using indicates whether the Move item should be present or not.  Just change that argument to True or use the second overload that omits that argument if you want the form to be movable.

As for the other issue, it is an odd situation.  If you create the SystemMenuManager object in the class initialisation, the constructor, the Load event handler or the Activated event handler it doesn't work.  It seems that the use of a Timer is the only way, which works even if the Timer has the smallest possible Interval.  I'd actually recommend using a System.Timers.Timer object with an Interval of 1 (millisecond) and the AutoReset set to False so the Elapsed event is only raised once.  If you do use a System.Windows.Forms.Timer then make sure you call Stop in the Tick event handler or the Timer will continue to raise the Tick event over and over.

----------


## jmcilhinney

Actually, I just tested a bit more and you don't have to use a Timer if you select Disabled or Removed but you do if you select Greyed.  Love those idiosynchrasies!

----------


## rabid lemming

oops sorry jmcilhinney, I have amended my post now. As for the 




> AutoReset set to False so the Elapsed event is only raised once


Do you mean that once the timer has fired once you can disable it and the form should still act as a child form and have the close button disabled ?   :Ehh:

----------


## rabid lemming

hummm... I found that even setting it to Disabled or Removed  and the form will be contained with in the main form container but the close button is still visible ?   :Ehh:

----------


## jmcilhinney

You only have to Disable/Remove the Close menu item once.  After that you would have to consciously put it back for it to be available again.  There's no need to keep doing it over and over, unless there is some other quirky MDI behaviour that I don't know about.  If you allow your Timer to keep raising its Tick event then you are wasting resources on it.  The AutoReset property is specifically designed to differentiate between a once only Timer and a continuous one, although it is only a member of the Timers.Timer and not the Windows.Forms.Timer.  If you use that one you have to explicitly Stop it.  The Timers.Timer is on the Components tab of the Toolbox.

----------


## jmcilhinney

> hummm... I found that even setting it to Disabled or Removed  and the form will be contained with in the main form container but the close button is still visible ?


Create the SystemMenuManager in the Load event handler and it should work, as it did for me.  If you declare the SMM at the class-level and create it on the same line it will not work.

----------


## rabid lemming

Yer i got it working using :


VB Code:
Private Sub LoadTimer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles LoadTimer.Tick
        Me.MdiParent = PhoneExchange.ActiveForm
        ' this is my own bug fix :
        Me.Left = Me.Left + 1
        LoadTimer.Stop()
    End Sub

As I found the form close button didnt disable until you moved the form by dragging it. So I made it move automatically with the timer on tick event

Thanks for all your help again   :Thumb:   :Alien Frog:   :wave:   :Big Grin:   :big yellow:   :Smilie:

----------


## jmcilhinney

All I did was put this code in the form's Load event handler:
VB Code:
Dim smm As New SystemMenuManager(Me, SystemMenuManager.MenuItemState.Removed)
Nothing else was required.  Also, I don't understand why you're setting the form's MdiParent property.  The normal thing to do is set the parent from the outside before you call Show.  A form setting it's own parent seems very odd.

----------


## rabid lemming

lol now i just feel silly   :Blush:  . You are of course absolutely right, So sorry...I have been up 24 hours so thats my only excuse   :Sick:   thanks for putting me right and putting up with my ignorance   :Roll Eyes (Sarcastic):

----------


## shakti5385

What about This

----------


## jmcilhinney

> What about This


The drawback with that is that you must inherit your form from that class.  My class can be added to any form you like, which makes it a little simpler to use.  I'd guess that that author has used the same method of disabling the Move menu item though.

----------


## rabid lemming

Hey,

I thought I would post this and see if it helps...a simple way to disable the close button in vb 2005


Code Code:
Private Const SC_CLOSE As Integer = &HF060
    Private Const MF_ENABLED As Integer = &H0
    Private Const MF_GRAYED As Integer = &H1
    Private Const MF_DISABLED As Integer = &H2
    Declare Function GetSystemMenu Lib "user32" (ByVal hWnd As IntPtr, ByVal revert As Boolean) As IntPtr
    Declare Function EnableMenuItem Lib "user32" (ByVal hMenu As IntPtr, ByVal item As Integer, ByVal enab As Integer) As Boolean
     Public Sub EnableExit(ByVal ok As Boolean)
        Try
            Dim hdl As IntPtr = GetSystemMenu(Me.Handle, False)
            Dim arg As Integer = MF_ENABLED
            If Not ok Then arg = MF_DISABLED + MF_GRAYED
            EnableMenuItem(hdl, SC_CLOSE, arg)
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
   End Sub
 'call  EnableExit(False) in your form load event to disable the clode button

Just thought it might be worth posting this  :Thumb:

----------


## jmcilhinney

> Hey,
> 
> I thought I would post this and see if it helps...a simple way to disable the close button in vb 2005
> 
> 
> Code Code:
> Private Const SC_CLOSE As Integer = &HF060
>     Private Const MF_ENABLED As Integer = &H0
>     Private Const MF_GRAYED As Integer = &H1
> ...


Have you read my code?  That's exactly how it works, but I wrapped it in a class that you can reuse instead of having to add that code to every form.

----------


## TTn

I had run into that problem before where the button becomes reenabled after resizing the form.  I no longer have that problem.

I think I fixed it by declaring the API PROPERLY!
Yes it's wrong that way, and many API will fail sometimes without an Alias.
For example the proper way:


```
Declare Function apiEnableMenuItem Lib "user32" Alias "EnableMenuItem" (ByVal hMenu As IntPtr, ByVal item As Int32, ByVal enab As Int32) As Boolean
```

Where the alias name should be different than the function name.
I'll see if I can indeed verify that as the reason, unless the IntPtr may also cause a problem.

----------


## TTn

I wasn't able to reproduce the quirk, but my comment still stands for API declares.

----------


## rabid lemming

Opps sorry jmcilhinney my bad  :Blush:   :EEK!:

----------


## kalboako1987

should i use imports?

----------


## RobDog888

> I had run into that problem before where the button becomes reenabled after resizing the form.  I no longer have that problem.
> 
> I think I fixed it by declaring the API PROPERLY!
> Yes it's wrong that way, and many API will fail sometimes without an Alias.
> For example the proper way:
> 
> 
> ```
> Declare Function apiEnableMenuItem Lib "user32" Alias "EnableMenuItem" (ByVal hMenu As IntPtr, ByVal item As Int32, ByVal enab As Int32) As Boolean
> ...


No, that incorrect as in .NET its most proper to use the dllimport attribute as alias' are not used or allowed as EntryPoint is used.



```
<System.Runtime.InteropServices.DllImport("User32.dll", CharSet:=Runtime.InteropServices.CharSet.Auto, EntryPoint:="EnableMenuItem")> _
Private Shared Function EnableMenuItem(ByVal hMenu As IntPtr, ByVal item As Int32, ByVal enab As Int32) As Boolean
End Function
```

----------


## jmcilhinney

> should i use imports?


What does this mean?

----------


## obi1kenobi

Sorry to refresh an old thread, but I have found a simple (yet far from ideal solution) to blocking the Alt + F4 key combination. It's sloppy, but extremely easy to do. Just set a menu item's shortcut key combination to Alt + F4 and every press will fire the menu item's Clicked event instead of closing the form.  :Big Grin:  Tested and works perfectly.

----------


## jmcilhinney

It's come to my attention that this class will not prevent the form moving if the ControlBox property is set to False.  The following code seems to work in all cases:
vb.net Code:
Private Structure WINDOWPOS    Public hwnd As Int32    Public hWndInsertAfter As Int32    Public x As Int32    Public y As Int32    Public cx As Int32    Public cy As Int32    Public flags As Int32End Structure Const WM_WINDOWPOSCHANGING As Int32 = &H46 Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)    If m.Msg = WM_WINDOWPOSCHANGING Then        Dim pos As WINDOWPOS = DirectCast(Runtime.InteropServices.Marshal.PtrToStructure(m.LParam, _                                                                                         GetType(WINDOWPOS)), _                                          WINDOWPOS)         pos.x = Me.Left        pos.y = Me.Top         Runtime.InteropServices.Marshal.StructureToPtr(pos, m.LParam, True)    End If     MyBase.WndProc(m)End Sub
See the first post for a downloadable class that incorporates this code.

----------


## Simply Me

Hi jm!

Your work is great it helps me alot and I implemented it in my apps.

I have a main form (not MDI) a treeview menu when user clicked a certain menu it opens another form on top of the main form. Whenever i click the icon of the form found in the start bar the form will minimized but when I click it again I was expecting that it would display it back but it is not restoring. I even tried right click then maximize or restore and its not working. Is it possible that whenever I click the icon in the start bar it will not minimize?

----------


## jmcilhinney

> Hi jm!
> 
> Your work is great it helps me alot and I implemented it in my apps.
> 
> I have a main form (not MDI) a treeview menu when user clicked a certain menu it opens another form on top of the main form. Whenever i click the icon of the form found in the start bar the form will minimized but when I click it again I was expecting that it would display it back but it is not restoring. I even tried right click then maximize or restore and its not working. Is it possible that whenever I click the icon in the start bar it will not minimize?


Are you saying that your second form is using my FormImmobiliser class and it won't restore after being minimised?

----------


## Simply Me

Yes. My second form uses your FormImmobiliser class. My second form BorderStyle is FixedToolWindow. Whenever I click the form's name in the task bar it automatically minimizes and when I right click and choose restore or maximize it is not restoring.

----------


## jmcilhinney

> Yes. My second form uses your FormImmobiliser class. My second form BorderStyle is FixedToolWindow. Whenever I click the form's name in the task bar it automatically minimizes and when I right click and choose restore or maximize it is not restoring.


I've changed the code for the FormImmobiliser class.  Download the new version from post #1 and see if that addresses the issue.

----------


## Simply Me

Great it works now! 

Thanks!

----------


## Always_Confused

Hi JM

I am using both of your classes after loading a form (frmSixQs) from a child form (frmProfiles). All runs as expected, except when I click off the form (frmSixQs), it closes.

How do I make my form focused exclusively until the user closes it intentionally?

----------


## jmcilhinney

> Hi JM
> 
> I am using both of your classes after loading a form (frmSixQs) from a child form (frmProfiles). All runs as expected, except when I click off the form (frmSixQs), it closes.
> 
> How do I make my form focused exclusively until the user closes it intentionally?


That doesn't sound like anything that would be caused by my code but I'll run some tests just to make sure.

----------


## jmcilhinney

> Hi JM
> 
> I am using both of your classes after loading a form (frmSixQs) from a child form (frmProfiles). All runs as expected, except when I click off the form (frmSixQs), it closes.
> 
> How do I make my form focused exclusively until the user closes it intentionally?


I tested my classes with all combinations of Show and ShowDialog with 1, 2 and 3 forms and saw no such behaviour, so I can only assume that it's something to do with your own code.  What happens if you remove my classes?  Do you still see that behaviour?

----------


## obi1kenobi

The SystemMenuManager class doesn't seem to have any effect on the close button of a FixedToolWindow form. Problem encountered in Windows Vista SP1. I tried setting the SMM both to disable and to remove the close button, with absolutely no effect whatsoever. Here's the declaration:



```
Private smm As New SystemMenuManager(Me, SystemMenuManager.MenuItemState.Removed)
```

For now, I've set the ControlBox property to False, however I'd also like to block the Alt + F4 key combination, which seems to work, albeit erratically. I will explore the problem further and attempt to narrow down the source of the problem. I'll keep you posted as best I can, given my poor internet connection.

----------


## jmcilhinney

> The SystemMenuManager class doesn't seem to have any effect on the close button of a FixedToolWindow form. Problem encountered in Windows Vista SP1. I tried setting the SMM both to disable and to remove the close button, with absolutely no effect whatsoever. Here's the declaration:
> 
> 
> 
> ```
> Private smm As New SystemMenuManager(Me, SystemMenuManager.MenuItemState.Removed)
> ```
> 
> For now, I've set the ControlBox property to False, however I'd also like to block the Alt + F4 key combination, which seems to work, albeit erratically. I will explore the problem further and attempt to narrow down the source of the problem. I'll keep you posted as best I can, given my poor internet connection.


I probably never tested that scenario.  I'll have a look myself too, when I get the chance.  Out of town visiting my dad for this Australia Day long weekend.  Submitting this using his brand new Internet connection.

----------


## Matchlighter

What Is the value of the Size menu Item? I would like to disable form sizing but, I need to have it have a sizable border style? I hope I didn't pass over it while scanning the forum. I have tried Googleing it but, that results in "Set the border style to something with Fixed in it."

Thanks!
E

----------


## harshada1

Hi,

I was using your formImmobiliser.vb class only since i use vb .net 2005.
Then i declared Dim frmMove As New FormImmobilisre(Me) in 'declarations' region. That's it?
but it doen't work properly. where to declare dim statement and anything else to do?
form will move only upwards (no left, right, down).
can you give code sample how to use your class?

----------


## VBNetDude

> The SystemMenuManager class doesn't seem to have any effect on the close button of a FixedToolWindow form. Problem encountered in Windows Vista SP1. I tried setting the SMM both to disable and to remove the close button, with absolutely no effect whatsoever. Here's the declaration:
> 
> 
> 
> ```
> Private smm As New SystemMenuManager(Me, SystemMenuManager.MenuItemState.Removed)
> ```
> 
> For now, I've set the ControlBox property to False, however I'd also like to block the Alt + F4 key combination, which seems to work, albeit erratically. I will explore the problem further and attempt to narrow down the source of the problem. I'll keep you posted as best I can, given my poor internet connection.


I'm having the same trouble on Windows XP. Everything works great! Thank you very much! I'll take a look at things and report if I find anything to make it work with fixed tool windows.

----------


## medsont

```
myMenuManager = New SystemMenuManager(_handle, True, SystemMenuManager.MenuItemState.Enabled)
```

oh my god i can't enabled my close button  :Sick:

----------


## jmcilhinney

> ```
> myMenuManager = New SystemMenuManager(_handle, True, SystemMenuManager.MenuItemState.Enabled)
> ```
> 
> oh my god i can't enabled my close button


Um, huh?  The Close button is enabled by default, so you don't have to do anything to enable it.  The whole point of this thread is to disable it.  Are you saying, without actually saying, that you have already disabled it and then you want to re-enable it at some point?

----------


## RobDog888

Sounds like its being disabled but they are not able to re-enable it. Since its probably a coding issue not directly related I would suggest posting a new thread in the VB.NET forum and link/reference this codebank thread so all can assist you better.  :Smilie:

----------


## medsont

ok Thank you Mr.SuperModerator.....

----------


## Zaxxan

Hi, I know this is an old thread but I was hoping someone could help me. I am using the Form Immobilizer and it is working great. What I would like to know is if it is possible to enable/disable the feature during run time or by changing a setting in an ini file? 

Thanks

----------


## jmcilhinney

> Hi, I know this is an old thread but I was hoping someone could help me. I am using the Form Immobilizer and it is working great. What I would like to know is if it is possible to enable/disable the feature during run time or by changing a setting in an ini file? 
> 
> Thanks


This is the part that actually stops the form moving:

```
Protected Overrides Sub WndProc(ByRef m As Message)
    If m.Msg = WM_MOVING Then
        Marshal.StructureToPtr(New RECT(Me.target.Bounds), _
                               m.LParam, _
                               False)
        m.Result = New IntPtr([TRUE])
    End If

    MyBase.WndProc(m)
End Sub
```

If you want to allow the form to move then all you need to do is not execute that bit of code.  It's already in an If block so all you have to do is add a flag to that If statement that can be set from outside, e.g.
vb.net Code:
Public Property CanMove As Boolean Protected Overrides Sub WndProc(ByRef m As Message)    If Not CanMove AndAlso m.Msg = WM_MOVING Then        Marshal.StructureToPtr(New RECT(Me.target.Bounds), _                               m.LParam, _                               False)        m.Result = New IntPtr([TRUE])    End If     MyBase.WndProc(m)End Sub

----------


## Zaxxan

That's brilliant. 

Thanks

----------

