Jump to content



Photo

Ghost inputs; where start debugging?


  • Please log in to reply
10 replies to this topic

#1 Armag3ddon

Armag3ddon

    Seeker

  • Active Members
  • 34 posts

Posted 27 May 2012 - 10:56 PM

So this is a tough one. Kept me busy all day long especially to configure AutoIt Debugger to start the application in a decent amount of time. My project exceeded any reasonable number of lines I could post into the forum and even if I did, you wouldn't be able to test it because it's more or less a file explorer for a somewhat small game.
I will try to compile a script which demonstrates my observations tomorrow, though I fear when I do, the buggy behaviour will be gone.

Anyway, here's a rough overview over what I have so far:
A treeview created via the UDFs - the main file tree showing the files. A proper file explorer needs all kind of operations you are used to, like copy, cut, paste etc. so I did this kind of stuff.
You'd expect these options accessible via a context menu, so I did that one too. The how to do this I found here: http://www.autoitscript.com/forum/topic/...ew-items/page__view__findpost_

My setup so far:
treeview via _GUICtrlTreeView_Create etc. etc.
and context menu via GUICtrlCreateContextMenu

->
; Context menu (fileview) Local $dummy = GUICtrlCreateDummy() Global $ctxmenu = GUICtrlCreateContextMenu($dummy) ; Needs to be hooked up on the dummy Global $contextmenu = GUICtrlGetHandle($ctxmenu) ; Saved for later use, the menu is called via this handle GUICtrlSetOnEvent(GUICtrlCreateMenuItem(LoadStr("Context_New"), $ctxmenu), "NewFile") GUICtrlSetOnEvent(GUICtrlCreateMenuItem(LoadStr("Context_Cut"), $ctxmenu), "CutFile") GUICtrlSetOnEvent(GUICtrlCreateMenuItem(LoadStr("Context_Copy"), $ctxmenu), "CopyFile") GUICtrlSetOnEvent(GUICtrlCreateMenuItem(LoadStr("Context_Paste"), $ctxmenu), "PasteFile") GUICtrlSetOnEvent(GUICtrlCreateMenuItem(LoadStr("Context_Delete"), $ctxmenu), "DeleteFile") GUICtrlCreateMenuItem("", $ctxmenu) GUICtrlSetOnEvent(GUICtrlCreateMenuItem(LoadStr("Context_Refresh"), $ctxmenu), "RefreshFileViewWrapper")


LoadStr is just a function that returns a localized language string. The context menu is show on rightclick - of course.
This is a piece from my WM_NOTIFY:
    Case $NM_RCLICK ; right click      $mouse = _WinAPI_GetMousePos(True, $main)      $hit_test = _GUICtrlTreeView_HitTest($fileview, DllStructGetData($mouse, "X"), DllStructGetData($mouse, "Y"))      $selitem = _GUICtrlTreeView_HitTestItem($fileview, DllStructGetData($mouse, "X"), DllStructGetData($mouse, "Y"))      If $hit_test = 1 Or $hit_test = 32 Then       FileviewLoseSelection()       RefreshContextMenu()       _GUICtrlMenu_TrackPopupMenu($contextmenu, $main)       Return 1      Else       If $selitem = 0 Then Return $GUI_RUNDEFMSG       _GUICtrlTreeView_SelectItem($fileview, $selitem)       _GUICtrlTreeView_SetSelected($fileview, $selitem)       $no_selection = False      RefreshContextMenu()       _GUICtrlMenu_TrackPopupMenu($contextmenu, $main)       Return 1      EndIf


I test to see whether the user clicked on an item - if yes, select that item. If no, clear the selection of the treeview (a bit hacky though but sufficient for my purpose) so the user may create new files in the root directory (which is the game dir). That's what FileviewLoseSelection() does.
RefreshContextMenu does a bunch of de-/activation of context menu entries e.g. deactivating the Paste option of no file was selected for cutting/copying:
Func RefreshContextMenu() ConsoleWrite("RefreshContextMenu" & @CRLF) ; Paste operation only accessible if file to paste If Not $file_operation Then   _GUICtrlMenu_SetItemDisabled($contextmenu, 3) Else   _GUICtrlMenu_SetItemEnabled($contextmenu, 3) EndIf [...]


The weirdness begins now. I wanted to test everything when a 'crash' occured. I looked further into this and could narrow it down to have something to do with the context menu. I discovered, using AutoIt Debugger, that this was no real crash but that my regular end program routine was called. But not only that, I got random inputs on every menu item in my whole GUI. This isn't limited to the context menu but also triggers random entries from the system menu of the GUI:

Global $optmenu = GUICtrlCreateMenu(LoadStr("Menu_Options")) GUICtrlSetOnEvent(GUICtrlCreateMenuItem(LoadStr("Menu_Prefs"), $optmenu), "OpenPreferences") GUICtrlSetOnEvent(GUICtrlCreateMenuItem(LoadStr("Menu_Quit"), $optmenu), "EditorClose") Global $infomenu = GUICtrlCreateMenu(LoadStr("Menu_Info")) GUICtrlSetOnEvent(GUICtrlCreateMenuItem(LoadStr("Menu_About"), $infomenu), "ShowInfo") Global $info_window ; To save the info window Global $prefs_window ; To save the preferences window


There never was a crashed but the Menu_Quit entry was triggered. Sometimes the preferences window opened, sometimes the about screen. Sometimes the new file dialogue opens (first context menu entry), sometimes the file tree is refreshed (6th entry, not counting the separator) or I am asked if I want to delete the file. These ghost inputs occur on two different occasions:
1. The context menu is opened; AutoIt Debugger told me that RefreshContextMenu was called, ConsoleWrite wrote the console but then the execution of RefreshContextMenu was interrupted and the other function kicked in e.g. I get prompted for file deletion. After this interrupting process is done, RefreshContextMenu continues and the context menu opens.
2. I select an entry from the context menu. The entry is processed and when that's finished the random function is done. This often was my 'crash' because Menu_Quit was called. Though I get a crash report from Windows and everything.

After I disabled the creation of the system menu, at least quitting of the program and opening of the preferences stopped. So that's my current status. I have no idea how to access this problem. AutoIt Debugger doesn't give me any more useful information than the interruption of the context refresh function. I'm happy to provide anyone who is willing to help with the full source (~33 MB). I'm desperate. I invested already ~5 hours into finding this bug.

To wrap it all up, here's my creation routine of the GUI and the three elements in question (treeview, system menu, context menu). Maybe someone can make something out of it:

AutoIt         
; Create the GUI Opt("GUIOnEventMode", 1) Opt("GUICloseOnESC", 0) Opt("PixelCoordMode", 2) Opt("TrayIconHide", 1) Global $main = GUICreate("OpenClonk Editor", 800, 600, -1, -1, BitOR($WS_CAPTION, $WS_MINIMIZEBOX, $WS_SYSMENU, $DS_CONTEXTHELP, $WS_SYSMENU, $WS_VISIBLE, $WS_CLIPCHILDREN)) GUISetOnEvent($GUI_EVENT_CLOSE, "EditorClose", $main) GUISetOnEvent($GUI_EVENT_PRIMARYUP, "EndDrag", $main) GUISetState(@SW_DISABLE, $main) ; Show splash screen SplashImageOn(LoadStr("General_InitMenu"), ".\res\Splash.jpg", 320, 240) ; Options menu Global $optmenu = GUICtrlCreateMenu(LoadStr("Menu_Options")) GUICtrlSetOnEvent(GUICtrlCreateMenuItem(LoadStr("Menu_Prefs"), $optmenu), "OpenPreferences") GUICtrlSetOnEvent(GUICtrlCreateMenuItem(LoadStr("Menu_Quit"), $optmenu), "EditorClose") Global $infomenu = GUICtrlCreateMenu(LoadStr("Menu_Info")) GUICtrlSetOnEvent(GUICtrlCreateMenuItem(LoadStr("Menu_About"), $infomenu), "ShowInfo") Global $info_window ; To save the info window Global $prefs_window ; To save the preferences window ; Context menu (fileview) Local $dummy = GUICtrlCreateDummy() ; This is necessary because autoit handles context menus poorly. It won't work with _GUICtrlTreeView (TreeView created via autoit UDFs) Global $ctxmenu = GUICtrlCreateContextMenu($dummy) ; Needs to be hooked up on the dummy Global $contextmenu = GUICtrlGetHandle($ctxmenu) ; Saved for later use, the menu is called via this handle GUICtrlSetOnEvent(GUICtrlCreateMenuItem(LoadStr("Context_New"), $ctxmenu), "NewFile") GUICtrlSetOnEvent(GUICtrlCreateMenuItem(LoadStr("Context_Cut"), $ctxmenu), "CutFile") GUICtrlSetOnEvent(GUICtrlCreateMenuItem(LoadStr("Context_Copy"), $ctxmenu), "CopyFile") GUICtrlSetOnEvent(GUICtrlCreateMenuItem(LoadStr("Context_Paste"), $ctxmenu), "PasteFile") GUICtrlSetOnEvent(GUICtrlCreateMenuItem(LoadStr("Context_Delete"), $ctxmenu), "DeleteFile") GUICtrlCreateMenuItem("", $ctxmenu) GUICtrlSetOnEvent(GUICtrlCreateMenuItem(LoadStr("Context_Refresh"), $ctxmenu), "RefreshFileViewWrapper") If $C4GROUP_EXE <> "" Then GUICtrlCreateMenuItem("", $ctxmenu) GUICtrlSetOnEvent(GUICtrlCreateMenuItem(LoadStr("Context_C4GPack"), $ctxmenu), "PackFile") GUICtrlSetOnEvent(GUICtrlCreateMenuItem(LoadStr("Context_C4GUnpack"), $ctxmenu), "UnpackFile") EndIf SplashImageOn(LoadStr("General_InitFiles"), ".\res\Splash.jpg", 320, 240) ; Tree file view Global $fileview = _GUICtrlTreeView_Create($main, 0,0, 200,560, BitOR($TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_SHOWSELALWAYS, $TVS_EDITLABELS, $TVIS_DROPHILITED, $WS_TABSTOP, $TVS_CHECKBOXES), $WS_EX_CLIENTEDGE) InitFileView() Local $hFunc DIM $TVN_BEGINDRAG DIM $TVN_BEGINLABELEDIT DIM $TVN_ENDLABELEDIT ; For drag and drop behaviour inside the treeview Global $drag_item, $next_item, $prev_item, $hover_item, $hover_time ; Drag and drop outside the treeview, explorer extension _OLEInitialize() GUIRegisterMsg($WM_DI_GETDRAGIMAGE, "MY_GETDRAGIMAGE") Global $IDragSourceHelper = _ObjCoCreateInstance($CLSID_DragDropHelper,$IID_IDragSourceHelper,$IDragSourceHelper_vTable) Global $objIDataSource ; Proper detecting of the return key is broken in AutoIt, this is used for a workaround: Global $wProcHandle = DllCallbackRegister("_WindowProc", "int", "hwnd;uint;wparam;lparam") Global $wProcOld = _WinAPI_SetWindowLong($fileview, $GWL_WNDPROC, DllCallbackGetPtr($wProcHandle)) Global Const $VK_RETURN = 0x0D ; Enter key ; For renaming Global $edit_label = False Global $just_edited = "" Global Const $VK_F2 = 0x71 ; F2 key ; For checking .ocd Global $checked_item = 0 Global $checked_path = "" Global $checked_state = False ; Workaround to have the treeview "lose" its selection Global $no_selection = False ; Temporary memory for sorting the elements (after renaming/moving/creation) Global $sort_memory[1] $sort_memory[0] = ""






#2 Zedna

Zedna

    AutoIt rulez!

  • MVPs
  • 8,315 posts

Posted 27 May 2012 - 11:18 PM

For such problems is definitely good idea to use eliminating method.
Make copy of your script and then continuosly remove unneccesary code pieces until bug dissapear.

Also good idea is to create as small as possible reproducing script.

#3 Armag3ddon

Armag3ddon

    Seeker

  • Active Members
  • 34 posts

Posted 28 May 2012 - 11:40 AM

Thanks so far. I did as you said and removed piece by piece of the code. I could narrow it down but the behaviour still looked kind of random when it occured. I then realised that it was my own behaviour that triggered the bug. If I selected an entry before rightclicking it, nothing unusual happened. It's like this:
- Item is not selected. Left click, item gets selected. Right click on selected item, context menu opens, everything's fine.
- Item is not selected. Right click on unselected item, context menu opens, weird stuff happens.

It has something to do with calling _GUICtrlTreeView_SelectItem($fileview, $selitem) in my $NM_RCLICK case in WM_NOTIFY. Still clueless how to solve though. I could of course do a workaround without reselection.

Edited by Armag3ddon, 28 May 2012 - 11:41 AM.


#4 Zedna

Zedna

    AutoIt rulez!

  • MVPs
  • 8,315 posts

Posted 28 May 2012 - 12:02 PM

If you have code in WM_NOTIFY then problems may be due to "blocking" (long lasting) code.
This results in weird behaviour.
Search this forum/wiki about blocking/non-blocking code in message loop.

EDIT:
http://www.autoitscript.com/wiki/GUIRegisterMsg

Edited by Zedna, 28 May 2012 - 03:31 PM.


#5 Armag3ddon

Armag3ddon

    Seeker

  • Active Members
  • 34 posts

Posted 28 May 2012 - 09:54 PM

I can't seem to find anything like this in my code but maybe my mind is just stuck. But I was able to recreate the bug in a test script!

So here it is. On startup you get a simple GUI with a treeview element in it. You can rightclick to open a context menu with several entries. Only Cut und Paste work, the others just call a dummy function that sends the message "Clicked on either New, Copy, Delete or Refresh"

To reproduce my bug open the first group ([10] New Item) and afterwards select [29] New Child using the arrow keys (it won't work by leftclicking). Whenever I select the entry (not deselecting) I get the message Clicked on either New, Copy, Delete or Refresh. This should not happen though.

Hopefully, this will lead someone to the bug. Here it is:

AutoIt         
#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 #include <GuiConstantsEx.au3> #include <GuiTreeView.au3> #include <WindowsConstants.au3> #include <GuiMenu.au3> Opt('MustDeclareVars', 1) Opt("GUIOnEventMode", 1) $Debug_TV = False ; Check ClassName being passed to functions, set to True and use a handle to another control to see it work Global Const $TVSORTCB = "ptr Parent;ptr Compare;lparam SortParam;" Global $Data[500] Global $operation = False Global $hWnd_GUI, $hTreeView, $contextmenu _Main() While 1 Sleep(10) WEnd Func _Main()     Local $hItem[10], $hChildItem[30], $hGrandChildItem[90], $hGrandGrantChildItem[180]     Local $iCItem = 0, $iGCItem = 0, $IGGCItem = 0, $i1 = 10, $i2 = 30, $i3 = 90, $i4 = 180     Local $iStyle = BitOR($TVS_EDITLABELS, $TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_DISABLEDRAGDROP, $TVS_SHOWSELALWAYS)     $hWnd_GUI = GUICreate("TreeView Sort", 400, 300) GUISetOnEvent($GUI_EVENT_CLOSE, "Close", $hWnd_GUI)     $hTreeView = _GUICtrlTreeView_Create($hWnd_GUI, 2, 2, 396, 268, $iStyle, $WS_EX_CLIENTEDGE)     _GUICtrlTreeView_SetUnicodeFormat($hTreeView, True)     GUISetState()     _GUICtrlTreeView_BeginUpdate($hTreeView)     Local $Count = 0     For $a = 0 To 9         $Data[$Count] = StringFormat("[%02d] New Item", $i1)         $hItem[$a] = _GUICtrlTreeView_Add($hTreeView, $hTreeView, $Data[$Count])         _GUICtrlTreeView_SetItemParam($hTreeView, $hItem[$a], $Count)         $Count += 1         For $b = 1 To 3             $Data[$Count] = StringFormat("[%02d] New Child", $i2)             $hChildItem[$iCItem] = _GUICtrlTreeView_AddChild($hTreeView, $hItem[$a], $Data[$Count])             _GUICtrlTreeView_SetItemParam($hTreeView, $hChildItem[$iCItem], $Count)             $Count += 1             For $c = 1 To 3                 $Data[$Count] = StringFormat("[%02d] New Grandchild", $i3)                 $hGrandChildItem[$iGCItem] = _GUICtrlTreeView_AddChild($hTreeView, $hChildItem[$iCItem], $Data[$Count])                 _GUICtrlTreeView_SetItemParam($hTreeView, $hGrandChildItem[$iGCItem], $Count)                 $Count += 1                 For $d = 1 To 2                     $Data[$Count] = StringFormat("[%02d] New GrandGrandChild", $i4)                     $hGrandGrantChildItem[$IGGCItem] = _GUICtrlTreeView_AddChild($hTreeView, $hGrandChildItem[$iGCItem], $Data[$Count])                     _GUICtrlTreeView_SetItemParam($hTreeView, $hGrandGrantChildItem[$IGGCItem], $Count)                     $Count += 1                     $IGGCItem += 1                     $i4 -= 1                 Next                 $iGCItem += 1                 $i3 -= 1             Next             $iCItem += 1             $i2 -= 1         Next         $i1 -= 1     Next _GUICtrlTreeView_EndUpdate($hTreeView) ; Context menu Local $dummy = GUICtrlCreateDummy() Local $ctxmenu = GUICtrlCreateContextMenu($dummy) $contextmenu = GUICtrlGetHandle($ctxmenu) GUICtrlSetOnEvent(GUICtrlCreateMenuItem("New", $ctxmenu), "Dummy") GUICtrlSetOnEvent(GUICtrlCreateMenuItem("Cut", $ctxmenu), "Cut") GUICtrlSetOnEvent(GUICtrlCreateMenuItem("Copy", $ctxmenu), "Dummy") GUICtrlSetOnEvent(GUICtrlCreateMenuItem("Paste", $ctxmenu), "Paste") GUICtrlSetOnEvent(GUICtrlCreateMenuItem("Delete", $ctxmenu), "Dummy") GUICtrlCreateMenuItem("", $ctxmenu) GUICtrlSetOnEvent(GUICtrlCreateMenuItem("Refresh", $ctxmenu), "Dummy") GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY") EndFunc   ;==>_Main Func Close() GUIDelete($hWnd_GUI) Exit EndFunc ;==>Close Func WM_NOTIFY($hWnd, $Msg, $wParam, $lParam) Local $struct, $hWndFrom, $hWnd_fileview If $hWnd <> $hWnd_GUI Then Return $GUI_RUNDEFMSG $hWnd_fileview = $hTreeView If Not IsHWnd($hTreeView) Then $hWnd_fileview = GUICtrlGetHandle($hTreeView) $struct = DllStructCreate($tagNMHDR, $lParam) If @error Then Return $GUI_RUNDEFMSG $hWndFrom = HWnd(DllStructGetData($struct, "hWndFrom")) Switch $hWndFrom   Case $hWnd_fileview    Switch DllStructGetData($struct, "code")     Case $NM_RCLICK ; right click      Local $mouse = _WinAPI_GetMousePos(True, $hWnd)      Local $hit_test = _GUICtrlTreeView_HitTest($hTreeView, DllStructGetData($mouse, "X"), DllStructGetData($mouse, "Y"))      Local $selitem = _GUICtrlTreeView_HitTestItem($hTreeView, DllStructGetData($mouse, "X"), DllStructGetData($mouse, "Y"))      If $selitem = 0 Then Return $GUI_RUNDEFMSG      _GUICtrlTreeView_SelectItem($hTreeView, $selitem)      RefreshContextMenu()      _GUICtrlMenu_TrackPopupMenu($contextmenu, $hWnd_GUI)      Return 1    EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>WM_NOTIFY Func Dummy() ConsoleWrite("Clicked on either New, Copy, Delete or Refresh" & @CRLF) EndFunc ;==>Dummy Func Cut() ConsoleWrite("Cut" & @CRLF) If $operation Then ClearOperation() $operation = _GUICtrlTreeView_GetSelection($hTreeView) _GUICtrlTreeView_SetCut($hTreeView, $operation, True) EndFunc ;==>Cut Func Paste() ConsoleWrite("Paste" & @CRLF) If Not $operation Then Return Local $target = _GUICtrlTreeView_GetSelection($hTreeView) _GUICtrlTreeView_BeginUpdate($hTreeView) TreeItemCopy($hTreeView, $operation, $target) _GUICtrlTreeView_Delete($hTreeView, $operation) _GUICtrlTreeView_EndUpdate($hTreeView) ClearOperation() EndFunc ;==>Paste Func RefreshContextMenu() If Not $operation Then   _GUICtrlMenu_SetItemDisabled($contextmenu, 3) Else   _GUICtrlMenu_SetItemEnabled($contextmenu, 3) EndIf EndFunc ;==>RefreshContextMenu Func ClearOperation() _GUICtrlTreeView_SetCut($hTreeView, $operation, False) $operation = False EndFunc ;==>ClearOperation Func _CompareFunc($ilParam1, $ilParam2, $fAscending)     ConsoleWrite("ilParam: " & $ilParam1 & " | ilParam2: " & $ilParam2)     ConsoleWrite(@CRLF)     Local $sText1, $sText2, $iCompare     $sText1 = $Data[$ilParam1]     $sText2 = $Data[$ilParam2]     $iCompare = StringCompare($sText1, $sText2) ; case-insensitive     If $fAscending Then ; Ascending case         If $iCompare < 0 Then ; Text1 < Text2 so return -1 (Item1 should precede Item2)             Return -1         ElseIf $iCompare > 0 Then ; Text2 < Text1 so return 1 (Item2 should precede Item1)             Return 1         Else ; Text1 = Text2 so return 0 (don't swap)             Return 0         EndIf     Else ; Descending case         If $iCompare > 0 Then ; Text1 > Text2 so return -1 (Item1 should precede Item2)             Return -1         ElseIf $iCompare < 0 Then ; Text2 > Text1 so return 1 (Item2 should precede Item1)             Return 1         Else ; Text1 = Text2 so return 0 (don't swap)             Return 0         EndIf     EndIf EndFunc   ;==>_CompareFunc Func __GUICtrlTreeView_Sort($hWnd, $hFunc, $fAscending = True)     If $Debug_TV Then __UDF_ValidateClassName($hWnd, $__TREEVIEWCONSTANT_ClassName)     Local $pFunc = DllCallbackGetPtr($hFunc)     If $pFunc = 0 Then Return SetError(1, 0, False)     Local $tSort, $pSort     $tSort = DllStructCreate($TVSORTCB)     $pSort = DllStructGetPtr($tSort)     ; lparam = 1 sort ascending     ; lparam = 0 sort descending     DllStructSetData($tSort, "SortParam", $fAscending) ; It's up to the callback function to do whatever it wants to do with SortParam     DllStructSetData($tSort, "Compare", $pFunc)     If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd)     Local $hItem = _SendMessage($hWnd, $TVM_GETNEXTITEM, $TVGN_CHILD, $TVI_ROOT, 0, "wparam", "handle", "handle")     If Not $hItem Then Return     While $hItem         If _GUICtrlTreeView_GetChildren($hWnd, $hItem) Then             DllStructSetData($tSort, "Parent", $hItem)             _SendMessage($hWnd, $TVM_SORTCHILDRENCB, 0, $pSort, 0, "wparam", "ptr")         EndIf         $hItem = _GUICtrlTreeView_GetNext($hWnd, $hItem)     WEnd     DllStructSetData($tSort, "Parent", $TVI_ROOT)     _SendMessage($hWnd, $TVM_SORTCHILDRENCB, 0, $pSort, 0, "wparam", "ptr")     Return SetError(0, 0, True) EndFunc   ;==>__GUICtrlTreeView_Sort Func TreeItemCopy($hWnd, $hItemSource, $hItemTarget) Local $hNew     Local $hTest = $hItemTarget     Do         $hTest = _GUICtrlTreeView_GetParentHandle($hWnd, $hTest)         If $hTest = $hItemSource Then Return 0 Until $hTest = 0     Local $sText = _GUICtrlTreeView_GetText($hWnd, $hItemSource) If $hItemTarget <> $hWnd Then   $hNew = _GUICtrlTreeView_AddChild($hWnd, $hItemTarget, $sText) Else   $hNew = _GUICtrlTreeView_Add($hWnd, $hItemTarget, $sText) EndIf _GUICtrlTreeView_SetImageIndex($hWnd, $hNew, _GUICtrlTreeView_GetImageIndex($hWnd, $hItemSource))     _GUICtrlTreeView_SetSelectedImageIndex($hWnd, $hNew, _GUICtrlTreeView_GetSelectedImageIndex($hWnd, $hItemSource)) Local $iChildCount = _GUICtrlTreeView_GetChildCount($hWnd, $hItemSource)     If $iChildCount > 0 Then   Local $i, $hRecSource         For $i = 0 To $iChildCount-1             $hRecSource = _GUICtrlTreeView_GetItemByIndex($hWnd, $hItemSource, $i)             TreeItemCopy($hWnd, $hRecSource, $hNew)         Next     EndIf     Return $hNew EndFunc ;==>TreeItemCopy

Edited by Armag3ddon, 28 May 2012 - 09:55 PM.


#6 Armag3ddon

Armag3ddon

    Seeker

  • Active Members
  • 34 posts

Posted 28 May 2012 - 10:28 PM

Apparently, it is not necessary that cut and paste serve any purpose, so here is a stripped down variant of the testing script.

Reproduction steps and behaviour stay the same.

AutoIt         
#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 #include <GuiConstantsEx.au3> #include <GuiTreeView.au3> #include <WindowsConstants.au3> #include <GuiMenu.au3> Opt('MustDeclareVars', 1) Opt("GUIOnEventMode", 1) $Debug_TV = False ; Check ClassName being passed to functions, set to True and use a handle to another control to see it work Global Const $TVSORTCB = "ptr Parent;ptr Compare;lparam SortParam;" Global $Data[500] Global $operation = False Global $hWnd_GUI, $hTreeView, $contextmenu _Main() While 1 Sleep(10) WEnd Func _Main()     Local $hItem[10], $hChildItem[30], $hGrandChildItem[90], $hGrandGrantChildItem[180]     Local $iCItem = 0, $iGCItem = 0, $IGGCItem = 0, $i1 = 10, $i2 = 30, $i3 = 90, $i4 = 180     Local $iStyle = BitOR($TVS_EDITLABELS, $TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_DISABLEDRAGDROP, $TVS_SHOWSELALWAYS)     $hWnd_GUI = GUICreate("TreeView Sort", 400, 300) GUISetOnEvent($GUI_EVENT_CLOSE, "Close", $hWnd_GUI)     $hTreeView = _GUICtrlTreeView_Create($hWnd_GUI, 2, 2, 396, 268, $iStyle, $WS_EX_CLIENTEDGE)     _GUICtrlTreeView_SetUnicodeFormat($hTreeView, True)     GUISetState()     _GUICtrlTreeView_BeginUpdate($hTreeView)     Local $Count = 0     For $a = 0 To 9         $Data[$Count] = StringFormat("[%02d] New Item", $i1)         $hItem[$a] = _GUICtrlTreeView_Add($hTreeView, $hTreeView, $Data[$Count])         _GUICtrlTreeView_SetItemParam($hTreeView, $hItem[$a], $Count)         $Count += 1         For $b = 1 To 3             $Data[$Count] = StringFormat("[%02d] New Child", $i2)             $hChildItem[$iCItem] = _GUICtrlTreeView_AddChild($hTreeView, $hItem[$a], $Data[$Count])             _GUICtrlTreeView_SetItemParam($hTreeView, $hChildItem[$iCItem], $Count)             $Count += 1             For $c = 1 To 3                 $Data[$Count] = StringFormat("[%02d] New Grandchild", $i3)                 $hGrandChildItem[$iGCItem] = _GUICtrlTreeView_AddChild($hTreeView, $hChildItem[$iCItem], $Data[$Count])                 _GUICtrlTreeView_SetItemParam($hTreeView, $hGrandChildItem[$iGCItem], $Count)                 $Count += 1                 For $d = 1 To 2                     $Data[$Count] = StringFormat("[%02d] New GrandGrandChild", $i4)                     $hGrandGrantChildItem[$IGGCItem] = _GUICtrlTreeView_AddChild($hTreeView, $hGrandChildItem[$iGCItem], $Data[$Count])                     _GUICtrlTreeView_SetItemParam($hTreeView, $hGrandGrantChildItem[$IGGCItem], $Count)                     $Count += 1                     $IGGCItem += 1                     $i4 -= 1                 Next                 $iGCItem += 1                 $i3 -= 1             Next             $iCItem += 1             $i2 -= 1         Next         $i1 -= 1     Next _GUICtrlTreeView_EndUpdate($hTreeView) ; Context menu Local $dummy = GUICtrlCreateDummy() Local $ctxmenu = GUICtrlCreateContextMenu($dummy) $contextmenu = GUICtrlGetHandle($ctxmenu) GUICtrlSetOnEvent(GUICtrlCreateMenuItem("New", $ctxmenu), "Dummy") GUICtrlSetOnEvent(GUICtrlCreateMenuItem("Cut", $ctxmenu), "Dummy") GUICtrlSetOnEvent(GUICtrlCreateMenuItem("Copy", $ctxmenu), "Dummy") GUICtrlSetOnEvent(GUICtrlCreateMenuItem("Paste", $ctxmenu), "Dummy") GUICtrlSetOnEvent(GUICtrlCreateMenuItem("Delete", $ctxmenu), "Dummy") GUICtrlCreateMenuItem("", $ctxmenu) GUICtrlSetOnEvent(GUICtrlCreateMenuItem("Refresh", $ctxmenu), "Dummy") GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY") EndFunc   ;==>_Main Func Close() GUIDelete($hWnd_GUI) Exit EndFunc ;==>Close Func WM_NOTIFY($hWnd, $Msg, $wParam, $lParam) Local $struct, $hWndFrom, $hWnd_fileview If $hWnd <> $hWnd_GUI Then Return $GUI_RUNDEFMSG $hWnd_fileview = $hTreeView If Not IsHWnd($hTreeView) Then $hWnd_fileview = GUICtrlGetHandle($hTreeView) $struct = DllStructCreate($tagNMHDR, $lParam) If @error Then Return $GUI_RUNDEFMSG $hWndFrom = HWnd(DllStructGetData($struct, "hWndFrom")) Switch $hWndFrom   Case $hWnd_fileview    Switch DllStructGetData($struct, "code")     Case $NM_RCLICK ; right click      Local $mouse = _WinAPI_GetMousePos(True, $hWnd)      Local $hit_test = _GUICtrlTreeView_HitTest($hTreeView, DllStructGetData($mouse, "X"), DllStructGetData($mouse, "Y"))      Local $selitem = _GUICtrlTreeView_HitTestItem($hTreeView, DllStructGetData($mouse, "X"), DllStructGetData($mouse, "Y"))      If $selitem = 0 Then Return $GUI_RUNDEFMSG      _GUICtrlTreeView_SelectItem($hTreeView, $selitem)      _GUICtrlMenu_TrackPopupMenu($contextmenu, $hWnd_GUI)      Return 1    EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>WM_NOTIFY Func Dummy() ConsoleWrite("Clicked on either New, Copy, Delete or Refresh" & @CRLF) EndFunc ;==>Dummy


#7 Armag3ddon

Armag3ddon

    Seeker

  • Active Members
  • 34 posts

Posted 28 May 2012 - 10:41 PM

I can as well remove the WM_NOTIFY func and the bug persists.

#8 Zedna

Zedna

    AutoIt rulez!

  • MVPs
  • 8,315 posts

Posted 29 May 2012 - 02:20 PM

I can as well remove the WM_NOTIFY func and the bug persists.


Then don't hesitate and post minimalistic reproducing script ...

#9 Armag3ddon

Armag3ddon

    Seeker

  • Active Members
  • 34 posts

Posted 29 May 2012 - 02:49 PM

Ah, sorry. I thought I did. Was too sleepy ;)

Okay, here. Reproduction stays the same: Open first item "[10] New Item", select "[29] New Child" using arrow keys. Erroneous log message appears.

AutoIt         
#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 #include <GuiConstantsEx.au3> #include <GuiTreeView.au3> #include <WindowsConstants.au3> #include <GuiMenu.au3> Opt('MustDeclareVars', 1) Opt("GUIOnEventMode", 1) $Debug_TV = False ; Check ClassName being passed to functions, set to True and use a handle to another control to see it work Global Const $TVSORTCB = "ptr Parent;ptr Compare;lparam SortParam;" Global $Data[500] Global $operation = False Global $hWnd_GUI, $hTreeView, $contextmenu _Main() While 1     Sleep(10) WEnd Func _Main()     Local $hItem[10], $hChildItem[30], $hGrandChildItem[90], $hGrandGrantChildItem[180]     Local $iCItem = 0, $iGCItem = 0, $IGGCItem = 0, $i1 = 10, $i2 = 30, $i3 = 90, $i4 = 180     Local $iStyle = BitOR($TVS_EDITLABELS, $TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_DISABLEDRAGDROP, $TVS_SHOWSELALWAYS)     ; Create GUI     $hWnd_GUI = GUICreate("TreeView Sort", 400, 300)     GUISetOnEvent($GUI_EVENT_CLOSE, "Close", $hWnd_GUI)     $hTreeView = _GUICtrlTreeView_Create($hWnd_GUI, 2, 2, 396, 268, $iStyle, $WS_EX_CLIENTEDGE)     _GUICtrlTreeView_SetUnicodeFormat($hTreeView, True)     GUISetState()     ; Create treeview and fill with some items _GUICtrlTreeView_BeginUpdate($hTreeView)     Local $Count = 0     For $a = 0 To 9         $Data[$Count] = StringFormat("[%02d] New Item", $i1)         $hItem[$a] = _GUICtrlTreeView_Add($hTreeView, $hTreeView, $Data[$Count])         _GUICtrlTreeView_SetItemParam($hTreeView, $hItem[$a], $Count)         $Count += 1         For $b = 1 To 3             $Data[$Count] = StringFormat("[%02d] New Child", $i2)             $hChildItem[$iCItem] = _GUICtrlTreeView_AddChild($hTreeView, $hItem[$a], $Data[$Count])             _GUICtrlTreeView_SetItemParam($hTreeView, $hChildItem[$iCItem], $Count)             $Count += 1             For $c = 1 To 3                 $Data[$Count] = StringFormat("[%02d] New Grandchild", $i3)                 $hGrandChildItem[$iGCItem] = _GUICtrlTreeView_AddChild($hTreeView, $hChildItem[$iCItem], $Data[$Count])                 _GUICtrlTreeView_SetItemParam($hTreeView, $hGrandChildItem[$iGCItem], $Count)                 $Count += 1                 For $d = 1 To 2                     $Data[$Count] = StringFormat("[%02d] New GrandGrandChild", $i4)                     $hGrandGrantChildItem[$IGGCItem] = _GUICtrlTreeView_AddChild($hTreeView, $hGrandChildItem[$iGCItem], $Data[$Count])                     _GUICtrlTreeView_SetItemParam($hTreeView, $hGrandGrantChildItem[$IGGCItem], $Count)                     $Count += 1                     $IGGCItem += 1                     $i4 -= 1                 Next                 $iGCItem += 1                 $i3 -= 1             Next             $iCItem += 1             $i2 -= 1         Next         $i1 -= 1     Next     _GUICtrlTreeView_EndUpdate($hTreeView) ; Context menu     Local $dummy = GUICtrlCreateDummy()     Local $ctxmenu = GUICtrlCreateContextMenu($dummy)     $contextmenu = GUICtrlGetHandle($ctxmenu)     GUICtrlSetOnEvent(GUICtrlCreateMenuItem("New", $ctxmenu), "Dummy")     GUICtrlSetOnEvent(GUICtrlCreateMenuItem("Cut", $ctxmenu), "Dummy")     GUICtrlSetOnEvent(GUICtrlCreateMenuItem("Copy", $ctxmenu), "Dummy")     GUICtrlSetOnEvent(GUICtrlCreateMenuItem("Paste", $ctxmenu), "Dummy")     GUICtrlSetOnEvent(GUICtrlCreateMenuItem("Delete", $ctxmenu), "Dummy")     GUICtrlCreateMenuItem("", $ctxmenu)     GUICtrlSetOnEvent(GUICtrlCreateMenuItem("Refresh", $ctxmenu), "Dummy") EndFunc   ;==>_Main Func Close()     GUIDelete($hWnd_GUI)     Exit EndFunc ;==>Close Func Dummy()     ConsoleWrite("Clicked on either New, Copy, Delete or Refresh" & @CRLF) EndFunc ;==>Dummy


#10 Melba23

Melba23

    Yes, me!

  • Moderators
  • 15,350 posts

Posted 29 May 2012 - 03:03 PM

Armag3ddon,

This has come up a couple of times recently. AutoIt uses the Item Parameters in natively created ListViews and TreeViews to hold the ControlID of the particular item. You are setting the parameter to numbers used by the ControlIDs of other controls and so confusing AutoIt.

The solution is to add a suitably high number ot the parameter so that the value does not repeat a ControlID - I have used 1000 in this example:
AutoIt         
#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 #include <GuiConstantsEx.au3> #include <GuiTreeView.au3> #include <WindowsConstants.au3> #include <GuiMenu.au3> Opt('MustDeclareVars', 1) Opt("GUIOnEventMode", 1) $Debug_TV = False ; Check ClassName being passed to functions, set to True and use a handle to another control to see it work Global Const $TVSORTCB = "ptr Parent;ptr Compare;lparam SortParam;" Global $Data[500] Global $operation = False Global $hWnd_GUI, $hTreeView, $contextmenu _Main() While 1     Sleep(10) WEnd Func _Main()     Local $hItem[10], $hChildItem[30], $hGrandChildItem[90], $hGrandGrantChildItem[180]     Local $iCItem = 0, $iGCItem = 0, $IGGCItem = 0, $i1 = 10, $i2 = 30, $i3 = 90, $i4 = 180     Local $iStyle = BitOR($TVS_EDITLABELS, $TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_DISABLEDRAGDROP, $TVS_SHOWSELALWAYS)     ; Create GUI     $hWnd_GUI = GUICreate("TreeView Sort", 400, 300)     GUISetOnEvent($GUI_EVENT_CLOSE, "Close", $hWnd_GUI)     $hTreeView = _GUICtrlTreeView_Create($hWnd_GUI, 2, 2, 396, 268, $iStyle, $WS_EX_CLIENTEDGE)     _GUICtrlTreeView_SetUnicodeFormat($hTreeView, True)     GUISetState()     ; Create treeview and fill with some items _GUICtrlTreeView_BeginUpdate($hTreeView)     Local $Count = 0     For $a = 0 To 9         $Data[$Count] = StringFormat("[%02d] New Item", $i1)         $hItem[$a] = _GUICtrlTreeView_Add($hTreeView, $hTreeView, $Data[$Count])         _GUICtrlTreeView_SetItemParam($hTreeView, $hItem[$a], 1000 + $Count) ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<         $Count += 1         For $b = 1 To 3             $Data[$Count] = StringFormat("[%02d] New Child", $i2)             $hChildItem[$iCItem] = _GUICtrlTreeView_AddChild($hTreeView, $hItem[$a], $Data[$Count])             _GUICtrlTreeView_SetItemParam($hTreeView, $hChildItem[$iCItem], 1000 + $Count) ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<             $Count += 1             For $c = 1 To 3                 $Data[$Count] = StringFormat("[%02d] New Grandchild", $i3)                 $hGrandChildItem[$iGCItem] = _GUICtrlTreeView_AddChild($hTreeView, $hChildItem[$iCItem], $Data[$Count])                 _GUICtrlTreeView_SetItemParam($hTreeView, $hGrandChildItem[$iGCItem], 1000 + $Count) ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<                 $Count += 1                 For $d = 1 To 2                     $Data[$Count] = StringFormat("[%02d] New GrandGrandChild", $i4)                     $hGrandGrantChildItem[$IGGCItem] = _GUICtrlTreeView_AddChild($hTreeView, $hGrandChildItem[$iGCItem], $Data[$Count])                     _GUICtrlTreeView_SetItemParam($hTreeView, $hGrandGrantChildItem[$IGGCItem], 1000 + $Count) ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<                     $Count += 1                     $IGGCItem += 1                     $i4 -= 1                 Next                 $iGCItem += 1                 $i3 -= 1             Next             $iCItem += 1             $i2 -= 1         Next         $i1 -= 1     Next     _GUICtrlTreeView_EndUpdate($hTreeView) ; Context menu     Local $dummy = GUICtrlCreateDummy()     Local $ctxmenu = GUICtrlCreateContextMenu($dummy)     $contextmenu = GUICtrlGetHandle($ctxmenu)     GUICtrlSetOnEvent(GUICtrlCreateMenuItem("New", $ctxmenu), "Dummy")     GUICtrlSetOnEvent(GUICtrlCreateMenuItem("Cut", $ctxmenu), "Dummy")     GUICtrlSetOnEvent(GUICtrlCreateMenuItem("Copy", $ctxmenu), "Dummy")     GUICtrlSetOnEvent(GUICtrlCreateMenuItem("Paste", $ctxmenu), "Dummy")     GUICtrlSetOnEvent(GUICtrlCreateMenuItem("Delete", $ctxmenu), "Dummy")     GUICtrlCreateMenuItem("", $ctxmenu)     GUICtrlSetOnEvent(GUICtrlCreateMenuItem("Refresh", $ctxmenu), "Dummy") EndFunc   ;==>_Main Func Close()     GUIDelete($hWnd_GUI)     Exit EndFunc ;==>Close Func Dummy()     ConsoleWrite("Clicked on either New, Copy, Delete or Refresh" & @CRLF) EndFunc ;==>Dummy

No "ghost" firings now when I run it - and the sorting should still work as you have suitably differentiated parameters to work with. ;)
M23
  • Armag3ddon likes this
StringSize - Automatically size controls to fit text - ExtMsgBox - A user customisable replacement for MsgBox

Toast - Small GUIs which pop out of the Systray - Marquee - Scrolling tickertape GUIs

Scrollbars - Automatically sized scrollbars with a single command - GUIFrame - Subdivide GUIs into many adjustable frames

GUIExtender - Extend and retract multiple sections within a GUI - NoFocusLines - Remove the dotted focus lines from buttons, sliders, radios and checkboxes

ChooseFileFolder - Single and multiple selections from specified path tree structure - - Notify - Small notifications on the edge of the display

RecFileListToArray - An alternative to _FileListToArray with user-defined include/exclude masks, maximum recursion level, sorting and displayed path options

GUIListViewEx - Insert, delete, move, drag and sort ListView items


#11 Armag3ddon

Armag3ddon

    Seeker

  • Active Members
  • 34 posts

Posted 29 May 2012 - 03:10 PM

Oh my! Awesome, thanks! ;)
You are surely my hero of the day!




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users