Jump to content
Sign in to follow this  
this-is-me

Need help detecting click on submenu header, not menu item

Recommended Posts

this-is-me

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?

Share this post


Link to post
Share on other sites
Danyfirex

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
  • Like 1

Share this post


Link to post
Share on other sites
this-is-me

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?

Share this post


Link to post
Share on other sites
this-is-me

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?

Share this post


Link to post
Share on other sites
Melba23

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


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______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

 

Share this post


Link to post
Share on other sites
this-is-me

I'm sorry to say that the only message I get from that code is a WM_ENTERIDLE message, which also happens every pixel the mouse moves.


Who else would I be?

Share this post


Link to post
Share on other sites
this-is-me

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?

Share this post


Link to post
Share on other sites
BrewManNH

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
  • Like 2

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

Share this post


Link to post
Share on other sites
this-is-me

BrewManNH, thanks for the _LoWord value for the index. I needed that.


Who else would I be?

Share this post


Link to post
Share on other sites
BrewManNH

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

Share this post


Link to post
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
Sign in to follow this  

×