Bilgus Posted March 11, 2018 Share Posted March 11, 2018 (edited) I was curious about adding menus to other programs I found Melbas Excellent Answer and realized maybe there was another way besides subclassing with a separate dll or checking every item and forgoing accelerator keys Here is my try at it expandcollapse popup#Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_Res_HiDpi=Y #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #include <WinAPI.au3> #include <GuiMenu.au3> #include <GUIConstants.au3> ;;#include <SendMessage.au3> Global $aCmdID[4][2] = [ _ ["&Insert", 0x0], _ ;Top Level ["&Date", 0x2000], _ ["&Time", 0x2100], _ ["&Os", 0x2200]] Global $hWnd, $hMenu, $hItem, $iItemIndex ;Need to be accessible from _Exit OnAutoItExitRegister("_Exit") HotKeySet("{F1}", "_Exit") MsgBox(0, "Menu Insert", "Activate a Notepad window or Press [F1] to quit") Notepad_Menu_Handler() Func _Exit() _MenuRemove($hWnd, $hMenu, $hItem, $iItemIndex) Exit EndFunc ;==>_Exit Func _MenuInsert($hWnd, ByRef $hMenu, ByRef $hItem, ByRef $iItemIndex) ;Melba23 $hMenu = 0 $hItem = 0 $hMenu = 0 $iItemIndex = -1 $sTopLevel = StringReplace($aCmdID[0][0], "&", "") ;need to remove accelerator If Not IsHWnd($hWnd) Then Return SetError(1, 0, False) $hMenu = _GUICtrlMenu_GetMenu($hWnd) $iItemIndex = _GUICtrlMenu_FindItem($hMenu, $sTopLevel) If $iItemIndex <> -1 Then ;Already Exists $hItem = _GUICtrlMenu_GetItemSubMenu($hMenu, $iItemIndex) Return SetError(2, 0, True) EndIf $hItem = _GUICtrlMenu_CreatePopup($MNS_AUTODISMISS) ;_GUICtrlMenu_CreateMenu() For $i = 1 To UBound($aCmdID) - 1 _GUICtrlMenu_InsertMenuItem($hItem, 0, $aCmdID[$i][0], $aCmdID[$i][1]) Next ; Insert new menu _GUICtrlMenu_AppendMenu($hMenu, $MF_POPUP, $hItem, $aCmdID[0][0]) _GUICtrlMenu_DrawMenuBar($hWnd) $iItemIndex = _GUICtrlMenu_FindItem($hMenu, $sTopLevel) If $iItemIndex < 0 Then _GUICtrlMenu_DestroyMenu($hItem) Return SetError(3, 0, False) EndIf Return True EndFunc ;==>_MenuInsert Func _MenuWaitForSelection() Local Const $M_ITEM_FOCUSED = 0x7 Local Const $M_LEFTALIGN = 0x1 Local Const $M_TOPALIGN = 0x1 Local Const $M_RETURNCMD = 0x2 Local Const $WM_NCACTIVATE = 0x86 Local $aInfo Local $hGui Local $iSelected = -1 While $iSelected < 0 And WinActive($hWnd) ; Check status of menubar $aInfo = _GUICtrlMenu_GetMenuBarInfo($hWnd, $iItemIndex + 1, 1) ; If menu is active If $aInfo[$M_ITEM_FOCUSED] = True Then $hGui = GUICreate("", 0, 0, $aInfo[0], $aInfo[1], 0, -1, $hWnd) WinActivate($hGui) _WinAPI_PostMessage($hWnd, $WM_NCACTIVATE, 1, 0) _WinAPI_PostMessage($hWnd, $WM_CANCELMODE, 0, 0) ;Close the real menu $iSelected = _GUICtrlMenu_TrackPopupMenu($hItem, $hGui, $aInfo[0], $aInfo[3], $M_LEFTALIGN, $M_TOPALIGN, $M_RETURNCMD) If WinActive($hGui) Then WinActivate($hWnd) Else _WinAPI_PostMessage($hWnd, $WM_NCACTIVATE, 0, 0) _MenuRemove($hWnd, $hMenu, $hItem, $iItemIndex) EndIf GUIDelete($hGui) EndIf WEnd If Not WinActive($hWnd) Then _MenuRemove($hWnd, $hMenu, $hItem, $iItemIndex) Return $iSelected EndFunc ;==>_MenuWaitForSelection Func _MenuRemove($hWnd, $hMenu, $hItem, $iItemIndex) If IsHWnd($hWnd) Then ConsoleWrite("REMOVING " & $hWnd & " " & $hMenu & ":" & $hItem & ":" & $iItemIndex & @CRLF) _GUICtrlMenu_RemoveMenu($hMenu, $iItemIndex) _GUICtrlMenu_DestroyMenu($hItem) _GUICtrlMenu_DrawMenuBar($hWnd) EndIf EndFunc ;==>_MenuRemove Func Edit_Send_Selected($hWnd, $iSelected) ConsoleWrite("Item: 0x" & Hex($iSelected) & " Selected" & @CRLF) Switch $iSelected Case 0x2000 ConsoleWrite("Sending Date" & @CRLF) ControlSend($hWnd, "", "Edit1", @MDAY & "/" & @MON & "/" & @YEAR) Case 0x2100 ConsoleWrite("Sending Time" & @CRLF) ControlSend($hWnd, "", "Edit1", @HOUR & ":" & @MIN & "." & @SEC) Case 0x2200 ConsoleWrite("Sending Os" & @CRLF) ControlSend($hWnd, "", "Edit1", @OSVersion & " " & @OSArch) EndSwitch EndFunc ;==>Edit_Send_Selected Func Notepad_Menu_Handler() While (1) $hWnd = WinWaitActive("[Class:Notepad]") If IsHWnd($hWnd) Then _MenuInsert($hWnd, $hMenu, $hItem, $iItemIndex) ConsoleWrite("New Item is Index: " & $iItemIndex & " Error:" & @error & @CRLF) Edit_Send_Selected($hWnd, _MenuWaitForSelection()) Sleep(100) Else ConsoleWrite("Invalid hWnd" & @CRLF) EndIf WEnd EndFunc ;==>Notepad_Menu_Handler Its not perfect it is a hack after all and yes I know F5 returns time and date in notepad its just an example How does it work? We start off adding a menu to a notepad window only when it becomes active (We remove this menu item if the window is no longer active since we are no longer watching it) When a user selects our top level menu item we cancel the original menu with a $WM_CANCELMODE message We then popup the same menu only this time from our process This does cause a deactivation of the notepad window but we fake it with a $WM_NCACTIVATE message Unfortunately when I instead made the new gui window a child of the notepad window it works better but then I can't get the accelerator keys to work It also makes this menu item deviate from the behavior of the normal menus in that you can't arrow to the others without closing it but hey, you can't get everything Edited March 11, 2018 by Bilgus Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now