Re: Taskbar shortcut menu - adding commands.

Tech-Archive recommends: Fix windows errors by optimizing your registry

From: Howard (Howard_at_discussions.microsoft.com)
Date: 08/15/04


Date: Sun, 15 Aug 2004 03:57:01 -0700

Thanks Bob! It worked out ok, apart from the RemoveMenu function which didn't
seem to remove the correct command with the MF_BYCOMMAND attribute (although
the supplied menu ID was correct). I must be doing something wrong there. To
remove the custom commands, I'm now using the attribute MF_BYPOSITION and
calling the RemoveMenu function for all commands up to number 7 (6 is the
last system command, i.e. "close"). I think menus must be removed from bottom
to top. Anyway, everything works as expected now. Thanks for your help!

By the way, this is useful for adding a separator after the default commands:
AppendMenu hSysMenu, MF_SEPARATOR, hSysMenu, "separator".

Howard

"Bob Butler" wrote:

> "Howard" <Howard@discussions.microsoft.com> wrote in message
> news:19077BE8-D0A2-4151-B964-6BBF3762CFEE@microsoft.com
> > Hello everybody
> >
> > The application's icon on the windows taskbar normally has the
> > "restore; move; size; minimize; maximize; close" shortcut menu. Is it
> > possible to add commands to this shortcut menu? I want to make it
> > possible for the users to execute a procedure, while the
> > application's MDI window is minimized.
>
> Here's a simple example that should get you started... (don't go into break
> mode or stop the app except by closing the form or your VB instance may hang
> since the subclassing code may confuse it)
>
> Start a new project and paste this into the default form code:
>
> Private Sub Form_Load()
> ' subclass this form
> HookWindow Me.hwnd
> End Sub
>
> Private Sub Form_Unload(Cancel As Integer)
> ' unhook the window!!!
> UnHookWindow
> End Sub
>
> Add a standard BAS code module (project / add module) and paste in this
> code:
>
> ' API stuff for subclassing window
> Private Const WM_MENUSELECT = &H11F
> Private Const WM_COMMAND = &H111
> Private Const WM_SYSCOMMAND = &H112
> Private Declare Sub CopyMemory Lib "Kernel32" Alias "RtlMoveMemory" _
> (xdest As Any, xsource As Any, ByVal xsize As Long)
> ' info for decoding menu messages
> Private Const MF_BYPOSITION = &H400&
> Private Const MF_BYCOMMAND = &H0&
> Private Const MF_SYSMENU = &H2000&
> Private Const MF_POPUP = &H10&
> Private Declare Function GetMenuString Lib "user32" Alias "GetMenuStringA" _
> (ByVal hMenu As Long, ByVal wIDItem As Long, ByVal lpString As String, _
> ByVal nMaxCount As Long, ByVal wFlag As Long) As Long
> Private Const GWL_WNDPROC = (-4)
> Private Declare Function GetWindowLong Lib "user32" _
> Alias "GetWindowLongA" (ByVal hwnd As Long, _
> ByVal nIndex As Long) As Long
> Private Declare Function SetWindowLong Lib "user32" _
> Alias "SetWindowLongA" (ByVal hwnd As Long, _
> ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
> Private 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
> ' keep track of hooked window
> Private mlHookedhWnd As Long
> Private mlOldWProc As Long
> ' API for add/remove menus
> Private Const MY_MENU_ID As Long = 42
> Private Declare Function AppendMenu Lib "user32" Alias "AppendMenuA" _
> (ByVal hMenu As Long, ByVal wFlags As Long, ByVal wIDNewItem As Long, _
> ByVal lpNewItem As String) As Long
> Private Declare Function RemoveMenu Lib "user32" (ByVal hMenu As Long, _
> ByVal nPosition As Long, ByVal wFlags As Long) As Long
> Private Declare Function GetSystemMenu Lib "user32" (ByVal hwnd As Long, _
> ByVal bRevert As Long) As Long
>
> Function MyWindowProc(ByVal hwnd As Long, ByVal wMsg As Long, _
> ByVal wParam As Long, ByVal lParam As Long) As Long
> Dim bCancel As Boolean
> ' check message to see if we care
> Select Case wMsg
> Case WM_MENUSELECT:
> Debug.Print "select "; wParam; lParam
> Call DoMenuSelect(wParam, lParam, False) ' check menu rollover
> bCancel = False ' call default procedure
> Case WM_COMMAND, WM_SYSCOMMAND:
> Debug.Print "command "; wParam; lParam
> Call DoMenuSelect(wParam, lParam, True) ' check menu selected
> Case Else:
> bCancel = False ' call default procedure
> End Select
> If Not bCancel Then
> ' call default handler
> MyWindowProc = CallWindowProc(mlOldWProc, hwnd, _
> wMsg, wParam, lParam)
> End If
> End Function
>
> Private Sub DoMenuSelect(ByVal wParam As Long, ByVal lParam As Long, _
> ByVal Clicked As Boolean)
> Dim lFlags As Long ' menu flags
> Dim lItem As Long ' menu item number
> Dim sbuff As String * 512 ' scratch for getting caption
> Dim bPopup As Boolean ' menu item has sub-menu
> Dim bSystem As Boolean ' system menu item (control box)
> Dim x As Long ' scratch
> lFlags = (wParam \ 65536) And 65535 ' get flags passed in message
> lItem = wParam And 65535 ' get item number
> If lFlags <> 32767 Or lParam <> 0 Then
> bPopup = CBool(lFlags And MF_POPUP) ' does this item have a sub-menu?
> bSystem = CBool(lFlags And MF_SYSMENU) ' is this the controlbox menu?
> If bPopup Then
> ' for items with sub-menus we get the item number in the current menu
> x = GetMenuString(lParam, lItem, sbuff, Len(sbuff), MF_BYPOSITION)
> Else
> ' for items without sub-menus we get the menu ID instead...
> x = GetMenuString(lParam, lItem, sbuff, Len(sbuff), MF_BYCOMMAND)
> End If
> If x < 0 Then x = 0 ' sanity check
> If bSystem Then Debug.Print "System ";
> If bPopup Then Debug.Print "Popup ";
> If Not bSystem And Not bPopup Then Debug.Print "Menu ";
> Debug.Print Left$(sbuff, x); " (hwnd="; wParam; ", item="; lItem; ")"
> If Clicked = True And lItem = MY_MENU_ID Then MsgBox "*CLICK*"
> End If
> End Sub
>
> Public Sub HookWindow(ByVal hwnd As Long)
> Dim hSysMenu As Long
> Dim x As Long
> If mlHookedhWnd Then
> UnHookWindow
> mlHookedhWnd = 0
> End If
> ' Subclass the requested window
> mlHookedhWnd = hwnd
> mlOldWProc = GetWindowLong(hwnd, GWL_WNDPROC)
> ' re-direct messages to our message handler
> x = SetWindowLong(hwnd, GWL_WNDPROC, AddressOf MyWindowProc)
> hSysMenu = GetSystemMenu(hwnd, 0)
> If hSysMenu Then
> x = AppendMenu(hSysMenu, 0, MY_MENU_ID, "&My Menu Item")
> End If
> End Sub
>
> Public Sub UnHookWindow()
> Dim hSysMenu As Long
> Dim x As Long
> ' stop subclassing the window
> If mlHookedhWnd Then
> ' restore original message handler
> x = SetWindowLong(mlHookedhWnd, GWL_WNDPROC, mlOldWProc)
> hSysMenu = GetSystemMenu(mlHookedhWnd, 0)
> If hSysMenu Then
> x = RemoveMenu(hSysMenu, MF_BYCOMMAND, MY_MENU_ID)
> End If
> mlHookedhWnd = 0
> End If
> End Sub
>
>



Relevant Pages

  • Re: API to find position of active cell no longer working in 2007.
    ... the EXCELE window remains as does its window coordinates ... Private Sub CommandButton1_Click ... Dim hWndXLDesk As Long ... Dim nRow As Long, nCol As Long ...
    (microsoft.public.excel.programming)
  • Re: Access popup window from IE object.
    ... You could just Wait for the window to finish loading - if you know there ... Dim objShell As Object, o As Object ... Private Sub x_NewWindow2 ... Public Sub SetVisible ...
    (microsoft.public.excel.programming)
  • Re: Trying to get info and control a "child" web page
    ... Sub getgoogle() ... window with a URL matching some kind of pattern. ... Dim objShell As Object, objShellWindows As Object, o As Object ... Which opens up a page, this page I can programically navigate and open another page ...
    (microsoft.public.excel.programming)
  • Re: Trying to get info and control a "child" web page
    ... You can use this to get a reference to the child window. ... Dim objShell As Object, objShellWindows As Object, o As Object ... Sub DoBrowse1 ... Which opens up a page, this page I can programically navigate and open another page ...
    (microsoft.public.excel.programming)
  • Re: Issuing DOS command in VBA macro?
    ... Sub FindandListFiles() ... Dim FN As String ' For File Name ... > issue the commands in a macro and have all run in one step. ...
    (microsoft.public.excel.programming)