Armag3ddon Posted May 27, 2012 Share Posted May 27, 2012 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: 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 EndIfI 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 windowThere 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:expandcollapse popup; 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] = "" Link to comment Share on other sites More sharing options...
Zedna Posted May 27, 2012 Share Posted May 27, 2012 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. Resources UDF Â ResourcesEx UDF Â AutoIt Forum Search Link to comment Share on other sites More sharing options...
Armag3ddon Posted May 28, 2012 Author Share Posted May 28, 2012 (edited) 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 May 28, 2012 by Armag3ddon Link to comment Share on other sites More sharing options...
Zedna Posted May 28, 2012 Share Posted May 28, 2012 (edited) 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 May 28, 2012 by Zedna Resources UDF Â ResourcesEx UDF Â AutoIt Forum Search Link to comment Share on other sites More sharing options...
Armag3ddon Posted May 28, 2012 Author Share Posted May 28, 2012 (edited) 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:expandcollapse popup#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 May 28, 2012 by Armag3ddon Link to comment Share on other sites More sharing options...
Armag3ddon Posted May 28, 2012 Author Share Posted May 28, 2012 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. expandcollapse popup#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 Link to comment Share on other sites More sharing options...
Armag3ddon Posted May 28, 2012 Author Share Posted May 28, 2012 I can as well remove the WM_NOTIFY func and the bug persists. Link to comment Share on other sites More sharing options...
Zedna Posted May 29, 2012 Share Posted May 29, 2012 I can as well remove the WM_NOTIFY func and the bug persists.Then don't hesitate and post minimalistic reproducing script ... Resources UDF Â ResourcesEx UDF Â AutoIt Forum Search Link to comment Share on other sites More sharing options...
Armag3ddon Posted May 29, 2012 Author Share Posted May 29, 2012 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.expandcollapse popup#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 Link to comment Share on other sites More sharing options...
Moderators Melba23 Posted May 29, 2012 Moderators Share Posted May 29, 2012 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:expandcollapse popup#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 ;==>DummyNo "ghost" firings now when I run it - and the sorting should still work as you have suitably differentiated parameters to work with. M23 Armag3ddon 1  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 columnsChooseFileFolder ---- Single and multiple selections from specified path treeview listingDate_Time_Convert -- Easily convert date/time formats, including the language usedExtMsgBox --------- A highly customisable replacement for MsgBoxGUIExtender -------- Extend and retract multiple sections within a GUIGUIFrame ---------- Subdivide GUIs into many adjustable framesGUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView itemsGUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeViewMarquee ----------- Scrolling tickertape GUIsNoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxesNotify ------------- Small notifications on the edge of the displayScrollbars ----------Automatically sized scrollbars with a single commandStringSize ---------- Automatically size controls to fit textToast -------------- Small GUIs which pop out of the notification area  Link to comment Share on other sites More sharing options...
Armag3ddon Posted May 29, 2012 Author Share Posted May 29, 2012 Oh my! Awesome, thanks! You are surely my hero of the day! 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