Jump to content

Need help detecting click on submenu header, not menu item


this-is-me
 Share

Recommended Posts

I have a short and messy script that I am using to dynamically create a context menu of folders starting with C:
My problem is that I would like to detect clicks on the menu item that opens a submenu, but these items do not return a message when clicked that I can see. My explanation is better understood in the following screenshot:
6cqr.jpg
When I click on a menu item that has a submenu, I would like something to happen in the script. I can probably figure it out from there.

Please bear in mind that I would prefer to avoid _IsPressed and Mouse Hooks. Instead. I would like to make this object notify my script if possible.

Here's the script as it is so far:
 

#include <GuiMenu.au3>
#include <GUIConstants.au3>
#include <WindowsConstants.au3>
#include <Constants.au3>
#include <WinAPICom.au3>
#include <WinAPIShellEx.au3>
#include <GuiImageList.au3>
#include <GDIPlus.au3>

;#include <..\..\ProjectIncludes\Debug.au3>
;$dbgType = $dbgTypeConsole
Func dbg($str)
    ConsoleWrite($str & @CRLF)
EndFunc

Global $base = "C:"
Global $lastMenuSelected = 0
Dim $dirs[1][2]

_WinAPI_CoInitialize()
_GDIPlus_Startup()

GUIRegisterMsg($WM_INITMENUPOPUP, "WM_INITMENUPOPUP")
;GUIRegisterMsg($WM_UNINITMENUPOPUP, "WM_UNINITMENUPOPUP")
GUIRegisterMsg($WM_MENUCOMMAND, "WM_MENUCOMMAND")
GUIRegisterMsg($WM_MENUSELECT, "WM_MENUSELECT")

Dim $hGUI = GUICreate("Test", 150, 150)
Local $hIml = GetSystemImageList()
$ctxmenu = GUICtrlGetHandle(GUICtrlCreateContextMenu())
$dirs[0][0] = $ctxmenu
$dirs[0][1] = $base
_GUICtrlMenu_SetMenuStyle($ctxmenu, $MNS_NOTIFYBYPOS)
FillMenu($ctxmenu, $base)

GUISetState()

Do
Until GUIGetMsg() = -3

GUIDelete()
_WinAPI_CoUninitialize()
_GDIPlus_Shutdown()
Exit

Func FindUpperDir($ID)
    Local $ub = UBound($dirs)
    For $i = 0 To $ub - 1
        If $dirs[$i][0] = $ID Then Return $dirs[$i][1]
    Next
EndFunc

Func FillMenu($menu, $base)
    If $base = "" Then Return
    If _GUICtrlMenu_GetItemText($menu, 0) = "[Loading]" Then _GUICtrlMenu_DeleteMenu($menu, 0)
    $lst = ListFolders($base & "\")
    For $i = 1 To $lst[0] - 1 ;Last item in list of folders is always empty
        If $lst[$i] = "$Recycle.Bin" Or $lst[$i] = "winsxs" Then ContinueLoop
        Local $curFolder = $base & "\" & $lst[$i]
        Local $iImage = GetIconIndex($curFolder)
        If FolderHasAFolder($curFolder) Then ;Only make submenus out of folders with folders inside
            Local $newmenu = _GUICtrlMenu_CreatePopup() ;8+32
            _GUICtrlMenu_AddMenuItem($newmenu, "[Loading]")
            _GUICtrlMenu_AppendMenu($menu, $MF_POPUP, $newmenu, $lst[$i])
            Local $ub = UBound($dirs)
            ReDim $dirs[$ub + 1][2]
            $dirs[$ub][0] = $newmenu
            $dirs[$ub][1] = $curFolder
        Else
            _GUICtrlMenu_AddMenuItem($menu, $lst[$i])
        EndIf
        Local $loc = _GUICtrlMenu_GetItemCount($menu) - 1
        Local $hBitmap = hBitmapFromImageList($hIml, $iImage)
        _GUICtrlMenu_SetItemBmp($menu, $loc, $hBitmap)
        ;_WinAPI_DeleteObject($hBitmap)
    Next
EndFunc

Func hBitmapFromImageList($hImageList, $iIndex)
    Local $icon = _GUIImageList_GetIcon($hImageList, $iIndex)
    Local $bitmap = _GDIPlus_BitmapCreateFromHICON($icon)
    Local $hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($bitmap)
    _GUIImageList_DestroyIcon($icon)
    _GDIPlus_ImageDispose($bitmap)
    Return $hBitmap
EndFunc

Func GetSystemImageList( $bLargeIcons = False )
  Local $tSHFILEINFO = DllStructCreate( $tagSHFILEINFO )
  Local $dwFlags = BitOR( $SHGFI_USEFILEATTRIBUTES, $SHGFI_SYSICONINDEX )
  If Not $bLargeIcons Then $dwFlags = BitOR( $dwFlags, $SHGFI_SMALLICON )
  Local $hIml = _WinAPI_ShellGetFileInfo( ".txt", $dwFlags, $FILE_ATTRIBUTE_NORMAL, $tSHFILEINFO )
  If @error Then Return SetError( @error, 0, 0 )
  Return $hIml
EndFunc

Func GetIconIndex( $sFileName )
    Local $pPIDL = _WinAPI_ShellILCreateFromPath( $sFileName )
    Local $tSHFILEINFO = DllStructCreate( $tagSHFILEINFO )
    Local $iFlags = BitOr( $SHGFI_PIDL, $SHGFI_SYSICONINDEX )
    ShellGetFileInfo( $pPIDL, $iFlags, 0, $tSHFILEINFO )
    Local $iIcon = DllStructGetData( $tSHFILEINFO, "iIcon" )
    _WinAPI_CoTaskMemFree( $pPIDL )
    Return $iIcon
EndFunc

Func ShellGetFileInfo($pPIDL, $iFlags, $iAttributes, ByRef $tSHFILEINFO)
    Local $aRet = DllCall('shell32.dll', 'dword_ptr', 'SHGetFileInfoW', 'ptr', $pPIDL, 'dword', $iAttributes, 'struct*', $tSHFILEINFO, 'uint', DllStructGetSize($tSHFILEINFO), 'uint', $iFlags)
    If @error Then Return SetError(@error, @extended, 0)
    Return $aRet[0]
EndFunc

Func FolderHasAFolder($dir)
    $search = FileFindFirstFile($dir & "\*")
    If Not @error Then
        While 1
            $nxtfile = FileFindNextFile($search)
            If @error Then ExitLoop
            If StringInStr(FileGetAttrib($dir & "\" & $nxtfile), "D") Then
                FileClose($search)
                Return 1
            EndIf
        WEnd
    EndIf
    FileClose($search)
    Return 0
EndFunc

Func ListFolders($baseDir)
    Local $line = ""
    $foo = Run(@ComSpec & ' /c "dir /b /ad "' & $baseDir & '""', @SystemDir, @SW_HIDE, $STDOUT_CHILD)
    Do
        $line &= StdoutRead($foo)
    Until @error
    If StringInStr($line, "cannot find the file") Or StringInStr($line, "File Not Found") Then Return StringSplit("", "")
    Return StringSplit($line, @CRLF, 1)
EndFunc

Func WM_INITMENUPOPUP($hwnd, $iMsg, $iwParam, $ilParam)
    If _GUICtrlMenu_FindItem($iwParam, "[Loading]") <> -1 Then FillMenu($iwParam, FindUpperDir($iwParam))
    Return $GUI_RUNDEFMSG
EndFunc

#cs
Func WM_UNINITMENUPOPUP($hwnd, $iMsg, $iwParam, $ilParam)
    Switch $iwParam
        Case $ctxmenu
            ;_GUICtrlMenu_AddMenuItem($menu, "Test")
            ;_GUICtrlMenu_DestroyMenu($ctxmenu)
    EndSwitch
    Return "GUI_RUNDEFMSG"
EndFunc
#ce

Func WM_MENUSELECT($hWnd, $iMsg, $iwParam, $ilParam)
    ;This performs the function of automatically scrolling long lists when the mouse is over the arrows.
    $lastMenuSelected = $ilParam
    If $iwParam = 0 And $iwParam = 0 Then MouseDown("primary")
    Return $GUI_RUNDEFMSG
EndFunc

Func WM_MENUCOMMAND($hWnd, $iMsg, $iwParam, $ilParam)
    #forceref $hWnd, $iMsg, $ilParam
    If _GUICtrlMenu_IsMenu($ilParam) Then
        $base = FindUpperDir($ilParam)
        $folder = _GUICtrlMenu_GetItemText($ilParam, $iwParam)
        dbg($base & "\" & $folder)
    EndIf
    Return $GUI_RUNDEFMSG
EndFunc

Simply run the script and right click to see a list of folders on your C: drive.

Who else would I be?
Link to comment
Share on other sites

Hi.

Change your WM_MENUSELECT for this:

Edit. is not all that you want.but this part can help to know if is popup menu.

Func WM_MENUSELECT($hWnd, $iMsg, $iwParam, $ilParam)
    Local $Flags = BitShift($iwParam, 16)
    If BitAND($Flags, $MF_POPUP) Then
        Consolewrite("I have An Arrow :)" & @crlf)
        EndIf
    Return $GUI_RUNDEFMSG
EndFunc

Saludos

Edited by Danyfirex
Link to comment
Share on other sites

JohnOne, I am sorry to say that the WM_LBUTTONUP message is not generated from the menu. (EDIT: Actually even the form itself does not generate such a message, am I doing it wrong?)

Danyfirex, Thanks for that little snippet of code. It has already helped help me.

Anyone have another suggestion?

Edited by this-is-me
Who else would I be?
Link to comment
Share on other sites

Sorry, I just tried with the gui, and the mouseup message is generated on the gui. My mistake, but the message is still not generated when on the menu, or is not sent to my program. Does it matter that this menu is not generated using built-in functions? I am using _GuiCtrlMenu_ functions to build the menu. Is that the difference?

This is what I'm using to test it:
 

GUIRegisterMsg($WM_LBUTTONUP, "WM_LBUTTONUP")
Func WM_LBUTTONUP($hWnd, $iMsg, $iwParam, $ilParam)
    #forceref $hWnd, $iMsg, $ilParam
    ConsoleWrite("Mouse up" & @CRLF)
    Return $GUI_RUNDEFMSG
EndFunc
Edited by this-is-me
Who else would I be?
Link to comment
Share on other sites

  • Moderators

JohnOne,

The @GUI_CtrlID macro only exists inside a function called using OnEvent mode - as this script uses GUIGteMsg it hss no meaning, as you have discovered. ;)

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

You didn't waste my time. Instead, I learned something. And, it seems that the only way to achieve my goal is to use a mouse hook, so that's what I'll do. Thanks for your help everyone. If anyone does come up with a solution other than a global mouse hook, I am willing to try it.

Who else would I be?
Link to comment
Share on other sites

If you substitute this code with your WM_MENUSELECT function, you might be able to work with it.

Func WM_MENUSELECT($hWnd, $iMsg, $iwParam, $ilParam)
    Local $index = _LoWord($iwParam)
    Local $flags = _HiWord($iwParam)
    _DebugPrint("index or identifier: " & $index)
    If BitAND($flags, $MF_BITMAP) Then _DebugPrint("$MF_BITMAP")
    If BitAND($flags, $MF_CHECKED) Then _DebugPrint("$MF_CHECKED")
    If BitAND($flags, $MF_DISABLED) Then _DebugPrint("$MF_DISABLED")
    If BitAND($flags, $MF_GRAYED) Then _DebugPrint("$MF_GRAYED")
    If BitAND($flags, $MF_HILITE) Then _DebugPrint("$MF_HILITE")
    If BitAND($flags, $MF_MOUSESELECT) Then _DebugPrint("$MF_MOUSESELECT")
    If BitAND($flags, $MF_OWNERDRAW) Then _DebugPrint("$MF_OWNERDRAW")
    If BitAND($flags, $MF_POPUP) Then _DebugPrint("$MF_POPUP")
    If BitAND($flags, $MF_SYSMENU) Then _DebugPrint("$MF_SYSMENU")
    If $ilParam Then _DebugPrint("Handle: " & $ilParam)
    Return $GUI_RUNDEFMSG
EndFunc

; Helper functions.
Func _HiWord($x)
    Return BitShift($x, 16)
EndFunc   ;==>_HiWord

Func _LoWord($x)
    Return BitAND($x, 0xFFFF)
EndFunc   ;==>_LoWord

Func _DebugPrint($s_text)
    $s_text = StringReplace(StringReplace($s_text, @CRLF, @LF), @LF, @LF & "!-->")
    ConsoleWrite( _
            "+===========================================================" & @LF & _
            "!-->" & $s_text & @LF & _
            "+===========================================================" & @LF & @LF)
EndFunc   ;==>_DebugPrint

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Link to comment
Share on other sites

I inadvertently forgot to link where I got that snippet from, I didn't want any confusion created.

'?do=embed' frameborder='0' data-embedContent>>

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Link to comment
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...