Attribute VB_Name = "modTitlebarPopUp" Option Explicit '============================================================================================================= ' ' modTitlebarPopUp Module ' ----------------------- ' ' Created By : Kevin Wilson ' http://www.TheVBZone.com ( The VB Zone ) ' http://www.TheVBZone.net ( The VB Zone .net ) ' ' Last Update : April 01, 2000 ' ' VB Versions : 5.0 / 6.0 ' ' Requires : NOTHING ' ' Description : This module gives you full control over the system (pop up) menu of any form or window ' allowing you to add/remove menu items and modify their properties. ' ' Example Use : ' ' Dim Menu1 As long ' Menu_Initialize Me.hwnd ' Menu_Add Menu1, "Testing" ' Menu_Check Menu1 ' '============================================================================================================= ' ' LEGAL: ' ' You are free to use this code as long as you keep the above heading information intact and unchanged. Credit ' given where credit is due. Also, it is not required, but it would be appreciated if you would mention ' somewhere in your compiled program that that your program makes use of code written and distributed by ' Kevin Wilson (www.TheVBZone.com). Feel free to link to this code via your web site or articles. ' ' You may NOT take this code and pass it off as your own. You may NOT distribute this code on your own server ' or web site. You may NOT take code created by Kevin Wilson (www.TheVBZone.com) and use it to create products, ' utilities, or applications that directly compete with products, utilities, and applications created by Kevin ' Wilson, TheVBZone.com, or Wilson Media. You may NOT take this code and sell it for profit without first ' obtaining the written consent of the author Kevin Wilson. ' ' These conditions are subject to change at the discretion of the owner Kevin Wilson at any time without ' warning or notice. Copyright© by Kevin Wilson. All rights reserved. ' '============================================================================================================= ' API Constants Public Const MF_BYCOMMAND = &H0& Public Const MF_BYPOSITION = &H400& Public Const MF_BITMAP = &H4& Public Const MF_CHECKED = &H8& Public Const MF_DISABLED = &H2& Public Const MF_ENABLED = &H0& Public Const MF_GRAYED = &H1& Public Const MF_MENUBARBREAK = &H20& Public Const MF_MENUBREAK = &H40& Public Const MF_OWNERDRAW = &H100& Public Const MF_POPUP = &H10& Public Const MF_SEPARATOR = &H800& Public Const MF_STRING = &H0& Public Const MF_UNCHECKED = &H0& Public Const SC_CLOSE = &HF060& Public Const SC_HOTKEY = &HF150& Public Const SC_HSCROLL = &HF080& Public Const SC_KEYMENU = &HF100& Public Const SC_MAXIMIZE = &HF030& Public Const SC_MINIMIZE = &HF020& Public Const SC_MOUSEMENU = &HF090& Public Const SC_MOVE = &HF010& Public Const SC_NEXTWINDOW = &HF040& Public Const SC_PREVWINDOW = &HF050& Public Const SC_RESTORE = &HF120& Public Const SC_SCREENSAVE = &HF140& Public Const SC_SIZE = &HF000& Public Const SC_TASKLIST = &HF130& Public Const SC_VSCROLL = &HF070& Public Const WM_SYSCOMMAND = &H112 Public Const GWL_WNDPROC = -4 ' Private Variables (used in this module only) Private ReturnValue As Long Private MenuID_Caption() As String Private SystemMenuHandle As Long Private lpPrevWndProc As Long Private FormHandle As Long Private Hooked As Boolean Private Initialized As Boolean ' Public Variables Public MenuID_Count As Long Public M_Restore As Long Public M_Move As Long Public M_Size As Long Public M_Minimize As Long Public M_Maximize As Long Public M_Seperator As Long Public M_Close As Long ' Public API declarations Public Declare Function CallWindowProc Lib "USER32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal MSG As Long, ByVal wParam As Long, ByVal lParam As Long) As Long Public Declare Function SetWindowLong Lib "USER32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long Public Declare Function GetSystemMenu Lib "USER32" (ByVal hWnd As Long, ByVal bRevert As Long) As Long Public Declare Function InsertMenu Lib "USER32" Alias "InsertMenuA" (ByVal hMenu As Long, ByVal nPosition As Long, ByVal wFlags As Long, ByVal wIDNewItem As Long, ByVal lpNewItem As Any) As Long Public Declare Function AppendMenu Lib "USER32" Alias "AppendMenuA" (ByVal hMenu As Long, ByVal wFlags As Long, ByVal wIDNewItem As Long, ByVal lpNewItem As Any) As Long Public Declare Function ModifyMenu Lib "USER32" Alias "ModifyMenuA" (ByVal hMenu As Long, ByVal nPosition As Long, ByVal wFlags As Long, ByVal wIDNewItem As Long, ByVal LPString As Any) As Long Public Declare Function RemoveMenu Lib "USER32" (ByVal hMenu As Long, ByVal nPosition As Long, ByVal wFlags As Long) As Long '*********************************************************************************** ' Customize this function to make the menu clicks actually do something '*********************************************************************************** Private Function Menu_Action(MenuID As Long) On Error Resume Next ' Form is minimized and the user click the START bar If MenuID = 61728 Then If frmMain.WindowState = vbMinimized Then Menu_Enable M_Maximize Menu_Enable M_Minimize Menu_Disable M_Restore End If ' Form is maximized and the user double-clicks on the titlebar ElseIf MenuID = 61730 Then If frmMain.WindowState = vbMaximized Then Menu_Enable M_Maximize Menu_Enable M_Minimize Menu_Disable M_Restore End If End If ' Do an action based on the button pushed Select Case MenuID Case M_Close Unload frmMain Case M_Maximize GoSub ResetMenus frmMain.WindowState = vbMaximized Menu_Disable M_Maximize Case M_Minimize GoSub ResetMenus frmMain.WindowState = vbMinimized Menu_Disable M_Minimize Case M_Restore GoSub ResetMenus frmMain.WindowState = vbNormal Menu_Disable M_Restore End Select Exit Function ResetMenus: Menu_Enable M_Maximize Menu_Enable M_Minimize Menu_Enable M_Restore Return End Function '*********************************************************************************** ' This is the first function that should be called. It starts everything. Public Function Menu_Initialize(Form_hWnd As Long) On Error Resume Next ' Get the system menu handle SystemMenuHandle = GetSystemMenu(Form_hWnd, False) If SystemMenuHandle = 0 Then Exit Function End If ' Make sure there's no other hooks left unhandled Menu_UnHook DoEvents ' Set the form's handle to be used later FormHandle = Form_hWnd Menu_Hook Initialized = True End Function ' It is not needed, but it's a good idea to call this function last to clean up Public Function Menu_Terminate() Menu_Clear End Function ' This function resets the system menu for the working form/window Public Function Menu_Clear() On Error Resume Next ' Make sure the user has initialized and hooked, otherwise you can't continue If Initialized = False Or Hooked = False Then Exit Function End If ' Unhook the form Menu_UnHook DoEvents ' Reset the variables Erase MenuID_Caption MenuID_Count = 0 Initialized = False Hooked = False ' Restore the original menu GetSystemMenu FormHandle, True End Function ' Add a menu item to a specified location in the specified system menu '-------------------------------------------------------------------------------------- ' Succeeded - MenuID variable returns the menu's ID number and function returns TRUE ' Failed - MenuID variable returns 0 and the function returns FALSE '-------------------------------------------------------------------------------------- Public Function Menu_Add(ByRef MenuID As Long, ByVal MenuText As String, Seperator As Boolean, Optional MenuItemLocation As Long = 0, Optional Checked As Boolean = False, Optional Enabled As Boolean = True, Optional PictureMenuItem As Boolean = False, Optional MenuIconHandle As Long = 0) As Boolean On Error Resume Next ' Make sure the user has initialized and hooked, otherwise you can't continue If Initialized = False Or Hooked = False Then Menu_Add = True Exit Function End If ' Create a unique Menu ID for use in adding the menu. MenuID_Count = MenuID_Count + 1 ReDim Preserve MenuID_Caption(MenuID_Count) As String ' If user wants seperator, add a seperator and exit If Seperator = True Then ReturnValue = InsertMenu(SystemMenuHandle, MenuItemLocation, MF_SEPARATOR, MenuID_Count, "") If ReturnValue = 0 Then GoTo ErrorOccured End If MenuID = MenuID_Count MenuID_Caption(MenuID_Count) = "" Exit Function End If ' If user wants a bitmap menu item, add the bitmap... not the text If PictureMenuItem = True And MenuIconHandle <> 0 Then MenuID_Caption(MenuID_Count) = "" If Checked = True And Enabled = True Then ReturnValue = InsertMenu(SystemMenuHandle, MenuItemLocation, MF_BITMAP Or MF_CHECKED, MenuID_Count, MenuIconHandle) ElseIf Checked = True And Enabled = False Then ReturnValue = InsertMenu(SystemMenuHandle, MenuItemLocation, MF_BITMAP Or MF_CHECKED Or MF_GRAYED, MenuID_Count, MenuIconHandle) ElseIf Checked = False And Enabled = True Then ReturnValue = InsertMenu(SystemMenuHandle, MenuItemLocation, MF_BITMAP Or MF_ENABLED, MenuID_Count, MenuIconHandle) ElseIf Checked = False And Enabled = False Then ReturnValue = InsertMenu(SystemMenuHandle, MenuItemLocation, MF_BITMAP Or MF_GRAYED, MenuID_Count, MenuIconHandle) End If ' If user wants a standard menu item, add the text... not the bitmap Else MenuID_Caption(MenuID_Count) = MenuText If Checked = True And Enabled = True Then ReturnValue = InsertMenu(SystemMenuHandle, MenuItemLocation, MF_STRING Or MF_CHECKED, MenuID_Count, MenuText) ElseIf Checked = True And Enabled = False Then ReturnValue = InsertMenu(SystemMenuHandle, MenuItemLocation, MF_STRING Or MF_CHECKED Or MF_GRAYED, MenuID_Count, MenuText) ElseIf Checked = False And Enabled = True Then ReturnValue = InsertMenu(SystemMenuHandle, MenuItemLocation, MF_STRING Or MF_ENABLED, MenuID_Count, MenuText) ElseIf Checked = False And Enabled = False Then ReturnValue = InsertMenu(SystemMenuHandle, MenuItemLocation, MF_STRING Or MF_GRAYED, MenuID_Count, MenuText) End If End If ' Check if error occured If ReturnValue = 0 Then GoTo ErrorOccured End If ' Return the menu's ID number MenuID = MenuID_Count Exit Function ErrorOccured: MenuID_Count = MenuID_Count - 1 ReDim Preserve MenuID_Caption(MenuID_Count) As String MenuID = 0 Menu_Add = False End Function ' Append a menu item to the end of the specified system menu '-------------------------------------------------------------------------------------- ' Succeeded - MenuID variable returns the menu's ID number and function returns TRUE ' Failed - MenuID variable returns 0 and the function returns FALSE '-------------------------------------------------------------------------------------- Public Function Menu_Append(ByRef MenuID As Long, ByVal MenuText As String, Seperator As Boolean, Optional Checked As Boolean = False, Optional Enabled As Boolean = True, Optional PictureMenuItem As Boolean = False, Optional MenuIconHandle As Long = 0) As Boolean On Error Resume Next ' Make sure the user has initialized and hooked, otherwise you can't continue If Initialized = False Or Hooked = False Then Menu_Append = True Exit Function End If ' Create a unique Menu ID for use in adding the menu. MenuID_Count = MenuID_Count + 1 ReDim Preserve MenuID_Caption(MenuID_Count) As String ' If user wants seperator, add a seperator and exit If Seperator = True Then ReturnValue = AppendMenu(SystemMenuHandle, MF_SEPARATOR, MenuID_Count, "") If ReturnValue = 0 Then GoTo ErrorOccured End If MenuID = MenuID_Count MenuID_Caption(MenuID_Count) = "" Exit Function End If ' If user wants a bitmap menu item, add the bitmap... not the text If PictureMenuItem = True And MenuIconHandle <> 0 Then MenuID_Caption(MenuID_Count) = "" If Checked = True And Enabled = True Then ReturnValue = AppendMenu(SystemMenuHandle, MF_BITMAP Or MF_CHECKED, MenuID_Count, MenuIconHandle) ElseIf Checked = True And Enabled = False Then ReturnValue = AppendMenu(SystemMenuHandle, MF_BITMAP Or MF_CHECKED Or MF_GRAYED, MenuID_Count, MenuIconHandle) ElseIf Checked = False And Enabled = True Then ReturnValue = AppendMenu(SystemMenuHandle, MF_BITMAP Or MF_ENABLED, MenuID_Count, MenuIconHandle) ElseIf Checked = False And Enabled = False Then ReturnValue = AppendMenu(SystemMenuHandle, MF_BITMAP Or MF_GRAYED, MenuID_Count, MenuIconHandle) End If ' If user wants a standard menu item, add the text... not the bitmap Else MenuID_Caption(MenuID_Count) = MenuText If Checked = True And Enabled = True Then ReturnValue = AppendMenu(SystemMenuHandle, MF_STRING Or MF_CHECKED, MenuID_Count, MenuText) ElseIf Checked = True And Enabled = False Then ReturnValue = AppendMenu(SystemMenuHandle, MF_STRING Or MF_CHECKED Or MF_GRAYED, MenuID_Count, MenuText) ElseIf Checked = False And Enabled = True Then ReturnValue = AppendMenu(SystemMenuHandle, MF_STRING Or MF_ENABLED, MenuID_Count, MenuText) ElseIf Checked = False And Enabled = False Then ReturnValue = AppendMenu(SystemMenuHandle, MF_STRING Or MF_GRAYED, MenuID_Count, MenuText) End If End If ' Check if error occured If ReturnValue = 0 Then GoTo ErrorOccured End If ' Return the menu's ID number MenuID = MenuID_Count Exit Function ErrorOccured: MenuID_Count = MenuID_Count - 1 ReDim Preserve MenuID_Caption(MenuID_Count) As String MenuID = 0 Menu_Append = False End Function ' Remove a menu item from the specified titlebar '-------------------------------------------------------------------------------------- ' Succeeded - Function returns TRUE ' Failed - Function returns FALSE '-------------------------------------------------------------------------------------- Public Function Menu_Remove(Menu As Long, Optional UseMenuID_NotPosition As Boolean = True, Optional DecrementMenuIDCount As Boolean = True) As Boolean On Error Resume Next ' Remove the specified menu item If UseMenuID_NotPosition = True Then ReturnValue = RemoveMenu(SystemMenuHandle, Menu, MF_BYCOMMAND) Else ReturnValue = RemoveMenu(SystemMenuHandle, Menu, MF_BYCOMMAND) End If ' Get return type If ReturnValue = 0 Then Menu_Remove = False Exit Function Else Menu_Remove = True End If ' Decrement the MenuID_Count If DecrementMenuIDCount = True And MenuID_Count > 0 Then MenuID_Count = MenuID_Count - 1 End If End Function ' Change the Checked property of the menu item to TRUE Public Function Menu_Check(MenuID As Long) As Boolean On Error Resume Next ReturnValue = ModifyMenu(SystemMenuHandle, MenuID, MF_BYCOMMAND Or MF_CHECKED, MenuID, MenuID_Caption(MenuID)) If ReturnValue = 0 Then Menu_Check = False Else Menu_Check = True End If End Function ' Change the Checked property of the menu item to FALSE Public Function Menu_Uncheck(MenuID As Long) As Boolean On Error Resume Next ReturnValue = ModifyMenu(SystemMenuHandle, MenuID, MF_BYCOMMAND Or MF_UNCHECKED, MenuID, MenuID_Caption(MenuID)) If ReturnValue = 0 Then Menu_Uncheck = False Else Menu_Uncheck = True End If End Function ' Change the Enabled property of the menu item to TRUE Public Function Menu_Enable(MenuID As Long) As Boolean On Error Resume Next ReturnValue = ModifyMenu(SystemMenuHandle, MenuID, MF_BYCOMMAND Or MF_ENABLED, MenuID, MenuID_Caption(MenuID)) If ReturnValue = 0 Then Menu_Enable = False Else Menu_Enable = True End If End Function ' Change the Enabled property of the menu item to TRUE Public Function Menu_Disable(MenuID As Long) As Boolean On Error Resume Next ReturnValue = ModifyMenu(SystemMenuHandle, MenuID, MF_BYCOMMAND Or MF_GRAYED, MenuID, MenuID_Caption(MenuID)) If ReturnValue = 0 Then Menu_Disable = False Else Menu_Disable = True End If End Function ' Change the Caption property of the menu item to the specified caption value Public Function Menu_CaptionChange(MenuID As Long, NewCaption As String) As Boolean On Error Resume Next ReturnValue = ModifyMenu(SystemMenuHandle, MenuID, MF_BYCOMMAND Or MF_STRING, MenuID, NewCaption) If ReturnValue = 0 Then Menu_CaptionChange = False Else MenuID_Caption(MenuID) = NewCaption Menu_CaptionChange = True End If End Function ' Change the the style of the menu item to picture. Picture replaces the caption. Public Function Menu_CaptionToPicture(MenuID As Long, PictureHandle As Long) As Boolean On Error Resume Next ReturnValue = ModifyMenu(SystemMenuHandle, MenuID, MF_BYCOMMAND Or MF_BITMAP, MenuID, PictureHandle) If ReturnValue = 0 Then Menu_CaptionToPicture = False Else MenuID_Caption(MenuID) = "" Menu_CaptionToPicture = True End If End Function ' This function allows you to reset the system menu of any window. ' WARNING : This is ment for the windows of other programs. If you're ' going to use this for a form in your project, use the ' Menu_Clear funciton instead. It cleans up the variables too. Public Function Menu_zRestore(Form_hWnd As Long) As Boolean On Error Resume Next If Form_hWnd = 0 Then Exit Function End If ReturnValue = GetSystemMenu(Form_hWnd, True) If ReturnValue = 0 Then Menu_zRestore = False Else Menu_zRestore = True End If End Function ' This function is designed to remove all system menu items from a window ' WARNING : This is ment for the windows of other programs. If you're ' going to use this for a form in your project, use the ' Menu_Clear or Menu_Remove funciton instead. ' NOTE : Unless the form has it's ControlBox property set to FALSE, or has ' no titlebar at all, the "Move" system menu item and a seperator ' right below it can not be removed. Public Function Menu_zClear(Form_hWnd As Long, Optional NumberOfMenuItems As Long = 10) As Boolean On Error Resume Next Dim hMenu As Long Dim MyCounter As Long If Form_hWnd = 0 Then Exit Function End If hMenu = GetSystemMenu(Form_hWnd, False) If hMenu <> 0 Then For MyCounter = 0 To NumberOfMenuItems RemoveMenu hMenu, MyCounter, MF_BYPOSITION Next End If End Function '============================================================================== ' Sublcassing Information '============================================================================== ' Subclasses the specified form so it will intercept messages going to it Private Function Menu_Hook() On Error Resume Next If Hooked = False Then Hooked = True Else Exit Function End If lpPrevWndProc = SetWindowLong(FormHandle, GWL_WNDPROC, AddressOf WindowProc) End Function ' Unsubclasses the specified form Private Function Menu_UnHook() On Error Resume Next If FormHandle = 0 Then Exit Function End If SetWindowLong FormHandle, GWL_WNDPROC, lpPrevWndProc Hooked = False Initialized = False End Function ' Process any messages sent to the specified form Private Function WindowProc(ByVal hw As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long On Error Resume Next Dim MenuID As Long ' Debug.Print "uMsg = " & Get_uMsg(uMsg) & ", wParam = " & wParam ' Trapping the WM_SYSCOMMAND message determines when the user has clicked ' on a custom menu item. That menu item is then passed to a function that ' handles the functionality of that menu item. If uMsg = WM_SYSCOMMAND Then MenuID = wParam And &HFFFF& If MenuID <> 0 Then Menu_Action MenuID End If End If 'Always call the original handler when you are done WindowProc = CallWindowProc(lpPrevWndProc, hw, uMsg, wParam, lParam) End Function Private Function Get_uMsg(uMsg As Long) Select Case uMsg Case SC_CLOSE ' Closes the window. Get_uMsg = "SC_CLOSE" 'Case SC_CONTEXTHELP ' Changes the cursor to a question mark with a pointer. If the user then clicks a control in the dialog box, the control receives a WM_HELP message. ' Get_uMsg = "SC_CONTEXTHELP" 'Case SC_DEFAULT ' Selects the default item; the user double-clicked the window menu. ' Get_uMsg = "SC_DEFAULT" Case SC_HOTKEY ' Activates the window associated with the application-specified hot key. The low-order word of lParam identifies the window to activate. Get_uMsg = "SC_HOTKEY" Case SC_HSCROLL ' Scrolls horizontally. Get_uMsg = "SC_HSCROLL" Case SC_KEYMENU ' Retrieves the window menu as a result of a keystroke. Get_uMsg = "SC_KEYMENU" Case SC_MAXIMIZE ' (or SC_ZOOM) Maximizes the window. Get_uMsg = "SC_MAXIMIZE" Case SC_MINIMIZE ' (or SC_ICON) Minimizes the window. Get_uMsg = "SC_MINIMIZE" 'Case SC_MONITORPOWER ' Windows 95 only: Sets the state of the display. This command supports devices that have power-saving features, such as a battery-powered personal computer. ' Get_uMsg = "SC_MONITORPOWER" Case SC_MOUSEMENU ' Retrieves the window menu as a result of a mouse click. Get_uMsg = "SC_MOUSEMENU" Case SC_MOVE ' Moves the window. Get_uMsg = "SC_MOVE" Case SC_NEXTWINDOW ' Moves to the next window. Get_uMsg = "SC_NEXTWINDOW" Case SC_PREVWINDOW ' Moves to the previous window. Get_uMsg = "SC_PREVWINDOW" Case SC_RESTORE ' Restores the window to its normal position and size. Get_uMsg = "SC_RESTORE" Case SC_SCREENSAVE ' Executes the screen saver application specified in the [boot] section of the SYSTEM.INI file. Get_uMsg = "SC_SCREENSAVE" Case SC_SIZE ' Sizes the window. Get_uMsg = "SC_SIZE" Case SC_TASKLIST ' Executes or activates Windows Task Manager. Get_uMsg = "SC_TASKLIST" Case SC_VSCROLL ' Scrolls vertically. Get_uMsg = "SC_VSCROLL" Case Else Get_uMsg = CStr(uMsg) End Select End Function