Disabling Titlebar Buttons with VB.NET

Introduction

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.

Design

Create a VB.NET application and add two forms. Include an Exit command button on both.

Logic

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.

Coding

Form1 – Method 1

Add the following APIs to Form1’s General Declaration section:

VB.NET

    '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:

VB.NET

    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:

VB.NET

    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:

VB.NET

    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. 🙂

Form1 cannot be manipulated by user interaction
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:

VB.NET

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:

VB.NET

    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

Form2 cannot be manipulated by user interaction.
Figure 2Form2 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.

Conclusion

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!

Hannes DuPreez
Hannes DuPreez
Ockert J. du Preez is a passionate coder and always willing to learn. He has written hundreds of developer articles over the years detailing his programming quests and adventures. He has written the following books: Visual Studio 2019 In-Depth (BpB Publications) JavaScript for Gurus (BpB Publications) He was the Technical Editor for Professional C++, 5th Edition (Wiley) He was a Microsoft Most Valuable Professional for .NET (2008–2017).

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read