Sometimes it is necessary to disable titlebar buttons and menus in your programs temporarily. These buttons include your Minimize, Maximize, Close and Restore buttons. It also includes the System menu. This is what we will cover today in two different ways.
Create a VB.NET application and add two forms. Include an Exit command button on both.
As mentioned earlier, I will cover two ways of achieving this goal. Method one will use various APIs to disable System buttons. Method two will use a term called subclassing.
One thing I need to clarify before continuing and before you stop reading: It is very simple to remove the Titlebar buttons on any form through the Designer window. The problem here is that this is permanent, which I do not want to demonstrate. I want to disable the already existing buttons similar to programs such as Nero, et. al.
Form1 - Method 1
Add the following APIs to Form1's General Declaration section:
'Deletes a menu item or detaches a submenu from the specified menu. Private Declare Function RemoveMenu Lib "user32" Alias _ "RemoveMenu" (ByVal hMenu As IntPtr, ByVal nPosition As Integer, ByVal wFlags As Integer) As Integer 'Enables the application to access the window menu (also known as the system menu or the control menu) for copying and modifying Private Declare Function GetSystemMenu Lib "user32" _ Alias "GetSystemMenu" (ByVal hwnd As IntPtr, ByVal bRevert As Integer) As IntPtr
RemoveMenu will allow us to remove the various window commands form Form1's titlebar. It will not physically remove the buttons, it will just remove it's functionality. GetSystemMenu allows us to obtain the titlebar button's actions.
Add the following Constants:
Private Const SC_CLOSE = &HF060& 'Closes the window Private Const MF_BYCOMMAND = &H0& 'Specifies that the parameter gives the command ID of the existing menu item Private Const SC_SIZE = &HF000& 'Sizes the window Private Const SC_MOVE = &HF010& 'Move the window Private Const SC_MINIMIZE = &HF020& 'Minimizes Window Private Const SC_MAXIMIZE = &HF030& 'Maximizes window Private Const SC_RESTORE = &HF120& 'Restores window Private Const MF_REMOVE = &H1000& 'Removes Window Private Const MF_SEPARATOR = &H800& ' Menu Separator
These constants are our system menu commands.
Add the following code segment into your Form_Load event:
Private Sub frmTitleBar_Load(sender As Object, e As EventArgs) Handles MyBase.Load 'Remove all system menu elements RemoveMenu(GetSystemMenu(Me.Handle, False), 0, MF_SEPARATOR) RemoveMenu(GetSystemMenu(Me.Handle, False), SC_CLOSE, MF_BYCOMMAND) RemoveMenu(GetSystemMenu(Me.Handle, False), SC_SIZE, MF_BYCOMMAND) RemoveMenu(GetSystemMenu(Me.Handle, False), SC_MOVE, MF_BYCOMMAND) RemoveMenu(GetSystemMenu(Me.Handle, False), SC_MINIMIZE, MF_BYCOMMAND) RemoveMenu(GetSystemMenu(Me.Handle, False), SC_MAXIMIZE, MF_BYCOMMAND) RemoveMenu(GetSystemMenu(Me.Handle, False), SC_RESTORE, MF_BYCOMMAND) End Sub
Here, we call both APIs and remove each button and menu's functionality. Simple. Short and Sweet.
Add the remaining code for Form1, else you won't be able to exit this window:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Dim F2 As New frmTitleBarF2 'Shows new form F2.Show() End Sub Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click Application.Exit() End Sub
Run your application now, and your form will resemble Figure 1. You will not be able to close, maximize or minimize your window now, or even resize it! Cool, or as my wife would say: "Cool Bananas" I don't know where she got that saying from, but it got stuck in my head. :)
Figure 1 - Form1 cannot be manipulated by user interaction
modSubClass - Method 2
Method 2 is slightly more complicated. Before we can write the code for Form2, we need to add a New Module to our project. Do this by clicking Project, New Module.
Add the following code to your module:
Module modSubClass 'Retrieves information about the specified window Declare Function GetWindowLong Lib "user32.dll" Alias _ "GetWindowLongA" (ByVal hwnd As Int32, ByVal nIndex As Int32) As Int32 'Passes message information to the specified window procedure Declare Function CallWindowProc Lib "user32.dll" Alias _ "CallWindowProcA" (ByVal lpPrevWndFunc As Int32, ByVal hwnd As Int32, ByVal msg As Int32, ByVal wParam As Int32, ByVal lParam As Int32) As Int32 'Changes an attribute of the specified window Declare Function SetWindowLong Lib "USER32.DLL" Alias _ "SetWindowLongA" (ByVal hwnd As Integer, ByVal attr As Integer, ByVal lVal As SubClassProcDelegate) As Integer ' Sets a new address for the window procedure Const GWL_WNDPROC As Short = (-4) 'This message is sent to a window when the user chooses a command from the window menu, formerly known as the system or control menu, or when the user chooses the maximize button or the minimize button. Private Const WM_SYSCOMMAND As Short = &H112S Public WndProcOld As Int32 'Old Window Procedure 'All messages are sent to the WndProc method after getting filtered through the PreProcessMessage metho Public Function WindProc(ByVal hwnd As Int32, ByVal wMsg As Int32, ByVal wParam As Int32, ByVal lParam As Int32) As Int32 If wMsg = WM_SYSCOMMAND Then Exit Function 'Do nothing when any system buttons pressed WindProc = CallWindowProc(WndProcOld, hwnd, wMsg, wParam, lParam) 'Override old Window method End Function 'Function to override normal activity Delegate Function SubClassProcDelegate(ByVal hwnd As Integer, ByVal msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer 'Subclass ( override ) procedure Sub SubClassWindow(ByVal hwnd As Integer) If WndProcOld = 0 Then WndProcOld = SetWindowLong(hwnd, GWL_WNDPROC, AddressOf WindProc) 'Replace function End If End Sub End Module
What Exactly is Subclassing?
Here is a nice explanation on subclassing and how powerful it can be: SubClassing
In short: It means that we have replaced the normal window functionalities with our own. Make sense?
Form 2 - ( Still ) Method 2
Add the following to Form2:
Private Sub frmTitleBarF2_Load(sender As Object, e As EventArgs) Handles MyBase.Load SubClassWindow(Handle.ToInt32) 'Override System Menu End Sub Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Application.Exit() End Sub
Run your app now and activate Form2. You will see that it gives us exactly the same effect Form1 did earlier
Figure 2 - Form2 cannot be manipulated by user interaction.
Both ofthese methods are good in their own way. Whichever one you end up using is entirely up to you, as this article just aims to serve as a reference.
I am attaching the project's source files below.
See, that wasn't too complicated now was it? No! I love demonstrating every day use to you guys, and I hope you enjoy learning from articles. 'Till next time, bye!