From 6702bcfd5009bd02d031cca8e1af27451654b696 Mon Sep 17 00:00:00 2001 From: WildByDesign Date: Fri, 30 Jan 2026 05:22:58 -0500 Subject: [PATCH 01/14] Update drag and drop code - using SHDoDragDrop - drag and drop to external programs is working - drag and drop to (or within) Files Au3 is not working yet - only using DROPEFFECT_COPY and DROPEFFECT_LINK right now - DROPEFFECT_MOVE works well, but is removed right now for purpose of testing --- lib/DropSourceObject.au3 | 340 +++++++++++++++ lib/GUIFrame_WBD_Mod.au3 | 1 - lib/IUnknown.au3 | 31 ++ lib/ProjectConstants.au3 | 48 +++ lib/TreeListExplorer.au3 | 901 +++++++++++++++++++++++++++------------ src/main.au3 | 786 ++++++++++++++++++++++++++-------- 6 files changed, 1661 insertions(+), 446 deletions(-) create mode 100644 lib/DropSourceObject.au3 create mode 100644 lib/IUnknown.au3 create mode 100644 lib/ProjectConstants.au3 diff --git a/lib/DropSourceObject.au3 b/lib/DropSourceObject.au3 new file mode 100644 index 0000000..4dcd01b --- /dev/null +++ b/lib/DropSourceObject.au3 @@ -0,0 +1,340 @@ +#include-once +#include "ProjectConstants.au3" +#include "IUnknown.au3" + +#include +#include +#include + +Global $g_hListview, $g_hTreeView, $sTargetCtrl, $hTLESystem + +; In this file we're probably just interested in these methods. The rest is just stuff to make our internal object work! +; __Mthd_QueryContinueDrag, __Mthd_GiveFeedback +; __Mthd_DragEnterTarget, __Mthd_DragLeaveTarget + +; __Mthd_QueryContinueDrag is called in a loop - it asks us if we want to continue the drag/drop. +; And we say: +; "drop!" if the left and right buttons are up. +; "cancel!" if the esc key is pressed. +; otherwise "Continue looping!" + +; __Mthd_GiveFeedback provides us with the oportunity to update the mouse cursor. +; We're delegating this to the system by returning DRAGDROP_S_USEDEFAULTCURSORS + +; __Mthd_DragEnterTarget & __Mthd_DragLeaveTarget lets us know what we're currently hovering over. (as a window handle) +; Just in case you want to do anything with that info!. + +;-------------------------------------------------------------------------------------------------------------- +; Our DropSource Object in memory... +;-------------------------------------------------------------------------------------------------------------- +; +; The left most column aren't part of the object - they're interface pointers. +; All of them are valid "object pointers" for our object. Regardless, some functions require us to provide a ptr to a specific interface. +; +; The "Thunk" methods are stubs, and redirect to the methods on pIUnkVtab. +; IIDs in aSupportedIIDs[] must be in the same order as the vtables in our layout. +; +; +; +- iIfaceCount +; | +; pIUnknown-----> +- pIUnkVtab --------> +- pQueryInterface +; | +- pAddRef +; | +- pRelease +; | +; pIDropSource -> += pIDrpSrcVTab -----> +- pQueryInterfaceThunk +; | +- pAddRefThunk +; | +- pReleaseThunk +; | +- pQueryContinueDrag +; | +- pGiveFeedback +; | +; pIDrpSrcNtfy -> += pIDrpSrcNtfyVTab--> +- pQueryInterfaceThunk +; | +- pAddRefThunk +; | +- pReleaseThunk +; | +- pDragEnterTarget +; | +- pDragLeaveTarget +; +- iRefCount +; | +; +- aSupportedIIDs[IID_IUnknown, IID_IDropSource, IID_IDropSourceNotify] +; | | +; +- hTarget +; +;-------------------------------------------------------------------------------------------------------------- + + + +Global $__g_aObjects[1][20] +Global $__g_hMthd_QueryInterface, $__g_hMthd_AddRef, $__g_hMthd_Release +Global $__g_hMthd_QueryInterfaceThunk, $__g_hMthd_AddRefThunk, $__g_hMthd_ReleaseThunk +Global $__g_hMthd_QueryContinueDrag, $__g_hMthd_GiveFeedback +Global $__g_hMthd_DragEnterTarget, $__g_hMthd_DragLeaveTarget + +Func CreateDropSource() + If Not $__g_hMthd_QueryInterface Then + $__g_hMthd_QueryInterface = DllCallbackRegister("__Mthd_QueryInterface", "long", "ptr;ptr;ptr") + $__g_hMthd_AddRef = DllCallbackRegister("__Mthd_AddRef", "long", "ptr") + $__g_hMthd_Release = DllCallbackRegister("__Mthd_Release", "long", "ptr") + + $__g_hMthd_QueryInterfaceThunk = DllCallbackRegister("__Mthd_QueryInterfaceThunk", "long", "ptr;ptr;ptr") + $__g_hMthd_AddRefThunk = DllCallbackRegister("__Mthd_AddRefThunk", "long", "ptr") + $__g_hMthd_ReleaseThunk = DllCallbackRegister("__Mthd_ReleaseThunk", "long", "ptr") + EndIf + + If Not $__g_hMthd_QueryContinueDrag Then + $__g_hMthd_QueryContinueDrag = DllCallbackRegister("__Mthd_QueryContinueDrag", "long", "ptr;bool;dword") + $__g_hMthd_GiveFeedback = DllCallbackRegister("__Mthd_GiveFeedback", "long", "ptr;dword") + EndIf + + If Not $__g_hMthd_DragEnterTarget Then + $__g_hMthd_DragEnterTarget = DllCallbackRegister("__Mthd_DragEnterTarget", "long", "ptr;hwnd") + $__g_hMthd_DragLeaveTarget = DllCallbackRegister("__Mthd_DragLeaveTarget", "long", "ptr") + EndIf + + Local $iObjectId = UBound($__g_aObjects) + ReDim $__g_aObjects[$iObjectId + 1][UBound($__g_aObjects, 2)] + $__g_aObjects[0][0] += 1 + + Local $tUnknownVTab = DllStructCreate("ptr pFunc[3]") + $tUnknownVTab.pFunc(1) = DllCallbackGetPtr($__g_hMthd_QueryInterface) + $tUnknownVTab.pFunc(2) = DllCallbackGetPtr($__g_hMthd_AddRef) + $tUnknownVTab.pFunc(3) = DllCallbackGetPtr($__g_hMthd_Release) + + Local $tDropSrcVTab = DllStructCreate("ptr pFunc[5]") + $tDropSrcVTab.pFunc(1) = DllCallbackGetPtr($__g_hMthd_QueryInterfaceThunk) + $tDropSrcVTab.pFunc(2) = DllCallbackGetPtr($__g_hMthd_AddRefThunk) + $tDropSrcVTab.pFunc(3) = DllCallbackGetPtr($__g_hMthd_ReleaseThunk) + $tDropSrcVTab.pFunc(4) = DllCallbackGetPtr($__g_hMthd_QueryContinueDrag) + $tDropSrcVTab.pFunc(5) = DllCallbackGetPtr($__g_hMthd_GiveFeedback) + + Local $tDropSrcNotifyVTab = DllStructCreate("ptr pFunc[5]") + $tDropSrcNotifyVTab.pFunc(1) = DllCallbackGetPtr($__g_hMthd_QueryInterfaceThunk) + $tDropSrcNotifyVTab.pFunc(2) = DllCallbackGetPtr($__g_hMthd_AddRefThunk) + $tDropSrcNotifyVTab.pFunc(3) = DllCallbackGetPtr($__g_hMthd_ReleaseThunk) + $tDropSrcNotifyVTab.pFunc(4) = DllCallbackGetPtr($__g_hMthd_DragEnterTarget) + $tDropSrcNotifyVTab.pFunc(5) = DllCallbackGetPtr($__g_hMthd_DragLeaveTarget) + + Local $tagObject = "align 4;int iImplIfaces;ptr pVTab[3];int iRefCnt;" & _ + "byte IID_IUnknown[16];" & _ + "byte IID_IDropSource[16];" & _ + "byte IID_IDropSourceNotify[16];" & _ + "hwnd hTarget" + + Local $tObject = DllStructCreate($tagObject) + $tObject.pVTab(1) = DllStructGetPtr($tUnknownVTab) + $tObject.pVTab(2) = DllStructGetPtr($tDropSrcVTab) + $tObject.pVTab(3) = DllStructGetPtr($tDropSrcNotifyVTab) + + $tObject.iRefCnt = 1 + $tObject.iImplIfaces = 3 + _WinAPI_GUIDFromStringEx($sIID_IUnknown, DllStructGetPtr($tObject, "IID_IUnknown")) + _WinAPI_GUIDFromStringEx($sIID_IDropSource, DllStructGetPtr($tObject, "IID_IDropSource")) + _WinAPI_GUIDFromStringEx($sIID_IDropSourceNotify, DllStructGetPtr($tObject, "IID_IDropSourceNotify")) + + Local $pObject = DllStructGetPtr($tObject, "pVTab") + + $__g_aObjects[$iObjectId][0] = $pObject + $__g_aObjects[$iObjectId][1] = $tObject + $__g_aObjects[$iObjectId][2] = $tUnknownVTab + $__g_aObjects[$iObjectId][3] = $tDropSrcVTab + $__g_aObjects[$iObjectId][4] = $tDropSrcNotifyVTab + + Return $pObject +EndFunc ;==>CreateDropSource + +Func DestroyDropSource($pObject) + If (Not $pObject) Or (Not IsPtr($pObject)) Then Return SetError($ERROR_INVALID_PARAMETER, 0, False) + + For $i = 0 To UBound($__g_aObjects) - 1 + If $__g_aObjects[$i][0] = $pObject Then ExitLoop + Next + If $i = UBound($__g_aObjects) Then Return SetError($ERROR_INVALID_PARAMETER, 0, False) + + For $j = 0 To UBound($__g_aObjects, 2) - 1 + $__g_aObjects[$i][$j] = 0 + Next + $__g_aObjects[0][0] -= 1 + + If Not $__g_aObjects[0][0] Then + DllCallbackFree($__g_hMthd_QueryInterface) + DllCallbackFree($__g_hMthd_AddRef) + DllCallbackFree($__g_hMthd_Release) + DllCallbackFree($__g_hMthd_QueryInterfaceThunk) + DllCallbackFree($__g_hMthd_AddRefThunk) + DllCallbackFree($__g_hMthd_ReleaseThunk) + DllCallbackFree($__g_hMthd_QueryContinueDrag) + DllCallbackFree($__g_hMthd_GiveFeedback) + DllCallbackFree($__g_hMthd_DragEnterTarget) + DllCallbackFree($__g_hMthd_DragLeaveTarget) + + $__g_hMthd_QueryInterface = 0 + $__g_hMthd_AddRef = 0 + $__g_hMthd_Release = 0 + $__g_hMthd_QueryInterfaceThunk = 0 + $__g_hMthd_AddRefThunk = 0 + $__g_hMthd_ReleaseThunk = 0 + $__g_hMthd_QueryContinueDrag = 0 + $__g_hMthd_GiveFeedback = 0 + $__g_hMthd_DragEnterTarget = 0 + $__g_hMthd_DragLeaveTarget = 0 + EndIf +EndFunc ;==>DestroyDropSource + + +#Region Internal IUnknown Methods + +Func __Mthd_QueryInterface($pThis, $pIID, $ppObj) + Local $hResult = $S_OK + + Local $iIIDCnt = DllStructGetData(DllStructCreate("int", Ptr($pThis - 4)), 1) + Local $tThis = DllStructCreate(StringFormat("align 4;ptr pVTab[%d];int iRefCnt", $iIIDCnt), $pThis) + + Local $pTestIID = DllStructGetPtr($tThis, "iRefCnt") + 4 + If Not $ppObj Then + $hResult = $E_POINTER + Else + For $i = 0 To $iIIDCnt - 1 + If _WinAPI_StringFromGUID($pIID) = _WinAPI_StringFromGUID(Ptr($pTestIID)) Then + DllStructSetData(DllStructCreate("ptr", $ppObj), 1, Ptr($pThis + $i * $PTR_LEN)) + __Mthd_AddRef($pThis) + ExitLoop + EndIf + $pTestIID += 16 + Next + If $i = $iIIDCnt Then $hResult = $E_NOINTERFACE + + EndIf + Return $hResult +EndFunc ;==>__Mthd_QueryInterface + +Func __Mthd_AddRef($pThis) + Local $iImplIfaces = DllStructGetData(DllStructCreate("int", Ptr($pThis - 4)), 1) + Local $tThis = DllStructCreate(StringFormat("align 4;ptr pVTab[%d];int iRefCnt", $iImplIfaces), $pThis) + $tThis.iRefCnt += 1 + Return $tThis.iRefCnt +EndFunc ;==>__Mthd_AddRef + +Func __Mthd_Release($pThis) + Local $iImplIfaces = DllStructGetData(DllStructCreate("int", Ptr($pThis - 4)), 1) + Local $tThis = DllStructCreate(StringFormat("align 4;ptr pVTab[%d];int iRefCnt", $iImplIfaces), $pThis) + $tThis.iRefCnt -= 1 + Return $tThis.iRefCnt +EndFunc ;==>__Mthd_Release + +Func __Mthd_QueryInterfaceThunk($pThis, $pIID, $ppObj) + Local $hResult = $S_OK + Local $tIID = DllStructCreate($tagGUID, $pIID) + If _WinAPI_StringFromGUID($tIID) = $sIID_IUnknown Then + DllStructSetData(DllStructCreate("ptr", $ppObj), 1, $pThis) + Else + $pThis = Ptr($pThis - $PTR_LEN) + Local $pVTab = DllStructGetData(DllStructCreate("ptr", $pThis), 1) + Local $pFunc = DllStructGetData(DllStructCreate("ptr", $pVTab), 1) + Local $aCall = DllCallAddress("long", $pFunc, "ptr", $pThis, "ptr", $pIID, "ptr", $ppObj) + $hResult = $aCall[0] + EndIf + Return $hResult +EndFunc ;==>__Mthd_QueryInterfaceThunk + +Func __Mthd_AddRefThunk($pThis) + $pThis = Ptr($pThis - $PTR_LEN) + Return _AddRef($pThis) +EndFunc ;==>__Mthd_AddRefThunk + +Func __Mthd_ReleaseThunk($pThis) + $pThis = Ptr($pThis - $PTR_LEN) + Return _Release($pThis) +EndFunc ;==>__Mthd_ReleaseThunk +#EndRegion Internal IUnknown Methods + +#Region Internal IDataSource Methods + +Func __Mthd_QueryContinueDrag($pThis, $bEscapePressed, $iKeyState) + #forceref $pThis, $bEscapePressed, $iKeyState + +;~ Key State values may be combined. Test using BitAND! +;~ If BitAND($MK_RBUTTON, $iKeyState) Then ... + +;~ Key Constants: +;~ $MK_RBUTTON +;~ $MK_SHIFT +;~ $MK_CONTROL +;~ $MK_MBUTTON +;~ $MK_XBUTTON1 +;~ $MK_XBUTTON2 + + Local $iReturn = $S_OK + If $bEscapePressed Then + $iReturn = $DRAGDROP_S_CANCEL + Else + If Not BitAND($iKeyState, BitOR($MK_LBUTTON, $MK_RBUTTON)) Then $iReturn = $DRAGDROP_S_DROP + EndIf + + Return $iReturn +EndFunc ;==>__Mthd_QueryContinueDrag + + +Func __Mthd_GiveFeedback($pThis, $iEffect) + #forceref $pThis, $iEffect + +;~ Drop effect values may be combined. Test using BitAND! +;~ If BitAND($DROPEFFECT_COPY, $iEffect) Then ... + +;~ Effect Constants... +;~ $DROPEFFECT_NONE +;~ $DROPEFFECT_COPY +;~ $DROPEFFECT_MOVE +;~ $DROPEFFECT_LINK +;~ $DROPEFFECT_SCROLL + + Select + Case $sTargetCtrl = 'Tree' + ; use __TreeListExplorer_GetPath($hTLESystem) to obtain initial tree path + ; reset selection back to original after + Local $hItemHover = TreeItemFromPoint2($g_hTreeView) + _WinAPI_SetFocus($g_hTreeView) + _GUICtrlTreeView_SelectItem($g_hTreeView, $hItemHover) + _GUICtrlTreeView_SetState($g_hTreeView, __TreeListExplorer_GetPath($hTLESystem), $TVIS_SELECTED, True) + Case $sTargetCtrl = 'List' + ; + Case Else + ; clear + EndSelect + + Return $DRAGDROP_S_USEDEFAULTCURSORS +EndFunc ;==>__Mthd_GiveFeedback + +#EndRegion Internal IDataSource Methods + +#Region Internal IDataSourceNotify Methods +Func __Mthd_DragEnterTarget($pThis, $hTarget) + Local Const $iDataOffset = 52 + $PTR_LEN + Local $tData = DllStructCreate("align 4; hwnd hTarget", Ptr($pThis + $iDataOffset)) + DllStructSetData($tData, "hTarget", $hTarget) + Local $hTargetCtrl = DllStructSetData($tData, "hTarget", $hTarget) + If $hTargetCtrl = $g_hTreeView Then + ConsoleWrite("drag target is treeview" & @CRLF) + $sTargetCtrl = 'Tree' + EndIf + If $hTargetCtrl = $g_hListview Then + ConsoleWrite("drag target is listview" & @CRLF) + $sTargetCtrl = 'List' + EndIf + ;ConsoleWrite("target: " & DllStructSetData($tData, "hTarget", $hTarget) & @CRLF) + ;ConsoleWrite("parent: " & _WinAPI_GetAncestor(DllStructSetData($tData, "hTarget", $hTarget), $GA_PARENT) & @CRLF) + + Return $S_OK +EndFunc ;==>__Mthd_DragEnterTarget + +Func __Mthd_DragLeaveTarget($pThis) + Local Const $iDataOffset = 52 + $PTR_LEN + Local $tData = DllStructCreate("align 4; hwnd hTarget", Ptr($pThis + $iDataOffset)) + DllStructSetData($tData, "hTarget", 0) + $sTargetCtrl = '' + + Return $S_OK +EndFunc ;==>__Mthd_DragLeaveTarget +#EndRegion Internal IDataSourceNotify Methods + +Func TreeItemFromPoint2($hWnd) + Local $tMPos = _WinAPI_GetMousePos(True, $hWnd) + Return _GUICtrlTreeView_HitTestItem($hWnd, DllStructGetData($tMPos, 1), DllStructGetData($tMPos, 2)) +EndFunc ;==>TreeItemFromPoint2 diff --git a/lib/GUIFrame_WBD_Mod.au3 b/lib/GUIFrame_WBD_Mod.au3 index efe78a0..f0c1f55 100644 --- a/lib/GUIFrame_WBD_Mod.au3 +++ b/lib/GUIFrame_WBD_Mod.au3 @@ -107,7 +107,6 @@ Func _GUIFrame_Create($hWnd, $iSepOrient = 0, $iSepPos = 0, $iSepSize = 5, $iX = Local $iSeperator_Pos, $hSeparator, $hFirstFrame, $hSecondFrame, $nSepPercent Local $iFrame_Style = BitOR(0x40000000, 0x10000000) ; $WS_CHILD, WS_VISIBLE Local $iFrame_Ext_Style = 0x02000000 ; WS_EX_COMPOSITED - ;Local $iFrame_Ext_Style = 0 ; Set separator size Local $iSeparatorSize = 9 diff --git a/lib/IUnknown.au3 b/lib/IUnknown.au3 new file mode 100644 index 0000000..98cb066 --- /dev/null +++ b/lib/IUnknown.au3 @@ -0,0 +1,31 @@ +#include-once +#include "ProjectConstants.au3" +#include + +;This allows us to call the IUnknown methods directly from an object pointer. +;(You could also use ObjCreateInterface to create an object type from the ptr). + +Func _QueryInterface($pThis, $sIID) + If (Not $pThis) Or (Not IsPtr($pThis)) Then Return SetError($ERROR_INVALID_PARAMETER) + Local $pVTab = DllStructGetData(DllStructCreate("ptr", $pThis), 1) + Local $pFunc = DllStructGetData(DllStructCreate("ptr", $pVTab), 1) + Local $tIID = _WinAPI_GUIDFromString($sIID) + Local $aCall = DllCallAddress("long", $pFunc, "ptr", $pThis, "struct*", $tIID, "ptr*", 0) + Return SetError($aCall[0], 0, $aCall[3]) +EndFunc ;==>_QueryInterface + +Func _AddRef($pThis) + If (Not $pThis) Or (Not IsPtr($pThis)) Then Return SetError($ERROR_INVALID_PARAMETER) + Local $pVTab = DllStructGetData(DllStructCreate("ptr", $pThis), 1) + Local $pFunc = DllStructGetData(DllStructCreate("ptr", $pVTab + $PTR_LEN), 1) + Local $aCall = DllCallAddress("uint", $pFunc, "ptr", $pThis) + Return $aCall[0] +EndFunc ;==>_AddRef + +Func _Release($pThis) + If (Not $pThis) Or (Not IsPtr($pThis)) Then Return SetError($ERROR_INVALID_PARAMETER) + Local $pVTab = DllStructGetData(DllStructCreate("ptr", $pThis), 1) + Local $pFunc = DllStructGetData(DllStructCreate("ptr", $pVTab + 2 * $PTR_LEN), 1) + Local $aCall = DllCallAddress("uint", $pFunc, "ptr", $pThis) + Return $aCall[0] +EndFunc ;==>_Release diff --git a/lib/ProjectConstants.au3 b/lib/ProjectConstants.au3 new file mode 100644 index 0000000..c1c0020 --- /dev/null +++ b/lib/ProjectConstants.au3 @@ -0,0 +1,48 @@ +#include-once + +#include +#include +#include +#include +#include + +Global Const $PTR_LEN = @AutoItX64 ? 8 : 4 + +Global Const $sIID_IUnknown = "{00000000-0000-0000-C000-000000000046}" +Global Const $sIID_IShellFolder = "{000214E6-0000-0000-C000-000000000046}" +Global Const $sIID_IDataObject = "{0000010e-0000-0000-C000-000000000046}" +Global Const $sIID_IDropSource = "{00000121-0000-0000-C000-000000000046}" +Global Const $sIID_IDropSourceNotify = "{0000012B-0000-0000-C000-000000000046}" + + +Global Const $DRAGDROP_S_DROP = 0x00040100 +Global Const $DRAGDROP_S_CANCEL = 0x00040101 +Global Const $DRAGDROP_S_USEDEFAULTCURSORS = 0x00040102 +Global Const $DRAGDROP_E_NOTREGISTERED = 0x80040100 +Global Const $DRAGDROP_E_ALREADYREGISTERED = 0x80040101 + +Global Const $DROPEFFECT_NONE = 0 +Global Const $DROPEFFECT_COPY = 1 +Global Const $DROPEFFECT_MOVE = 2 +Global Const $DROPEFFECT_LINK = 4 +Global Const $DROPEFFECT_SCROLL = 0x80000000 + +Global Const $MK_LBUTTON = 0x0001 +Global Const $MK_RBUTTON = 0x0002 +Global Const $MK_SHIFT = 0x0004 +Global Const $MK_CONTROL = 0x0008 +Global Const $MK_MBUTTON = 0x0010 +Global Const $MK_XBUTTON1 = 0x0020 +Global Const $MK_XBUTTON2 = 0x0040 + +Global Const $tagIShellFolder = _ + "ParseDisplayName hresult(hwnd; ptr*; wstr; ulong*; ptr*; ulong*);" & _ + "EnumObjects hresult(hwnd; ulong; ptr*);" & _ + "BindToObject hresult(ptr; ptr*; struct*; ptr*);" & _ + "BindToStorage hresult(ptr; ptr*; struct*; ptr*);" & _ + "CompareIDs hresult(lparam; ptr; ptr);" & _ + "CreateViewObject hresult(hwnd; struct*; ptr*);" & _ + "GetAttributesOf hresult(uint; ptr; ulong*);" & _ + "GetUIObjectOf hresult(hwnd; uint; ptr*; struct*; uint*; ptr*);" & _ + "GetDisplayNameOf hresult(ptr; ulong; ptr*);" & _ + "SetNameOf hresult(hwnd; ptr; wstr; ulong; ptr*);" \ No newline at end of file diff --git a/lib/TreeListExplorer.au3 b/lib/TreeListExplorer.au3 index f54b89e..a6c6401 100644 --- a/lib/TreeListExplorer.au3 +++ b/lib/TreeListExplorer.au3 @@ -1,17 +1,18 @@ #include-once -#include -#include -#include -#include -#include -#include #include #include -#include #include -#include -#Include +#include +#include +#include +#include +#include #include +#Include +#include +#include +#include +#include ; #INDEX# ======================================================================================================================= ; Title .........: TreeListExplorer @@ -20,7 +21,7 @@ ; Description ...: UDF to use a Listview or Treeview as a File/Folder Explorer ; Author(s) .....: Kanashius ; Special Thanks.: WildByDesign for testing this UDF a lot and helping me to make it better -; Version .......: 2.12 +; Version .......: 2.13 ; =============================================================================================================================== ; #CURRENT# ===================================================================================================================== @@ -30,10 +31,14 @@ ; __TreeListExplorer_CreateSystem ; __TreeListExplorer_DeleteSystem ; __TreeListExplorer_AddView +; __TreeListExplorer_SetViewIconSize +; __TreeListExplorer_FileGetIconBitmap +; __TreeListExplorer_ComboSetDropDownHeight ; __TreeListExplorer_SetCallback ; __TreeListExplorer_RemoveView ; __TreeListExplorer_OpenPath ; __TreeListExplorer_Reload +; __TreeListExplorer_ReloadView ; __TreeListExplorer_GetPath ; __TreeListExplorer_GetRoot ; __TreeListExplorer_GetSelected @@ -57,6 +62,7 @@ ; __TreeListExplorer__FileGetIconIndex ; __TreeListExplorer__ExpandTreeitem ; __TreeListExplorer__UpdateTreeItemContent +; __TreeListExplorer__TreeViewGetTree ; __TreeListExplorer__GetTreeViewItemDepth ; __TreeListExplorer__UpdateTreeItemExpandable ; __TreeListExplorer__GetDrives @@ -94,9 +100,15 @@ Global $__TreeListExplorer_Callback_ListViewPaths = 32 ; =============================================================================================================================== ; #INTERNAL_USE_ONLY GLOBAL CONSTANTS # ========================================================================================= -Global $__TreeListExplorer__Type_TreeView = 1, $__TreeListExplorer__Type_ListView = 2, $__TreeListExplorer__Type_Input = 3 -Global $__TreeListExplorer__Status_UpdateView = 1, $__TreeListExplorer__Status_ExpandTree = 2 -Global $__TreeListExplorer__Status_LoadTree = 4, $__TreeListExplorer__Status_WaitOpenPath = 8 +Global Const $__TreeListExplorer__Type_TreeView = 1, $__TreeListExplorer__Type_ListView = 2, $__TreeListExplorer__Type_Input = 4 +Global Const $__TreeListExplorer__Type_Combo = 8, $__TreeListExplorer__Type_ComboEx = 16 +Global Const $__TreeListExplorer__Status_UpdateView = 1, $__TreeListExplorer__Status_ExpandTree = 2 +Global Const $__TreeListExplorer__Status_LoadTree = 4, $__TreeListExplorer__Status_WaitOpenPath = 8 +Global Const $__TreeListExplorer__Icon_Folder = "FOLDER", $__TreeListExplorer__Icon_File = "FILE", $__TreeListExplorer__Icon_Disc = "DISC" +Global Const $__TreeListExplorer__Icon_ChangeableInput = "CHANGEABLE", $__TreeListExplorer__Icon_Harddrive = "HARDDRIVE" +Global Const $__TreeListExplorer__Icon_CDROM = "CDROM", $__TreeListExplorer__Icon_Networkdrive = "NETWORKDRIVE" +Global Const $__TreeListExplorer__Icon_Unknown = "UNKNOWN", $__TreeListExplorer__Icon_This_PC = "THISPC" +Global Const $__TreeListExplorer__Icon_Dummy = "DUMMY" ; =============================================================================================================================== ; #INTERNAL_USE_ONLY GLOBAL VARIABLES # ========================================================================================= @@ -106,9 +118,8 @@ Global $__TreeListExplorer__Data[] ; #FUNCTION# ==================================================================================================================== ; Name ..........: __TreeListExplorer_StartUp ; Description ...: StartUp of the TLE UDF initializing required variables. Must be called before using other UDF functions. -; Syntax ........: __TreeListExplorer_StartUp([$iLang = $__TreeListExplorer_Lang_EN[, $iIconSize = 16]]) +; Syntax ........: __TreeListExplorer_StartUp([$iLang = $__TreeListExplorer_Lang_EN]) ; Parameters ....: $iLang - [optional] an integer to set the language ($__TreeListExplorer_Lang_EN, $__TreeListExplorer_Lang_DE). Default is $__TreeListExplorer_Lang_EN. -; $iIconSize - [optional] the size for icons in the Tree-/ListView. Default is 16. ; Return values .: True on success. ; Author ........: Kanashius ; Modified ......: @@ -118,38 +129,21 @@ Global $__TreeListExplorer__Data[] ; and create the $__TreeListExplorer_Lang_?? variable. ; ; Errors: -; 1 - Parameter not valid (@extended: 1 - $iLang, 2 - $iIconSize) +; 1 - Parameter not valid (@extended: 1 - $iLang) ; Related .......: ; Link ..........: ; Example .......: No ; =============================================================================================================================== -Func __TreeListExplorer_StartUp($iLang = $__TreeListExplorer_Lang_EN, $iIconSize = 16) +Func __TreeListExplorer_StartUp($iLang = $__TreeListExplorer_Lang_EN) Local $arLangData = [["Filename", "Size", "Date created", "This PC"], _ ["Dateiname", "Größe", "Erstelldatum", "Dieser PC"]] If Not IsInt($iLang) Or $iLang<0 Or $iLang>UBound($arLangData)-1 Then Return SetError(1, 1, False) - If Not IsInt($iIconSize) Or $iIconSize<0 Then Return SetError(1, 2, False) $__TreeListExplorer__Data.iDoubleClickTime = 500 Local $arDoubleClickTime = DllCall('user32.dll', 'uint', 'GetDoubleClickTime') If Not @error And UBound($arDoubleClickTime)>0 And IsInt($arDoubleClickTime[0]) Then $__TreeListExplorer__Data.iDoubleClickTime = $arDoubleClickTime[0] - $__TreeListExplorer__Data.iIconSize = $iIconSize _GDIPlus_Startup() - Local $hImageList = _GUIImageList_Create($iIconSize, $iIconSize, 5, 1) - _GUIImageList_AddIcon($hImageList, 'shell32.dll', 3) ; Folder-Icon - _GUIImageList_AddIcon($hImageList, 'shell32.dll', 110) ; Folder-Icon checked - _GUIImageList_AddIcon($hImageList, 'shell32.dll', 0) ; File-Icon - _GUIImageList_AddIcon($hImageList, 'shell32.dll', 5) ; Disc-Icon - _GUIImageList_AddIcon($hImageList, 'shell32.dll', 7) ; Changeableinput-Icon - _GUIImageList_AddIcon($hImageList, 'shell32.dll', 8) ; Harddrive-Icon - _GUIImageList_AddIcon($hImageList, 'shell32.dll', 11) ; CDROM-Icon - _GUIImageList_AddIcon($hImageList, 'shell32.dll', 12) ; Networkdrive-Icon - _GUIImageList_AddIcon($hImageList, 'shell32.dll', 53) ; Unknown-Icon - _GUIImageList_AddIcon($hImageList, 'shell32.dll', 15) ; This PC - _GUIImageList_AddIcon($hImageList, 'shell32.dll', 109) ; Dummy element (Crossed O) - _GUIImageList_AddIcon($hImageList, 'shell32.dll', 305) ; Dummy element (Crossed O) - $__TreeListExplorer__Data.iCustomIconsStartIndex = _GUIImageList_GetImageCount($hImageList) - $__TreeListExplorer__Data.hIconList = $hImageList Local $mIcons[] $__TreeListExplorer__Data.mIcons = $mIcons Local $mSystems[] @@ -170,34 +164,6 @@ Func __TreeListExplorer_StartUp($iLang = $__TreeListExplorer_Lang_EN, $iIconSize Return True EndFunc -; #INTERNAL_USE_ONLY# =========================================================================================================== -; Name ..........: __TreeListExplorer_FreeIconCache -; Description ...: Removes all cached icons for all extensions or files -; Syntax ........: __TreeListExplorer_FreeIconCache() -; Parameters ....: -; Return values .: None -; Author ........: Kanashius -; Modified ......: -; Remarks .......: -; Related .......: -; Link ..........: -; Example .......: No -; =============================================================================================================================== -Func __TreeListExplorer_FreeIconCache() - Local $hImageList = $__TreeListExplorer__Data.hIconList, $iCustomIndex = $__TreeListExplorer__Data.iCustomIconsStartIndex - While _GUIImageList_GetImageCount($hImageList)>$iCustomIndex - Local $hIcon = _GUIImageList_GetIcon($hImageList, $iCustomIndex) - _GUIImageList_Remove($hImageList, $iCustomIndex) - _GUIImageList_DestroyIcon($hIcon) - WEnd - Local $mEmpty[] - $__TreeListExplorer__Data["mIcons"] = $mEmpty - Local $arSystemKeys = MapKeys($__TreeListExplorer__Data.mSystems) - For $i=0 To UBound($arSystemKeys)-1 Step 1 - __TreeListExplorer_Reload(__TreeListExplorer__GetHandleFromSystemID($arSystemKeys[$i]), True) - Next -EndFunc - ; #FUNCTION# ==================================================================================================================== ; Name ..........: __TreeListExplorer_Shutdown ; Description ...: Shutdown of the TLE UDF. Must be called before closing the program. If not called, the program may not exit. @@ -219,11 +185,10 @@ Func __TreeListExplorer_Shutdown() DllCallbackFree($__TreeListExplorer__Data.hProc) _WinAPI_UnhookWindowsHookEx($__TreeListExplorer__Data.hKeyPrevHook) DllCallbackFree($__TreeListExplorer__Data.hKeyProc) - _GUIImageList_Destroy($__TreeListExplorer__Data.hIconList) + __TreeListExplorer_FreeIconCache(Default, False) Local $mMap[] $__TreeListExplorer__Data = $mMap _GDIPlus_Shutdown() - __TreeListExplorer_FreeIconCache() Return True EndFunc @@ -342,25 +307,27 @@ EndFunc ; Description ...: Add a view (TreeView/ListView) to a TLE system. ; Syntax ........: __TreeListExplorer_AddView($hSystem, $hView, [$bShowFolders = Default, [$bShowFiles = Default, [$bNavigation = True, [$bListViewFolderUp = True, [$iLineNumber = @ScriptLineNumber]]]]]) ; Parameters ....: $hSystem - the system handle. -; $hView - the view to add (must be a TreeView or ListView). +; $hView - the view to add (must be a TreeView, ListView, Input or ComboBoxEx). ; $bShowFolders - [optional] a boolean defining, if folders will be shown in the view. Default depends on the view type (see remarks). ; $bShowFiles - [optional] a boolean defining, if files will be shown in the view. Default depends on the view type (see remarks). -; $bNavigation - [optional] boolean. Default is True. If False, the view cannot be used to navigate folders. (ListViews only) -; $bListViewFolderUp - [optional] boolean. Default is True. If False, the view wil not have the ".." folder at the top to go to the parent directory. (ListViews only) -; $bLVDefaultColumns - [optional] boolean. Default is True. If True, the default columns for the listview will be created. (ListViews only) -; $bEnableSorting - [optional] boolean. Default is True. If True, simple sorting is enabled for the ListView, where clicking at the header sorts by that column. (ListViews only) +; $bNavigation - [optional] boolean. Default is True. If False, the view cannot be used to navigate folders. (ListView only) +; $bListViewFolderUp - [optional] boolean. Default is True. If False, the view wil not have the ".." folder at the top to go to the parent directory. (ListView only) +; $bLVDefaultColumns - [optional] boolean. Default is True. If True, the default columns for the listview will be created. (ListView only) +; $bEnableSorting - [optional] boolean. Default is True. If True, simple sorting is enabled for the ListView, where clicking at the header sorts by that column. (ListView/ComboBox) ; $iLineNumber - [optional] an integer value. Default is @ScriptLineNumber. (should not be changed) ; Return values .: True on success ; Author ........: Kanashius ; Modified ......: -; Remarks .......: Default for $bShowFolders is True for TreeViews and ListViews, False for Inputs. +; Remarks .......: Default for $bShowFolders is True (TreeView, ListView, ComboBoxEx) and False (Input). ; -; Default for $bShowFiles is True for ListViews and False for TreeViews and Inputs. +; Default for $bShowFiles is True (ListView, ComboBoxEx) and False (TreeView, Input). ; ; Additional functionality can be accomplished using callbacks (click detection/handle loading/filtering/custom columns/sorting/...). ; See __TreeListExplorer_SetCallback for further information. ; ; $bEnableSorting only allows for simple sorting. To sort by yourself, you can use the $__TreeListExplorer_Callback_ListViewPaths callback (see __TreeListExplorer_SetCallback). +; The ComboBoxEx uses the same sorting method as the ListView, so if it is enabled, it is sorted by name (with folders at the top). +; The $__TreeListExplorer_Callback_ListViewPaths callback can be set for the ComboBoxEx as well. ; ; Errors: ; 1 - $hSystem is not a valid TLE system @@ -387,6 +354,10 @@ Func __TreeListExplorer_AddView($hSystem, $hView, $bShowFolders = Default, $bSho $iType = $__TreeListExplorer__Type_ListView ElseIf StringInStr($sClass, "Edit") And (Not BitAND(_WinAPI_GetWindowLong($hView, $GWL_STYLE), $ES_MULTILINE)) Then ; check if control is input $iType = $__TreeListExplorer__Type_Input + ElseIf StringInStr($sClass, "ComboBoxEx") Then + $iType = $__TreeListExplorer__Type_ComboEx + ElseIf StringInStr($sClass, "ComboBox") Then + $iType = $__TreeListExplorer__Type_Combo Else Return SetError(2, 50, False) ; $hView is not a valid control (wrong control type) EndIf @@ -404,11 +375,11 @@ Func __TreeListExplorer_AddView($hSystem, $hView, $bShowFolders = Default, $bSho Case $__TreeListExplorer__Type_TreeView If $bShowFolders = Default Then $bShowFolders=True If $bShowFiles = Default Then $bShowFiles=False - _GUICtrlTreeView_SetNormalImageList($hView, $__TreeListExplorer__Data.hIconList) + _GUICtrlTreeView_DeleteAll($hView) Case $__TreeListExplorer__Type_ListView If $bShowFolders = Default Then $bShowFolders=True If $bShowFiles = Default Then $bShowFiles=True - _GUICtrlListView_SetImageList($hView, $__TreeListExplorer__Data.hIconList, 1) + _GUICtrlListView_DeleteAllItems($hView) _GUICtrlListView_SetExtendedListViewStyle($hView, BitOR($LVS_EX_FULLROWSELECT, $LVS_EX_SUBITEMIMAGES)) Local $iListWidth = _WinAPI_GetWindowWidth($hView) If $bLVDefaultColumns Then @@ -425,6 +396,14 @@ Func __TreeListExplorer_AddView($hSystem, $hView, $bShowFolders = Default, $bSho $bShowFolders=False $bShowFiles=False GUICtrlSetData($hView, "") + Case $__TreeListExplorer__Type_Combo + $bShowFolders=True + $bShowFiles=True + _GUICtrlComboBox_ResetContent($hView) + Case $__TreeListExplorer__Type_ComboEx + $bShowFolders=True + $bShowFiles=True + _GUICtrlComboBoxEx_ResetContent($hView) EndSwitch Local $mView[] $mView.hWnd = $hView @@ -437,13 +416,7 @@ Func __TreeListExplorer_AddView($hSystem, $hView, $bShowFolders = Default, $bSho $mView.sSelected = -1 $mView.iUpdating = 0 $mView.iPathIndex = 0 - $mView.bNavigation = $bNavigation - $mView.bListViewFolderUp = $bListViewFolderUp - Local $mSorting[] - $mSorting.bEnabled = $bEnableSorting - $mSorting.iCol = $mView.iPathIndex - $mSorting.iDir = 0 ; 0 ASC, 1 DESC - $mView.mSorting = $mSorting + $mView.iIconSize = -1 $mView.sCallbackClick = Default $mView.sCallbackDoubleClick = Default $mView.sCallbackLoading = Default @@ -451,12 +424,303 @@ Func __TreeListExplorer_AddView($hSystem, $hView, $bShowFolders = Default, $bSho $mView.sCallbackListViewItemCreated = Default $mView.sCallbackListViewPaths = Default $mView.iLineNumber = $iLineNumber + Local $bAddSortingEntries = False + Switch $iType + Case $__TreeListExplorer__Type_Combo, $__TreeListExplorer__Type_ComboEx + $mView.iComboListHeight = 100 + Local $hCombo = $hView + If $iType = $__TreeListExplorer__Type_ComboEx Then $hCombo = _GUICtrlComboBoxEx_GetComboControl($hView) + Local $tInfo + _GUICtrlComboBox_GetComboBoxInfo($hCombo, $tInfo) + $mView.hCombo = DllStructGetData($tInfo, "hCombo") + $mView.hComboEdit = DllStructGetData($tInfo, "hEdit") + If $iType = $__TreeListExplorer__Type_ComboEx Then $mView.hComboEdit = _GUICtrlComboBoxEx_GetEditControl($hView) + $mView.hComboList = DllStructGetData($tInfo, "hList") + $bAddSortingEntries = True + Case $__TreeListExplorer__Type_ListView + $mView.bNavigation = $bNavigation + $mView.bListViewFolderUp = $bListViewFolderUp + $bAddSortingEntries = True + EndSwitch + If $bAddSortingEntries Then + Local $mSorting[] + $mSorting.bEnabled = $bEnableSorting + $mSorting.iCol = $mView.iPathIndex + $mSorting.iDir = 0 ; 0 ASC, 1 DESC + $mView.mSorting = $mSorting + EndIf $__TreeListExplorer__Data["mViews"][$hView] = $mView $__TreeListExplorer__Data["mSystems"][$iSystem]["mViews"][$hView] = 1 - __TreeListExplorer__UpdateView($hView) + __TreeListExplorer_SetViewIconSize($hView) ; includes __TreeListExplorer__UpdateView + If @error Then __TreeListExplorer__UpdateView($hView, True) + Return True +EndFunc + + +; #FUNCTION# ==================================================================================================================== +; Name ..........: __TreeListExplorer_SetViewIconSize +; Description ...: Set the icon size for the Tree-/ListView. +; Syntax ........: __TreeListExplorer_SetViewIconSize($hView[, $iIconSize = 16]) +; Parameters ....: $hView - the view where the callback should be added to (must be a TreeView, ListView or ComboBoxEx). +; $iIconSize - (optional) the desired icon size. Default: 16. +; Return values .: True on success +; Author ........: Kanashius +; Modified ......: +; Remarks .......: Errors: +; 1 - Parameter is invalid (@extended 1 - $hView, 2 - $iIconSize) +; Related .......: +; Link ..........: +; Example .......: No +; =============================================================================================================================== +Func __TreeListExplorer_SetViewIconSize($hView, $iIconSize = 16) + If Not IsHWnd($hView) Then + $hView = GUICtrlGetHandle($hView) + If @error Then Return SetError(2, @error, False) ; $hView is not a control + EndIf + If Not IsHWnd($hView) Or Not MapExists($__TreeListExplorer__Data.mViews, $hView) Then Return SetError(1, 1, False) + If $__TreeListExplorer__Data.mViews[$hView].iType=$__TreeListExplorer__Type_Input Or $__TreeListExplorer__Data.mViews[$hView].iType=$__TreeListExplorer__Type_Combo Then Return SetError(1, 1, False) ; inputs and normal combo boxes cannot have icons + If Not IsInt($iIconSize) Then Return SetError(1, 2, False) + If $__TreeListExplorer__Data["mViews"][$hView]["iIconSize"]<>$iIconSize Then + Local $iIconSizeBefore = $__TreeListExplorer__Data["mViews"][$hView]["iIconSize"] + $__TreeListExplorer__Data["mViews"][$hView]["iIconSize"] = $iIconSize + If Not MapExists($__TreeListExplorer__Data.mIcons, $iIconSize) Then + Local $mIcon[], $mCache[], $mViews[] + $mIcon["hList"] = _GUIImageList_Create($iIconSize, $iIconSize, 5, 1, 12) + $mCache[$__TreeListExplorer__Icon_File] = _GUIImageList_AddIcon($mIcon.hList, "shell32.dll", 0, True) + $mCache[$__TreeListExplorer__Icon_Folder] = _GUIImageList_AddIcon($mIcon.hList, "shell32.dll", 3, True) + $mCache[$__TreeListExplorer__Icon_Disc] = _GUIImageList_AddIcon($mIcon.hList, "shell32.dll", 5, True) + $mCache[$__TreeListExplorer__Icon_ChangeableInput] = _GUIImageList_AddIcon($mIcon.hList, "shell32.dll", 7, True) + $mCache[$__TreeListExplorer__Icon_Harddrive] = _GUIImageList_AddIcon($mIcon.hList, "shell32.dll", 8, True) + $mCache[$__TreeListExplorer__Icon_CDROM] = _GUIImageList_AddIcon($mIcon.hList, "shell32.dll", 11, True) + $mCache[$__TreeListExplorer__Icon_Networkdrive] = _GUIImageList_AddIcon($mIcon.hList, "shell32.dll", 12, True) + $mCache[$__TreeListExplorer__Icon_Unknown] = _GUIImageList_AddIcon($mIcon.hList, "shell32.dll", 53, True) + $mCache[$__TreeListExplorer__Icon_This_PC] = _GUIImageList_AddIcon($mIcon.hList, "shell32.dll", 15, True) + $mCache[$__TreeListExplorer__Icon_Dummy] = _GUIImageList_AddIcon($mIcon.hList, "shell32.dll", 109, True) + $mIcon["mCache"] = $mCache + $mViews[$hView] = 1 + $mIcon["mViews"] = $mViews + $__TreeListExplorer__Data["mIcons"][$iIconSize] = $mIcon + Else + $__TreeListExplorer__Data["mIcons"][$iIconSize]["mViews"][$hView] = 1 + EndIf + Switch $__TreeListExplorer__Data.mViews[$hView].iType + Case $__TreeListExplorer__Type_TreeView + _GUICtrlTreeView_SetNormalImageList($hView, $__TreeListExplorer__Data.mIcons[$iIconSize].hList) + _GUICtrlTreeView_SetIndent($hView, $iIconSize+4) + Case $__TreeListExplorer__Type_ListView + _GUICtrlListView_SetImageList($hView, $__TreeListExplorer__Data.mIcons[$iIconSize].hList, 0) + _GUICtrlListView_SetImageList($hView, $__TreeListExplorer__Data.mIcons[$iIconSize].hList, 1) + Case $__TreeListExplorer__Type_ComboEx + _GUICtrlComboBoxEx_SetImageList($hView, $__TreeListExplorer__Data.mIcons[$iIconSize].hList) + Case Else + ConsoleWrite("Control does not support an icon size."&@crlf) + EndSwitch + If $iIconSizeBefore<>-1 And MapExists($__TreeListExplorer__Data.mIcons, $iIconSizeBefore) Then ; MapExists crashes with $iIconSizeBefore = -1 for some reason... + MapRemove($__TreeListExplorer__Data.mIcons[$iIconSizeBefore]["mViews"], $hView) + If UBound(MapKeys($__TreeListExplorer__Data.mIcons[$iIconSizeBefore]["mViews"]))<=0 Then __TreeListExplorer_FreeIconCache($iIconSizeBefore, False) + EndIf + __TreeListExplorer_ReloadView($hView, True) + EndIf + Return True +EndFunc + +; #FUNCTION# ==================================================================================================================== +; Name ..........: __TreeListExplorer_FileGetIconBitmap +; Description ...: Get the bitmap of an icon for a file. (May need to be converted to a HBitmap to use in _GUIImageList.) +; Syntax ........: __TreeListExplorer_FileGetIconBitmap($sPath[, $iSize = Default[, $sExt = Default]]) +; Parameters ....: $sPath - the absolute path. +; $iIconSize - (optional) the desired size of the icon. +; Default: If $hView is provided the size for that control is used, 16 otherwise. +; $sExt - (optional) if Default the extension will be parsed from $sPath. (Ignored for folder/drive paths) +; Return values .: The bitmap +; Author ........: Kanashius +; Modified ......: +; Remarks .......: Errors: +; 1 - Invalid parameter (@extended 2 - $iIconSize) +; 2 - Bitmap could not be found/created/... +; Related .......: +; Link ..........: +; Example .......: No +; =============================================================================================================================== +Func __TreeListExplorer_FileGetIconBitmap($sPath, $iIconSize = Default, $sExt = Default) + If Not ($iIconSize<>Default Or IsInt($iIconSize)) Then Return SetError(1, 2, 0) + Local $sIconPath = -1, $iIconIndex = 0, $bAddForExtension = False + ; check for drives + Local $arRegExpDrive = StringRegExp($sPath, "^([^\/]+?:)\/*$", 1) + If UBound($arRegExpDrive)>0 Then + $sIconPath = "shell32.dll" + $iIconIndex = __TreeListExplorer__GetDriveIconId($arRegExpDrive[0]) + EndIf + ; check for folders (would also match drives) + If __TreeListExplorer__PathIsFolder($sPath) Then + $sIconPath = "shell32.dll" + $iIconIndex = 3 ; Default folder icon + EndIf + If $sIconPath=-1 And $sExt=Default Then + Local $arExt = StringRegExp($sPath, "^.*[^\\](\.[^\\]*?)$", 1) + If Not (@error Or UBound($arExt)<>1) Then $sExt = StringLower($arExt[0]) + EndIf + If $sIconPath=-1 Then + ; Handling for special extensions + Switch $sExt + Case ".exe" + $sIconPath = $sPath + Case ".url" + $sIconPath = IniRead($sPath, "InternetShortcut", "IconFile", -1) + $iIconIndex = IniRead($sPath, "InternetShortcut", "IconIndex", -1) + Case ".lnk" ; todo add the link symbol (arrow) to the icon + Local $arShortcutData = FileGetShortcut($sPath) + If $arShortcutData[4]<>"" Then ; icon file provided + $sIconPath = $arShortcutData[4] + $iIconIndex = $arShortcutData[5] + Else ; otherwise get icon from the linked path + Return __TreeListExplorer_FileGetIconBitmap($arShortcutData[0], $iIconSize) + EndIf + EndSwitch + EndIf + If $sIconPath=-1 Then + Local $sRegData = RegRead("HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\" & $sExt, "ProgID") + If @error Then + $sRegData = RegRead("HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\" & $sExt & "\UserChoice", "ProgID") + If @error Then + $sRegData = RegRead("HKCR\" & $sExt, "") + EndIf + EndIf + If $sRegData<>"" Then $sRegData = RegRead("HKCR\" & $sRegData & "\DefaultIcon", "") + If $sRegData="" Then $sRegData = _WinAPI_AssocQueryString($sExt, $ASSOCSTR_DEFAULTICON) + If StringInStr($sRegData, "@")=1 Then ; Handle urls with @{...} + Local $sIconPath = _WinAPI_LoadIndirectString($sRegData) + If @error Then $sIconPath = -1 + Local $arRes = StringRegExp($sIconPath, "^(.*\\)(.*-)(\d+)(\.\S+)$", 1) + If Not (@error And UBound($arRes)<>4) Then ; check for files with a pixel resolution closer to $iIconSize + Local $arFiles = _FileListToArray($arRes[0], $arRes[1]&"*"&$arRes[3]) + Local $arOptions[UBound($arFiles)-1][2], $iCount = 0 + For $i=1 To UBound($arFiles)-1 Step 1 ; get icon size for all files + Local $arFileParts = StringRegExp($arFiles[$i], "^.*-(\d+)\.\S+$", 1) + If Not @error Then + $arOptions[$iCount][0] = Int($arFileParts[0]) + $arOptions[$iCount][1] = $arFiles[$i] + $iCount+=1 + EndIf + Next + ReDim $arOptions[$iCount][2] + _ArraySort($arOptions) ; sort by size + For $i=0 To UBound($arOptions)-1 Step 1 ; take the best icon to be used (>= target icon size); Resize will be done later + If $iIconSize<=$arOptions[$i][0] Then + $sIconPath = $arRes[0]&$arOptions[$i][1] + ExitLoop + EndIf + Next + EndIf + ElseIf StringInStr($sRegData, ",") Then ; Handle , e.g.: ...shell32.dll, 0 + Local $arParts = StringRegExp($sRegData, '"?(.*?)"?,(-?\d+)', 1) + If UBound($arParts)=2 Then + $sIconPath = $arParts[0] + $iIconIndex = $arParts[1] + EndIf + ElseIf $sRegData<>"" Then ; Handle path without index + $sIconPath = $sRegData + EndIf + $bAddForExtension = True + EndIf + Local $hBitmap = 0 + If $sIconPath=-1 Then + Local $tSHFILEINFO = DllStructCreate($tagSHFILEINFO) + Local $dwFlags = BitOR($SHGFI_USEFILEATTRIBUTES, $SHGFI_ICON, $SHGFI_LARGEICON) ; $SHGFI_ICON + _WinAPI_ShellGetFileInfo($sPath, $dwFlags, $FILE_ATTRIBUTE_NORMAL, $tSHFILEINFO) + If DllStructGetData($tSHFILEINFO, 1)>0 Then + Local $hIcon = _WinAPI_Create32BitHICON(DllStructGetData($tSHFILEINFO, 1)) + _WinAPI_DestroyIcon(DllStructGetData($tSHFILEINFO, 1)) + $hBitmap = _GDIPlus_BitmapCreateFromHICON($hIcon) + _WinAPI_DestroyIcon($hIcon) + EndIf + EndIf + If $sIconPath<>-1 Or $hBitmap<>0 Then + Local $sIconExt = StringRight($sIconPath, 4) + If $hBitmap=0 And ($sIconExt=".dll" Or $sIconExt=".exe" Or $sIconExt=".ico") Then ; icon to extract + Local $hIcon = _WinAPI_ShellExtractIcon($sIconPath, $iIconIndex, $iIconSize, $iIconSize) + Local $hBitmap = _GDIPlus_BitmapCreateFromHICON($hIcon) + _WinAPI_DestroyIcon($hIcon) + If $hIcon<>0 Then Return $hBitmap + Else ; normal image file + If $hBitmap=0 Then $hBitmap = _GDIPlus_BitmapCreateFromFile($sIconPath) + If $hBitmap<>0 Then + ; todo check size to only scale up + Local $hBitmapResized = _GDIPlus_ImageResize($hBitmap, $iIconSize, $iIconSize) + _GDIPlus_BitmapDispose($hBitmap) + Return $hBitmapResized + EndIf + EndIf + EndIf + Local $hIcon = _WinAPI_ShellExtractIcon("shell32.dll", 0, $iIconSize, $iIconSize) ; Default file icon + If $hIcon<>0 Then Return SetExtended(1, _GDIPlus_BitmapCreateFromHICON($hIcon)) + Return SetError(2, 0, 0) +EndFunc + +; #FUNCTION# ==================================================================================================================== +; Name ..........: __TreeListExplorer_ComboSetDropDownHeight +; Description ...: Set the height of the drop down list of a comboboxex control. +; Syntax ........: __TreeListExplorer_ComboSetDropDownHeight($hView[, $iHeight = 100]) +; Parameters ....: $hView - the handle of the control +; $iHeight - (optional) Default: 100. The height in pixel. +; Return values .: True on success, False otherwise +; Author ........: Kanashius +; Modified ......: +; Remarks .......: +; Related .......: +; Link ..........: +; Example .......: No +; =============================================================================================================================== +Func __TreeListExplorer_ComboSetDropDownHeight($hView, $iHeight = 100) + If Not IsHWnd($hView) Or Not MapExists($__TreeListExplorer__Data.mViews, $hView) Then Return SetError(1, 1, False) + If Not ($__TreeListExplorer__Data.mViews[$hView].iType = $__TreeListExplorer__Type_Combo Or $__TreeListExplorer__Data.mViews[$hView].iType = $__TreeListExplorer__Type_ComboEx) Then Return SetError(1, 1, False) + If Not IsInt($iHeight) Then Return SetError(1, 2, False) + $__TreeListExplorer__Data["mViews"][$hView]["iComboListHeight"] = $iHeight + __TreeListExplorer__UpdateView($hView) ; no force update required; begin/end update is always called Return True EndFunc +; #FUNCTION# ==================================================================================================================== +; Name ..........: __TreeListExplorer_FreeIconCache +; Description ...: Removes cached icons +; Syntax ........: __TreeListExplorer_FreeIconCache($iIconSize[, $bReload = True]) +; Parameters ....: $iIconSize - (optional) Default: Free all IconSizes. If defined, only for that icon size, if it exists. +; $bReload - (optional) Default: True. Reload views using the cache. +; Return values .: None +; Author ........: Kanashius +; Modified ......: +; Remarks .......: +; Related .......: +; Link ..........: +; Example .......: No +; =============================================================================================================================== +Func __TreeListExplorer_FreeIconCache($iIconSize = Default, $bReload = True) + Local $arFree[0][0] + If $iIconSize=Default Then + For $iIconSize in MapKeys($__TreeListExplorer__Data.mIcons) + _GUIImageList_Destroy($__TreeListExplorer__Data.mIcons[$iIconSize].hList) + Local $arKeys = MapKeys($__TreeListExplorer__Data.mIcons[$iIconSize]["mViews"]) + MapRemove($__TreeListExplorer__Data.mIcons, $iIconSize) + If $bReload Then + For $hView in $arKeys + __TreeListExplorer_ReloadView($hView, True) + Next + EndIf + Next + Else + If MapExists($__TreeListExplorer__Data.mIcons, $iIconSize) Then + _GUIImageList_Destroy($__TreeListExplorer__Data.mIcons[$iIconSize].hList) + Local $arKeys = MapKeys($__TreeListExplorer__Data.mIcons[$iIconSize]["mViews"]) + MapRemove($__TreeListExplorer__Data.mIcons, $iIconSize) + If $bReload Then + For $hView in $arKeys + __TreeListExplorer_ReloadView($hView, True) + Next + EndIf + EndIf + EndIf +EndFunc + ; #FUNCTION# ==================================================================================================================== ; Name ..........: __TreeListExplorer_SetCallback ; Description ...: Add/Remove a callback to a TLE TreeView/ListView. Allows for click/load handling, filtering, custom columns, sorting,... @@ -565,6 +829,12 @@ Func __TreeListExplorer_RemoveView($hView) Local $iSystem = $mView.iSystem Local $iType = $mView.iType + ; Remove view from icon map + Local $iIconSize = $__TreeListExplorer__Data["mViews"][$hView]["iIconSize"] + If $iIconSize<>-1 And MapExists($__TreeListExplorer__Data.mIcons, $iIconSize) Then + MapRemove($__TreeListExplorer__Data.mIcons[$iIconSize]["mViews"], $hView) + If UBound(MapKeys($__TreeListExplorer__Data.mIcons[$iIconSize]["mViews"]))<=0 Then __TreeListExplorer_FreeIconCache($iIconSize, False) + EndIf ; Remove from maps first, to prevent events (WinProc) from being handled during deletion MapRemove($__TreeListExplorer__Data.mViews, $hView) MapRemove($__TreeListExplorer__Data["mSystems"][$iSystem]["mViews"], $hView) @@ -583,6 +853,15 @@ Func __TreeListExplorer_RemoveView($hView) WEnd _GUICtrlListView_SetImageList($hView, 0) _GUICtrlListView_EndUpdate($hView) + Case $__TreeListExplorer__Type_Combo + _GUICtrlComboBox_BeginUpdate($hView) + _GUICtrlComboBox_ResetContent($hView) + _GUICtrlComboBox_EndUpdate($hView) + Case $__TreeListExplorer__Type_ComboEx + _GUICtrlComboBoxEx_BeginUpdate($hView) + _GUICtrlComboBoxEx_ResetContent($hView) + _GUICtrlComboBoxEx_SetImageList($hView, 0) + _GUICtrlComboBoxEx_EndUpdate($hView) EndSwitch Return True EndFunc @@ -656,6 +935,40 @@ Func __TreeListExplorer_Reload($hSystem, $bAllFoldersOnPath = False) If $bAllFoldersOnPath Then $__TreeListExplorer__Data["mSystems"][$iSystem]["bReloadAllFolders"] = False EndFunc +; #FUNCTION# ==================================================================================================================== +; Name ..........: __TreeListExplorer_ReloadView +; Description ...: Reloads the folders and files in all views of the system. +; Syntax ........: __TreeListExplorer_ReloadView($hView[, $bAllFoldersOnPath = False]) +; Parameters ....: $hSystem - the view handle. +; $bAllFoldersOnPath - [optional] if false, only the current folder is reloaded. +; If true, all folders in the view will be reloaded. +; Default is False. +; Return values .: None +; Author ........: Kanashius +; Modified ......: +; Remarks .......: +; Related .......: +; Link ..........: +; Example .......: No +; =============================================================================================================================== +Func __TreeListExplorer_ReloadView($hView, $bAllFoldersOnPath = False) + If Not IsHWnd($hView) Then + $hView = GUICtrlGetHandle($hView) + If @error Then Return SetError(2, @error, False) ; $hView is not a control + EndIf + If Not IsHWnd($hView) Or Not MapExists($__TreeListExplorer__Data.mViews, $hView) Then Return SetError(1, 0, False) + Local $mView = $__TreeListExplorer__Data.mViews[$hView] + Local $iSystem = $mView.iSystem + + $__TreeListExplorer__Data["mSystems"][$iSystem]["bReloadFolder"] = True + If $bAllFoldersOnPath Then $__TreeListExplorer__Data["mSystems"][$iSystem]["bReloadAllFolders"] = True + + __TreeListExplorer__UpdateView($hView) + + $__TreeListExplorer__Data["mSystems"][$iSystem]["bReloadFolder"] = False + If $bAllFoldersOnPath Then $__TreeListExplorer__Data["mSystems"][$iSystem]["bReloadAllFolders"] = False +EndFunc + ; #FUNCTION# ==================================================================================================================== ; Name ..........: __TreeListExplorer_GetPath ; Description ...: Get the current folder, relative to the root folder. @@ -950,7 +1263,7 @@ EndFunc ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name ..........: __TreeListExplorer__UpdateView ; Description ...: Update a view to match a TLE systems root folder and current folder -; Syntax ........: __TreeListExplorer__UpdateView($hView) +; Syntax ........: __TreeListExplorer__UpdateView($hView[, $bReload = False]) ; Parameters ....: $hView - the control handle. ; $bReload - [optional] Default False. Forces a reload. ; Return values .: None @@ -971,6 +1284,10 @@ Func __TreeListExplorer__UpdateView($hView, $bReload = False) _GUICtrlTreeView_BeginUpdate($hView) Case $__TreeListExplorer__Type_ListView _GUICtrlListView_BeginUpdate($hView) + Case $__TreeListExplorer__Type_Combo + _GUICtrlComboBox_BeginUpdate($hView) + Case $__TreeListExplorer__Type_ComboEx + _GUICtrlComboBoxEx_BeginUpdate($hView) EndSwitch ; Root different Local $bRootOrFolderChanged = False @@ -987,14 +1304,15 @@ Func __TreeListExplorer__UpdateView($hView, $bReload = False) _GUICtrlTreeView_DeleteAll($hView) Local $hRoot If $mSystem.sRoot="" Then - $hRoot = _GUICtrlTreeView_Add($hView, 0, $__TreeListExplorer__Data.arLangData[$__TreeListExplorer__Data.iLang][3], 9, 9) ; maybe remove text here + Local $iIconIndex = $__TreeListExplorer__Data.mIcons[$__TreeListExplorer__Data.mViews[$hView].iIconSize].mCache[$__TreeListExplorer__Icon_This_PC] + $hRoot = _GUICtrlTreeView_Add($hView, 0, $__TreeListExplorer__Data.arLangData[$__TreeListExplorer__Data.iLang][3], $iIconIndex, $iIconIndex) ; maybe remove text here Else Local $arPath = __TreeListExplorer__GetPathAndLast($mSystem.sRoot) $hRoot = _GUICtrlTreeView_Add($hView, 0, $arPath[1], 0, 0) EndIf _GUICtrlTreeView_AddChild($hView, $hRoot, "HasChilds", 10, 10) __TreeListExplorer__ExpandTreeitem($hView, $hRoot) - Case $__TreeListExplorer__Type_ListView + Case $__TreeListExplorer__Type_ListView, $__TreeListExplorer__Type_Combo, $__TreeListExplorer__Type_ComboEx $bReload = True EndSwitch __TreeListExplorer__HandleViewCallback($hView, "sCallbackLoading", $mSystem.sRoot, False) @@ -1069,16 +1387,24 @@ Func __TreeListExplorer__UpdateView($hView, $bReload = False) __TreeListExplorer__HandleSystemCallback($iSystem, "sCallbackSelect") EndIf __TreeListExplorer__HandleViewCallback($hView, "sCallbackLoading", $mSystem.sFolder, False) - Case $__TreeListExplorer__Type_ListView + Case $__TreeListExplorer__Type_ListView, $__TreeListExplorer__Type_Combo, $__TreeListExplorer__Type_ComboEx If $bUpdateFolder Then __TreeListExplorer__HandleViewCallback($hView, "sCallbackLoading", $mSystem.sFolder, True) ; clear old data $__TreeListExplorer__Data["mViews"][$hView]["iIndex"] = -1 __TreeListExplorer__SetViewUpdating($hView, True, $__TreeListExplorer__Status_UpdateView) - _GUICtrlListView_DeleteAllItems($hView) + Switch $mView.iType + Case $__TreeListExplorer__Type_ListView + _GUICtrlListView_DeleteAllItems($hView) + Case $__TreeListExplorer__Type_Combo + _GUICtrlComboBox_ResetContent($hView) + Case $__TreeListExplorer__Type_ComboEx + _GUICtrlComboBoxEx_SetCurSel($hView, -1) + _GUICtrlComboBoxEx_ResetContent($hView) + EndSwitch ; do not display .. folder in root directory,... - If $mSystem.sFolder<>"" And $mView.bNavigation And $mView.bListViewFolderUp Then - _GUICtrlListView_AddItem($hView, "", 0) + If $mView.iType=$__TreeListExplorer__Type_ListView And $mSystem.sFolder<>"" And $mView.bNavigation And $mView.bListViewFolderUp Then + _GUICtrlListView_AddItem($hView, "", $__TreeListExplorer__Data.mIcons[$__TreeListExplorer__Data.mViews[$hView].iIconSize].mCache[$__TreeListExplorer__Icon_Folder]) _GUICtrlListView_SetItemText($hView, 0, "..", $mView.iPathIndex) EndIf ; collect drives/folders/files @@ -1133,11 +1459,12 @@ Func __TreeListExplorer__UpdateView($hView, $bReload = False) Next EndIf ; add entries to listview + If $mView.iType = $__TreeListExplorer__Type_Combo Then _GUICtrlComboBox_InitStorage(UBound($arPaths), 150, 300) + If $mView.iType = $__TreeListExplorer__Type_ComboEx Then _GUICtrlComboBoxEx_InitStorage(UBound($arPaths), 150, 300) For $i=0 to UBound($arPaths)-1 Local $sFile = $arPaths[$i][$mView.iPathIndex] Local $sFilePath = $sPath & $sFile Local $bDriveOrFolder = __TreeListExplorer__PathIsFolder($sFilePath) - Local $iIconIndex = __TreeListExplorer__FileGetIconIndex($sFilePath) Local $sFileName = $sFile, $sExt = "" If Not $bDriveOrFolder Then Local $arFileParts = StringRegExp($sFilename, "^(.+?)(\.[^.]{1,5}){0,1}$", 1) @@ -1148,32 +1475,68 @@ Func __TreeListExplorer__UpdateView($hView, $bReload = False) EndIf If $mView.sCallbackFilter=Default Or __TreeListExplorer__HandleCallback($iSystem, $hView, "sCallbackFilter", True, $sPath, $sFilename, $sExt) Then If UBound($arPaths, 2)>0 Then - Local $iIndex = _GUICtrlListView_AddItem($hView, $arPaths[$i][0], $iIconIndex) - For $j=1 To UBound($arPaths, 2)-1 - _GUICtrlListView_SetItemText($hView, $iIndex, $arPaths[$i][$j], $j) - Next + Switch $mView.iType + Case $__TreeListExplorer__Type_ListView + Local $iIconIndex = __TreeListExplorer__FileGetIconIndex($hView, $sFilePath) + Local $iIndex = _GUICtrlListView_AddItem($hView, $arPaths[$i][0], $iIconIndex) + For $j=1 To UBound($arPaths, 2)-1 + _GUICtrlListView_SetItemText($hView, $iIndex, $arPaths[$i][$j], $j) + Next + Case $__TreeListExplorer__Type_Combo + _GUICtrlComboBox_AddString($hView, $sFile) + Case $__TreeListExplorer__Type_ComboEx + Local $iIconIndex = __TreeListExplorer__FileGetIconIndex($hView, $sFilePath) + _GUICtrlComboBoxEx_AddString($hView, $sFile, $iIconIndex, $iIconIndex) + EndSwitch EndIf If $mView.sCallbackListViewItemCreated<>Default Then __TreeListExplorer__HandleCallback($iSystem, $hView, "sCallbackListViewItemCreated", $sFilePath, $sFile, $iIndex, $bDriveOrFolder) EndIf Next __TreeListExplorer__SetViewUpdating($hView, False, $__TreeListExplorer__Status_UpdateView) - __TreeListExplorer__HandleViewCallback($hView, "sCallbackLoading", $mSystem.sFolder, False) EndIf If $mSystem.sSelected<>"" Then Local $sSelected = $mSystem.sSelected - For $i=0 To _GUICtrlListView_GetItemCount($hView) - If _GUICtrlListView_GetItemText($hView, $i, $mView.iPathIndex)=$sSelected Then - _GUICtrlListView_EnsureVisible($hView, $i) - Local $arSel = _GUICtrlListView_GetSelectedIndices($hView, True) - For $j=1 To UBound($arSel)-1 Step 1 - _GUICtrlListView_SetItemSelected($hView, $arSel[$j], False) + Switch $mView.iType + Case $__TreeListExplorer__Type_ListView + For $i=0 To _GUICtrlListView_GetItemCount($hView)-1 + If _GUICtrlListView_GetItemText($hView, $i, $mView.iPathIndex)=$sSelected Then + _GUICtrlListView_EnsureVisible($hView, $i) + Local $arSel = _GUICtrlListView_GetSelectedIndices($hView, True) + For $j=1 To UBound($arSel)-1 Step 1 + _GUICtrlListView_SetItemSelected($hView, $arSel[$j], False) + Next + _GUICtrlListView_SetSelectionMark($hView, $i) + _GUICtrlListView_SetItemSelected($hView, $i) + ExitLoop + EndIf Next - _GUICtrlListView_SetSelectionMark($hView, $i) - _GUICtrlListView_SetItemSelected($hView, $i) - ExitLoop - EndIf - Next + Case $__TreeListExplorer__Type_Combo + Local $sText, $iCount = _GUICtrlComboBox_GetCount($hView) + If $iCount>0 Then + For $i=0 to $iCount-1 + _GUICtrlComboBox_GetLBText($hView, $i, $sText) + If $sText=$sSelected Then + _GUICtrlComboBox_SetEditText($hView, $sSelected) + _GUICtrlComboBox_SetCurSel($hView, $i) + ExitLoop + EndIf + Next + EndIf + Case $__TreeListExplorer__Type_ComboEx + Local $sText, $iCount = _GUICtrlComboBoxEx_GetCount($hView) + If $iCount>0 Then + For $i=0 To $iCount-1 + _GUICtrlComboBoxEx_GetItemText($hView, $i, $sText) + If $sText=$sSelected Then + _GUICtrlComboBoxEx_SetEditText($hView, $sSelected) + _GUICtrlComboBoxEx_SetCurSel($hView, $i) + ExitLoop + EndIf + Next + EndIf + EndSwitch EndIf + If $bUpdateFolder Then __TreeListExplorer__HandleViewCallback($hView, "sCallbackLoading", $mSystem.sFolder, False) Case $__TreeListExplorer__Type_Input If $bFolderChanged Then _GUICtrlEdit_SetText($hView, $mSystem.sFolder) EndSwitch @@ -1184,6 +1547,14 @@ Func __TreeListExplorer__UpdateView($hView, $bReload = False) $mView.bUpdating = False Case $__TreeListExplorer__Type_ListView _GUICtrlListView_EndUpdate($hView) + Case $__TreeListExplorer__Type_Combo, $__TreeListExplorer__Type_ComboEx + _GUICtrlComboBox_EndUpdate($hView) + Local $arPos = WinGetPos($mView.hComboList) + If $arPos[3]<>$mView.iComboListHeight Then + $arPos[3] = $mView.iComboListHeight + WinMove($mView.hComboList, "", $arPos[0], $arPos[1], $arPos[2], $arPos[3]) + EndIf + _WinAPI_RedrawWindow($hView) EndSwitch EndFunc @@ -1261,9 +1632,10 @@ EndFunc ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name ..........: __TreeListExplorer__FileGetIconIndex -; Description ...: Get the index of an icon in $__TreeListExplorer__Data.hIconList for a given extension and add missing icons. -; Syntax ........: __TreeListExplorer__FileGetIconIndex($sPath) +; Description ...: Get the index of an icon for a given path and add missing icons. +; Syntax ........: __TreeListExplorer__FileGetIconIndex($hView, $sPath) ; Parameters ....: $sPath - the absolute path. +; $hView - the handle to the Tree-/ListView. ; Return values .: The index ; Author ........: Kanashius ; Modified ......: @@ -1272,137 +1644,49 @@ EndFunc ; Link ..........: ; Example .......: No ; =============================================================================================================================== -Func __TreeListExplorer__FileGetIconIndex($sPath) - ; test for drive - Local $arRegExpDrive = StringRegExp($sPath, "^([^\/]+?:)\/*$", 1) - If UBound($arRegExpDrive)>0 Then return __TreeListExplorer__GetDriveIconId($arRegExpDrive[0]) - - ; test for folder - If __TreeListExplorer__PathIsFolder($sPath) Then Return 0 ; Default folder icon - - ; extract and handle cached extensions - Local $arExt = StringRegExp($sPath, "^.*[^\\](\.[^\\]*?)$", 1) - If @error Or UBound($arExt)<>1 Then Return 2 ; Default file icon - Local $sExt = StringLower($arExt[0]) - If MapExists($__TreeListExplorer__Data.mIcons, $sExt) Then Return $__TreeListExplorer__Data.mIcons[$sExt] - If MapExists($__TreeListExplorer__Data.mIcons, $sPath) Then Return $__TreeListExplorer__Data.mIcons[$sPath] +Func __TreeListExplorer__FileGetIconIndex($hView, $sPath) + Local $mView = $__TreeListExplorer__Data.mViews[$hView] + Local $iIconSize = $mView.iIconSize - Local $sIconPath = -1, $iIconIndex = 0, $bAddForExtension = False - ; handle .url (links) - If $sExt=".url" Then - $sIconPath = IniRead($sPath, "InternetShortcut", "IconFile", -1) - $iIconIndex = IniRead($sPath, "InternetShortcut", "IconIndex", -1) + ; handle drives + Local $arRegExpDrive = StringRegExp($sPath, "^([^\/]+?:)\/*$", 1) + If UBound($arRegExpDrive)>0 Then + Local $sType = __TreeListExplorer__GetDriveIconId($arRegExpDrive[0], True) + Return $__TreeListExplorer__Data.mIcons[$iIconSize]["mCache"][$sType] EndIf - ; handle .lnk (shortcuts) - If $sExt=".lnk" Then ; todo maybe add the link symbol (arrow) to the icon - + If __TreeListExplorer__PathIsFolder($sPath) Then + Return $__TreeListExplorer__Data.mIcons[$iIconSize]["mCache"][$__TreeListExplorer__Icon_Folder] EndIf - ; Handling for special extensions - Switch $sExt - Case ".exe" - $sIconPath = $sPath - Case ".url" - $sIconPath = IniRead($sPath, "InternetShortcut", "IconFile", -1) - $iIconIndex = IniRead($sPath, "InternetShortcut", "IconIndex", -1) - Case ".lnk" - Local $arShortcutData = FileGetShortcut($sPath) - If $arShortcutData[4]<>"" Then ; icon file provided - $sIconPath = $arShortcutData[4] - $iIconIndex = $arShortcutData[5] - Else ; otherwise get icon from the linked path - Return __TreeListExplorer__FileGetIconIndex($arShortcutData[0]) - EndIf - EndSwitch - If $sIconPath=-1 Then - Local $sRegData = RegRead("HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\" & $sExt, "ProgID") - If @error Then - $sRegData = RegRead("HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\" & $sExt & "\UserChoice", "ProgID") - If @error Then - $sRegData = RegRead("HKCR\" & $sExt, "") - EndIf - EndIf - If $sRegData<>"" Then $sRegData = RegRead("HKCR\" & $sRegData & "\DefaultIcon", "") - If $sRegData="" Then $sRegData = _WinAPI_AssocQueryString($sExt, $ASSOCSTR_DEFAULTICON) - If StringInStr($sRegData, "@")=1 Then ; Handle urls with @{...} - Local $sIconPath = _WinAPI_LoadIndirectString($sRegData) - If @error Then $sIconPath = -1 - Local $arRes = StringRegExp($sIconPath, "^(.*\\)(.*-)(\d+)(\.\S+)$", 1) - If Not (@error And UBound($arRes)<>4) Then ; check for files with a pixel resolution closer to $iIconSize - Local $iIconSize = $__TreeListExplorer__Data.iIconSize - Local $arFiles = _FileListToArray($arRes[0], $arRes[1]&"*"&$arRes[3]) - Local $arOptions[UBound($arFiles)-1][2], $iCount = 0 - For $i=1 To UBound($arFiles)-1 Step 1 ; get icon size for all files - Local $arFileParts = StringRegExp($arFiles[$i], "^.*-(\d+)\.\S+$", 1) - If Not @error Then - $arOptions[$iCount][0] = Int($arFileParts[0]) - $arOptions[$iCount][1] = $arFiles[$i] - $iCount+=1 - EndIf - Next - ReDim $arOptions[$iCount][2] - _ArraySort($arOptions) ; sort by size - For $i=0 To UBound($arOptions)-1 Step 1 ; take the best icon to be used (>= target icon size); Resize will be done later - If $iIconSize<=$arOptions[$i][0] Then - $sIconPath = $arRes[0]&$arOptions[$i][1] - ExitLoop - EndIf - Next - EndIf - ElseIf StringInStr($sRegData, ",") Then ; Handle , e.g.: ...shell32.dll, 0 - Local $arParts = StringRegExp($sRegData, '"?(.*?)"?,(-?\d+)', 1) - If UBound($arParts)=2 Then - $sIconPath = $arParts[0] - $iIconIndex = $arParts[1] - EndIf - ElseIf $sRegData<>"" Then ; Handle path without index - $sIconPath = $sRegData - EndIf - $bAddForExtension = True - EndIf - If $sIconPath<>-1 Then - Local $sIconExt = StringRight($sIconPath, 4), $sMapKey = $sPath - If $bAddForExtension Then $sMapKey = $sExt - If $sIconExt=".dll" Or $sIconExt=".exe" Or $sIconExt=".ico" Then ; icon to extract - Local $iIconSize = $__TreeListExplorer__Data.iIconSize - Local $hIcon = _WinAPI_ShellExtractIcon($sIconPath, $iIconIndex, $iIconSize, $iIconSize) - If $hIcon<>0 Then - Local $iIndex = _GUIImageList_ReplaceIcon($__TreeListExplorer__Data.hIconList, -1, $hIcon) - If $iIndex>=0 Then - $__TreeListExplorer__Data["mIcons"][$sMapKey] = $iIndex - Return $iIndex - EndIf - EndIf - Else ; normal image file - Local $hBitmap = _GDIPlus_BitmapCreateFromFile($sIconPath) - If @error Then Return 2 ; Default file icon - Local $iIconSize = $__TreeListExplorer__Data.iIconSize - Local $hBitmapResized = _GDIPlus_ImageResize($hBitmap, $iIconSize, $iIconSize) - Local $hImg = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmapResized) - Local $iIndex = _GUIImageList_Add($__TreeListExplorer__Data.hIconList, $hImg) - _GDIPlus_BitmapDispose($hBitmap) - _GDIPlus_BitmapDispose($hBitmapResized) - If $iIndex>=0 Then - $__TreeListExplorer__Data["mIcons"][$sMapKey] = $iIndex - Return $iIndex - EndIf - EndIf + ; extract and handle cached extensions + Local $arExt = StringRegExp($sPath, "^.*[^\\](\.[^\\]*?)$", 1), $sExt = Default, $bExtension = False, $bAddFileIcon = False + If Not (@error Or UBound($arExt)<>1) Then $sExt = StringLower($arExt[0]) + If $sExt<>Default And $sExt<>".exe" And $sExt<>".url" And $sExt<>".lnk" Then ; files with these extensions may have icons different from each other + If MapExists($__TreeListExplorer__Data.mIcons[$iIconSize]["mCache"], $sExt) Then Return $__TreeListExplorer__Data.mIcons[$iIconSize]["mCache"][$sExt] + $bExtension = True + ElseIf $sExt=".exe" Or $sExt=".url" Or $sExt=".lnk" Then + If MapExists($__TreeListExplorer__Data.mIcons[$iIconSize]["mCache"], $sPath) Then Return $__TreeListExplorer__Data.mIcons[$iIconSize]["mCache"][$sPath] Else - Local $tSHFILEINFO = DllStructCreate($tagSHFILEINFO) - Local $dwFlags = BitOR($SHGFI_USEFILEATTRIBUTES, $SHGFI_ICON, $SHGFI_ICONLOCATION) - _WinAPI_ShellGetFileInfo($sPath, $dwFlags, $FILE_ATTRIBUTE_NORMAL, $tSHFILEINFO) - If DllStructGetData($tSHFILEINFO, 2)<>0 Then ; ignore missing icons (SystemIcon=0 equals Default file icon) - If DllStructGetData($tSHFILEINFO, 1)>0 Then - Local $iIndex = _GUIImageList_ReplaceIcon($__TreeListExplorer__Data.hIconList, -1, DllStructGetData($tSHFILEINFO, 1)) - If $iIndex>=0 Then - $__TreeListExplorer__Data["mIcons"][$sExt] = $iIndex - Return $iIndex - EndIf - EndIf + Return $__TreeListExplorer__Data.mIcons[$iIconSize]["mCache"][$__TreeListExplorer__Icon_File] + EndIf + ; retrieve bitmap + Local $iIndex = -1 + Local $hBitmap = __TreeListExplorer_FileGetIconBitmap($sPath, $iIconSize, $sExt) + If Not @error And @extended = 1 Then ; handle default file icon + $iIndex = $__TreeListExplorer__Data.mIcons[$iIconSize]["mCache"][$__TreeListExplorer__Icon_File] + ElseIf Not @error Then + Local $hHBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap, 0x00000000) + $iIndex = _GUIImageList_Add($__TreeListExplorer__Data.mIcons[$iIconSize]["hList"], $hHBitmap) + EndIf + _GDIPlus_BitmapDispose($hBitmap) + If $iIndex>=0 Then + If $bExtension Then + $__TreeListExplorer__Data["mIcons"][$iIconSize]["mCache"][$sExt] = $iIndex Else - If DllStructGetData($tSHFILEINFO, 1)>0 Then _WinAPI_DestroyIcon(DllStructGetData($tSHFILEINFO, 1)) + $__TreeListExplorer__Data["mIcons"][$iIconSize]["mCache"][$sPath] = $iIndex EndIf + Return $iIndex EndIf - Return 2 ; Default file icon + Return $__TreeListExplorer__Data.mIcons[$iIconSize]["mCache"][$__TreeListExplorer__Icon_File] EndFunc ; #INTERNAL_USE_ONLY# =========================================================================================================== @@ -1456,7 +1740,7 @@ Func __TreeListExplorer__UpdateTreeItemContent($hView, $hItem, $bRecursive = Fal If Not $bRecursive Then __TreeListExplorer__SetViewUpdating($hView, True, $__TreeListExplorer__Status_LoadTree) ; get absolute path for item - Local $arPath = StringRegExp(StringReplace(_GUICtrlTreeView_GetTree($hView, $hItem), "|", "\"), "[^\\]*\\?(.*)$", 1) ; remove first element (root) + Local $arPath = StringRegExp(__TreeListExplorer__TreeViewGetTree($hView, $hItem), "[^\\]*\\?(.*)$", 1) ; remove first element (root) If @error Or UBound($arPath)<>1 Then Return False Local $sPath = $mSystem.sRoot & $arPath[0] ; Get Content data (drives/folders/files) @@ -1466,7 +1750,7 @@ Func __TreeListExplorer__UpdateTreeItemContent($hView, $hItem, $bRecursive = Fal ReDim $arEntries[UBound($arDrives)][3] For $i=0 To UBound($arDrives)-1 Step 1 $arEntries[$i][0] = $arDrives[$i][0] - $arEntries[$i][1] = $arDrives[$i][1] + $arEntries[$i][1] = $__TreeListExplorer__Data.mIcons[$__TreeListExplorer__Data.mViews[$hView].iIconSize].mCache[__TreeListExplorer__GetDriveIconId($arDrives[$i][0], True)] $arEntries[$i][2] = True If $bHasFilterCallback Then $arEntries[$i][2] = __TreeListExplorer__HandleCallback($iSystem, $hView, "sCallbackFilter", True, "", $arDrives[$i][0], "") @@ -1481,7 +1765,7 @@ Func __TreeListExplorer__UpdateTreeItemContent($hView, $hItem, $bRecursive = Fal ReDim $arEntries[$iSize][3] For $i=1 To UBound($arFolders)-1 Step 1 $arEntries[$i-1][0] = $arFolders[$i] - $arEntries[$i-1][1] = 0 + $arEntries[$i-1][1] = $__TreeListExplorer__Data.mIcons[$__TreeListExplorer__Data.mViews[$hView].iIconSize].mCache[$__TreeListExplorer__Icon_Folder] $arEntries[$i-1][2] = True If $bHasFilterCallback Then $arEntries[$i-1][2] = __TreeListExplorer__HandleCallback($iSystem, $hView, "sCallbackFilter", True, $sPath, $arFolders[$i], "") @@ -1490,7 +1774,7 @@ Func __TreeListExplorer__UpdateTreeItemContent($hView, $hItem, $bRecursive = Fal Local $iIndex = UBound($arFolders)-1-(UBound($arFolders)>0?1:0) For $i=1 To UBound($arFiles)-1 Step 1 $arEntries[$iIndex+$i][0] = $arFiles[$i] - $arEntries[$iIndex+$i][1] = __TreeListExplorer__FileGetIconIndex($sPath & "\" & $arFiles[$i]) + $arEntries[$iIndex+$i][1] = __TreeListExplorer__FileGetIconIndex($hView, $sPath & "\" & $arFiles[$i]) $arEntries[$iIndex+$i][2] = True If $bHasFilterCallback Then Local $sFilename = $arFiles[$i], $sExt = "" @@ -1565,6 +1849,29 @@ Func __TreeListExplorer__UpdateTreeItemContent($hView, $hItem, $bRecursive = Fal Return True EndFunc + +; #INTERNAL_USE_ONLY# =========================================================================================================== +; Name ..........: __TreeListExplorer__TreeViewGetTree +; Description ...: Get the tree of the element seperated by \ without influencing the users GUIDataSeparatorChar +; Syntax ........: __TreeListExplorer__TreeViewGetTree($hView, $hItem) +; Parameters ....: $hView - the treeview handle. +; $hItem - the item handle. +; Return values .: The \ seperated tree +; Author ........: Kanashius +; Modified ......: +; Remarks .......: +; Related .......: +; Link ..........: +; Example .......: No +; =============================================================================================================================== +Func __TreeListExplorer__TreeViewGetTree($hView, $hItem) + If Not IsHWnd($hView) Then $hView = GUICtrlGetHandle($hView) + Local $sSepBefore = Opt("GUIDataSeparatorChar", "\") + Local $sTree = _GUICtrlTreeView_GetTree($hView, $hItem) + Opt("GUIDataSeparatorChar", $sSepBefore) + Return $sTree +EndFunc + ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name ..........: __TreeListExplorer__TreeViewDeleteItem ; Description ...: _GUICtrlTreeView_Delete randomly does not work using x64 AutoIt and sometimes randomly deletes controls @@ -1668,19 +1975,7 @@ Func __TreeListExplorer__GetDrives() Local $arResult[UBound($arDrives)-1][2] For $i = 1 To UBound($arDrives)-1 $arResult[$i-1][0] = StringUpper($arDrives[$i]) - Switch DriveGetType($arDrives[$i]) - Case 'Fixed' - $arResult[$i-1][1] = 5 - Case 'CDROM' - $arResult[$i-1][1] = 6 - Case 'RAMDisk' - $arResult[$i-1][1] = 7 - Case 'Removable' - $arResult[$i-1][1] = 4 - If StringLeft($arDrives[$i], 2) = "A:" Or StringLeft($arDrives[$i], 2) = "B:" Then $arResult[$i-1][1] = 3 - Case Else - $arResult[$i-1][1] = 8 - EndSwitch + $arResult[$i-1][1] = __TreeListExplorer__GetDriveIconId($arDrives[$i]) Next Return $arResult EndFunc @@ -1688,10 +1983,11 @@ EndFunc ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name ..........: __TreeListExplorer__GetDriveIconId -; Description ...: Get the icon for a drive. -; Syntax ........: __TreeListExplorer__GetDriveIconId($sDrive) -; Parameters ....: -; Return values .: Id of the icon (or 0 if not matched) +; Description ...: Get the icon id or string for a drive. +; Syntax ........: __TreeListExplorer__GetDriveIconId($sDrive[, $bString = False]) +; Parameters ....: $sDrive - The drive path +; $bString - (optional) Default: False. If True the string for $__TreeListExplorer__Icon_... is provided. +; Return values .: Id/String of the icon (or 0 if not matched) ; Author ........: Kanashius ; Modified ......: ; Remarks .......: @@ -1699,21 +1995,21 @@ EndFunc ; Link ..........: ; Example .......: No ; =============================================================================================================================== -Func __TreeListExplorer__GetDriveIconId($sDrive) +Func __TreeListExplorer__GetDriveIconId($sDrive, $bString = False) Switch DriveGetType($sDrive) Case 'Fixed' - return 5 + return $bString?$__TreeListExplorer__Icon_Harddrive:8 Case 'CDROM' - return 6 + return $bString?$__TreeListExplorer__Icon_CDROM:11 Case 'RAMDisk' - return 7 + return $bString?$__TreeListExplorer__Icon_Networkdrive:12 Case 'Removable' - return 4 - If StringLeft($sDrive, 2) = "A:" Or StringLeft($sDrive, 2) = "B:" Then return 3 + return $bString?$__TreeListExplorer__Icon_ChangeableInput:7 + If StringLeft($sDrive, 2) = "A:" Or StringLeft($sDrive, 2) = "B:" Then return $bString?$__TreeListExplorer__Icon_Disc:5 Case Else - return 8 + return $bString?$__TreeListExplorer__Icon_Unknown:53 EndSwitch - return 0 + return $bString?$__TreeListExplorer__Icon_Folder:3 EndFunc ; #INTERNAL_USE_ONLY# =========================================================================================================== @@ -1765,7 +2061,7 @@ EndFunc ; Example .......: No ; =============================================================================================================================== Func __TreeListExplorer__TreeViewGetRelPath($iSystem, $hView, $hItem) - Local $sPath = StringReplace(_GUICtrlTreeView_GetTree($hView, $hItem), "|", "\") + Local $sPath = __TreeListExplorer__TreeViewGetTree($hView, $hItem) $arPath = StringRegExp($sPath, "[^\\]*\\?(.*)$", 1) ; remove first root element If UBound($arPath)>0 Then $sPath = $arPath[0] If $sPath<>"" And StringRight($sPath, 1)<>"\" And __TreeListExplorer__RelPathIsFolder($iSystem, $sPath) Then $sPath &= "\" @@ -1925,10 +2221,10 @@ Func __TreeListExplorer__KeyProc($nCode, $wParam, $lParam) Local $hView = ControlGetHandle($hGui, "", $sControl) Local $arHwnds = MapKeys($__TreeListExplorer__Data.mViews) For $i=0 To UBound($arHwnds)-1 Step 1 - If $arHwnds[$i]<>$hView Then ContinueLoop - Local $mView = $__TreeListExplorer__Data.mViews[$hView] + Local $mView = $__TreeListExplorer__Data.mViews[$arHwnds[$i]] + If $arHwnds[$i]<>$hView And (Not (MapExists($mView, "hComboEdit") And $mView.hComboEdit=$hView)) Then ContinueLoop Local $iSystem = $mView.iSystem - Switch $__TreeListExplorer__Data.mViews[$hView].iType + Switch $mView.iType Case $__TreeListExplorer__Type_Input If $vkCode=13 Then __TreeListExplorer_OpenPath(__TreeListExplorer__GetHandleFromSystemID($iSystem), _GUICtrlEdit_GetText($hView)) Case $__TreeListExplorer__Type_ListView @@ -1942,6 +2238,17 @@ Func __TreeListExplorer__KeyProc($nCode, $wParam, $lParam) Next EndIf EndSwitch + Case $__TreeListExplorer__Type_Combo, $__TreeListExplorer__Type_ComboEx + If $vkCode = 13 Then + Local $sPath = _GUICtrlEdit_GetText($mView.hComboEdit) + Local $hSystem = __TreeListExplorer__GetHandleFromSystemID($iSystem) + If $sPath="" Then + $sPath = __TreeListExplorer_GetRoot($hSystem) + ElseIf Not FileExists($sPath) Then + $sPath=__TreeListExplorer_GetRoot($hSystem)&__TreeListExplorer_GetPath($hSystem)&$sPath + EndIf + __TreeListExplorer_OpenPath($hSystem, $sPath) + EndIf EndSwitch Next EndIf @@ -2055,6 +2362,7 @@ Func __TreeListExplorer__WinProc($hWnd, $iMsg, $iwParam, $ilParam) If NOT $__TreeListExplorer__Data.bCTRL_DOWN Then ; do not open/select when CTRL+CLICK multiselecting Local $arPath = __TreeListExplorer__GetPathAndLast(__TreeListExplorer__GetCurrentPath($iSystem) & _GUICtrlListView_GetItemText($hView, $iIndex, $mView.iPathIndex)) Local $mOpenPathData[] + $mOpenPathData.iType = $__TreeListExplorer__Type_ListView $mOpenPathData.sFolder = $arPath[0] $mOpenPathData.sSelect = $arPath[1] $mOpenPathData.iSystem = $iSystem @@ -2087,10 +2395,10 @@ Func __TreeListExplorer__WinProc($hWnd, $iMsg, $iwParam, $ilParam) $__TreeListExplorer__Data["mViews"][$hView]["mSorting"]["iCol"] = $iCol If BitAND($iFormat, $HDF_SORTUP) Then ; ascending _GUICtrlHeader_SetItemFormat($hHeader, $iCol, BitOR(BitXOR($iFormat, $HDF_SORTUP), $HDF_SORTDOWN)) - $__TreeListExplorer__Data["mViews"][$hView]["mSorting"]["iDir"] = 0 + $__TreeListExplorer__Data["mViews"][$hView]["mSorting"]["iDir"] = 1 Else ; descending _GUICtrlHeader_SetItemFormat($hHeader, $iCol, BitOR(BitXOR($iFormat, $HDF_SORTDOWN), $HDF_SORTUP)) - $__TreeListExplorer__Data["mViews"][$hView]["mSorting"]["iDir"] = 1 + $__TreeListExplorer__Data["mViews"][$hView]["mSorting"]["iDir"] = 0 EndIf __TreeListExplorer__UpdateView($hView, True) EndIf @@ -2101,6 +2409,31 @@ Func __TreeListExplorer__WinProc($hWnd, $iMsg, $iwParam, $ilParam) ExitLoop Next EndIf + If $iMsg=$WM_COMMAND Then + Local $iCode = _WinAPI_HiWord($iwParam) + Local $hView = $ilParam + Local $arHwnds = MapKeys($__TreeListExplorer__Data.mViews) + For $i=0 To UBound($arHwnds)-1 Step 1 + If $arHwnds[$i]<>$hView Then ContinueLoop + Local $mView = $__TreeListExplorer__Data.mViews[$hView] + Local $iSystem = $mView.iSystem + Local $iType = $__TreeListExplorer__Data.mViews[$hView].iType + Switch $iType + Case $__TreeListExplorer__Type_Combo, $__TreeListExplorer__Type_ComboEx + Switch $iCode + Case $CBN_SELENDOK + Local $mOpenPathData[] + $mOpenPathData.iType = $iType + $mOpenPathData.sFolder = __TreeListExplorer__GetCurrentPath($iSystem) + $mOpenPathData.iSystem = $iSystem + $mOpenPathData.hView = $hView + $__TreeListExplorer__Data["mOpenPathViews"][$hView] = $mOpenPathData + __TreeListExplorer__SetViewUpdating($hView, True, $__TreeListExplorer__Status_WaitOpenPath) + AdlibRegister("__TreeListExplorer__RegisteredOpenPath", 10) + EndSwitch + EndSwitch + Next + EndIf If MapExists($__TreeListExplorer__Data.mGuis, $hWnd) Then Return _WinAPI_CallWindowProc($__TreeListExplorer__Data.mGuis[$hWnd].hPrevProc, $hWnd, $iMsg, $iwParam, $ilParam) EndFunc @@ -2124,15 +2457,31 @@ Func __TreeListExplorer__RegisteredOpenPath() For $i=0 to UBound($arViews)-1 Step 1 If __TreeListExplorer__IsViewUpdating($arViews[$i], $__TreeListExplorer__Status_WaitOpenPath) Then Local $mOpenPathData = $__TreeListExplorer__Data["mOpenPathViews"][$arViews[$i]] - Local $hView = $mOpenPathData.hView - Local $arSel[0] - If $mOpenPathData.bMarquee Then $arSel = _GUICtrlListView_GetSelectedIndices(HWnd($hView), True) - __TreeListExplorer__OpenPath($mOpenPathData.iSystem, $mOpenPathData.sFolder, $mOpenPathData.sSelect) - __TreeListExplorer__SetViewUpdating($hView, False, $__TreeListExplorer__Status_WaitOpenPath) - If $mOpenPathData.bWasClick Then __TreeListExplorer__HandleViewCallback($hView, "sCallbackClick", $mOpenPathData.iIndex) - For $j=1 To UBound($arSel)-1 - _GUICtrlListView_SetItemSelected($hView, $arSel[$j], True) - Next + Switch $mOpenPathData.iType + Case $__TreeListExplorer__Type_ListView + Local $hView = $mOpenPathData.hView + Local $arSel[0] + If $mOpenPathData.bMarquee Then $arSel = _GUICtrlListView_GetSelectedIndices(HWnd($hView), True) + __TreeListExplorer__OpenPath($mOpenPathData.iSystem, $mOpenPathData.sFolder, $mOpenPathData.sSelect) + __TreeListExplorer__SetViewUpdating($hView, False, $__TreeListExplorer__Status_WaitOpenPath) + If $mOpenPathData.bWasClick Then __TreeListExplorer__HandleViewCallback($hView, "sCallbackClick", $mOpenPathData.iIndex) + For $j=1 To UBound($arSel)-1 + _GUICtrlListView_SetItemSelected($hView, $arSel[$j], True) + Next + Case $__TreeListExplorer__Type_Combo, $__TreeListExplorer__Type_ComboEx + Local $hCombo = -1 + If $mOpenPathData.iType=$__TreeListExplorer__Type_Combo Then $hCombo = HWnd($mOpenPathData.hView) + If $mOpenPathData.iType=$__TreeListExplorer__Type_ComboEx Then $hCombo = _GUICtrlComboBoxEx_GetComboControl($mOpenPathData.hView) + If $hCombo<>-1 Then + Local $iIndex = _GUICtrlComboBox_GetCurSel($hCombo) + If $iIndex>=0 Then + Local $sSelText + _GUICtrlComboBox_GetLBText($hCombo, $iIndex, $sSelText) + Local $arPath = __TreeListExplorer__GetPathAndLast(__TreeListExplorer__GetCurrentPath($mOpenPathData.iSystem) & $sSelText) + __TreeListExplorer__OpenPath($mOpenPathData.iSystem, $arPath[0], $arPath[1]) + EndIf + EndIf + EndSwitch EndIf MapRemove($__TreeListExplorer__Data.mOpenPathViews, $arViews[$i]) Next @@ -2366,4 +2715,4 @@ EndFunc Func __TreeListExplorer__ConsoleWriteCallbackError($sFunc, $sCallbackName, $iLineNumber, $sLineFunc) ConsoleWrite('Error calling callback function "'&$sFunc&'" provided as $'&$sCallbackName&' to "'&$sLineFunc&'" in Line: '&$iLineNumber& _ ". The function probably has the wrong number of parameters."&@crlf) -EndFunc +EndFunc \ No newline at end of file diff --git a/src/main.au3 b/src/main.au3 index 88db1a4..4b73b85 100644 --- a/src/main.au3 +++ b/src/main.au3 @@ -14,6 +14,8 @@ #include "../lib/GUIFrame_WBD_Mod.au3" #include "../lib/History.au3" #include "../lib/TreeListExplorer.au3" +#include "../lib/ProjectConstants.au3" +#include "../lib/IUnknown.au3" ; CREDITS: ; Kanashius TreeListExplorer UDF @@ -24,9 +26,11 @@ ; argumentum Dark Mode functions ; NoNameCode Dark Mode functions ; Melba23 GUIFrame UDF -; ahmet Non-client painting of white line in dark mode +; ahmet Non-client painting of white menubar line in dark mode ; UEZ Lots and lots and lots ; DonChunior Code review, bug fixes and refactoring +; MattyD Drag and drop code +; jugador ListView multiple item drag and drop Global $sVersion = "0.4.0 - 2026-01-22" @@ -44,14 +48,14 @@ Global $hTLESystem, $iFrame_A, $hSeparatorFrame, $aWinSize2, $idInputPath, $g_hI Global $g_hGUI, $g_hChild, $g_hHeader, $g_hListview, $idListview, $iHeaderHeight, $hParentFrame, $g_iIconWidth, $g_hTreeView Global $g_hSizebox, $g_hOldProc, $g_iHeight, $g_hDots Global $idPropertiesItem, $idPropertiesLV, $sCurrentPath -Global $hListImgList, $iListDragIndex, $aDragSource +Global $hListImgList, $iListDragIndex, $aDragSource, $sTargetCtrl, $hTreeItemOrig, $hIcon Global $sBack, $sForward, $sUpLevel, $sRefresh Global $bDragTreeList = False, $sDragSrc, $sTreeDragItem, $sListDragItems, $bDragToolActive = False Global $bPathInputChanged = False, $bLoadStatus = False, $bCursorOverride = False Global $idExitItem, $idAboutItem Global $hCursor, $hProc -Global $sSelectedItems, $g_aText -Global $idSeparator, $idThemeItem, $hToolTip1, $hToolTip2, $hToolTip3, $bTooltipActive +Global $sSelectedItems, $g_aText, $gText +Global $idSeparator, $idThemeItem, $hToolTip1, $hToolTip2, $bTooltipActive Global $isDarkMode = _WinAPI_ShouldAppsUseDarkMode() Global $hFolderHistory = __History_Create("_doUnReDo", 100, "_historyChange"), $bFolderHistoryChanging = False Global $hSolidBrush = _WinAPI_CreateBrushIndirect($BS_SOLID, 0x000000) @@ -60,7 +64,11 @@ Global $aPosTip, $iOldaPos0, $iOldaPos1 ; force light mode ;$isDarkMode = False -Global $gText +Global $__g_aObjects[1][20] +Global $__g_hMthd_QueryInterface, $__g_hMthd_AddRef, $__g_hMthd_Release +Global $__g_hMthd_QueryInterfaceThunk, $__g_hMthd_AddRefThunk, $__g_hMthd_ReleaseThunk +Global $__g_hMthd_QueryContinueDrag, $__g_hMthd_GiveFeedback +Global $__g_hMthd_DragEnterTarget, $__g_hMthd_DragLeaveTarget Global $hKernel32 = DllOpen('kernel32.dll') Global $hGdi32 = DllOpen('gdi32.dll') @@ -131,15 +139,14 @@ Func _FilesAu3() EndIf ; Startup of the TreeListExplorer - __TreeListExplorer_StartUp($__TreeListExplorer_Lang_EN, $iTreeListIconSize) + __TreeListExplorer_StartUp($__TreeListExplorer_Lang_EN) ; Create GUI and register events $g_hGUI = GUICreate("Files Au3", @DesktopWidth - 600, @DesktopHeight - 400, -1, -1, $WS_OVERLAPPEDWINDOW) GUISetOnEvent($GUI_EVENT_CLOSE, "_EventsGUI") GUISetOnEvent($GUI_EVENT_MAXIMIZE, "_EventsGUI") GUISetOnEvent($GUI_EVENT_RESIZED, "_EventsGUI") - GUISetOnEvent($GUI_EVENT_PRIMARYUP, "_EventsGUI") - GUISetOnEvent($GUI_EVENT_MOUSEMOVE, "_EventsGUI") + GUISetOnEvent($GUI_EVENT_DROPPED, "_EventsGUI") ; used to determine separator position $FrameWidth1 = (@DesktopWidth - 600) / 3 @@ -156,8 +163,6 @@ Func _FilesAu3() _GUIToolTip_SetMaxTipWidth($hToolTip1, 400) $hToolTip2 = _GUIToolTip_Create(0) _GUIToolTip_SetMaxTipWidth($hToolTip2, 400) - $hToolTip3 = _GUIToolTip_Create(0) - _GUIToolTip_SetMaxTipWidth($hToolTip3, 400) GUISetFont(10, $FW_NORMAL, $GUI_FONTNORMAL, $sButtonFont) @@ -254,17 +259,13 @@ Func _FilesAu3() GUICtrlSetResizing(-1, $GUI_DOCKLEFT + $GUI_DOCKRIGHT + $GUI_DOCKTOP + $GUI_DOCKBOTTOM) $g_hTreeView = GUICtrlGetHandle($idTreeView) - _GUIToolTip_AddTool($hToolTip3, $g_hGUI, " ", $g_hGUI) - - _GUIToolTip_SetTitle($hToolTip3, 'File Operation', $TTI_INFO_LARGE) - _GUIToolTip_Deactivate($hToolTip3) - ; Create TLE system $hTLESystem = __TreeListExplorer_CreateSystem($g_hGUI, "", "_folderCallback") ; Add Views to TLE system __TreeListExplorer_AddView($hTLESystem, $idInputPath) __TreeListExplorer_AddView($hTLESystem, $idTreeView) + __TreeListExplorer_SetViewIconSize($idTreeView, $iTreeListIconSize) ; Create listview frame _GUIFrame_Switch($iFrame_A, 2) @@ -284,7 +285,7 @@ Func _FilesAu3() _GUICtrlHeader_SetItemAlign($g_hHeader, 1, 1) ; Set sort arrow - _GUICtrlHeader_SetItemFormat($g_hHeader, 0, $HDF_SORTUP) + ;_GUICtrlHeader_SetItemFormat($g_hHeader, 0, $HDF_SORTUP) ; get header height $iHeaderHeight = _WinAPI_GetWindowHeight($g_hHeader) @@ -309,6 +310,7 @@ Func _FilesAu3() ; add listview and callbacks to TLE system __TreeListExplorer_AddView($hTLESystem, $idListview, True, True, True, False, False) + __TreeListExplorer_SetViewIconSize($idListview, $iTreeListIconSize) __TreeListExplorer_SetCallback($idListview, $__TreeListExplorer_Callback_Loading, "_loadingCallback") __TreeListExplorer_SetCallback($idListview, $__TreeListExplorer_Callback_DoubleClick, "_doubleClickCallback") __TreeListExplorer_SetCallback($idListview, $__TreeListExplorer_Callback_ListViewPaths, "_handleListViewData") @@ -317,6 +319,7 @@ Func _FilesAu3() ; Set resizing flag for all created frames _GUIFrame_ResizeSet(0) + GUIRegisterMsg($WM_DROPFILES, "WM_DROPFILES") GUIRegisterMsg($WM_COMMAND, "WM_COMMAND2") GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY2") @@ -400,6 +403,14 @@ Func _FilesAu3() Local $i_ExStyle_Old = _WinAPI_GetWindowLong_mod(_GUIFrame_GetHandle($iFrame_A, 1), $GWL_EXSTYLE) _WinAPI_SetWindowLong_mod(_GUIFrame_GetHandle($iFrame_A, 1), $GWL_EXSTYLE, BitOR($i_ExStyle_Old, $WS_EX_COMPOSITED)) + ; add drop files support to treeview frame and listview frame + $i_ExStyle_Old = _WinAPI_GetWindowLong_mod(_GUIFrame_GetHandle($iFrame_A, 1), $GWL_EXSTYLE) + _WinAPI_SetWindowLong_mod(_GUIFrame_GetHandle($iFrame_A, 1), $GWL_EXSTYLE, BitOR($i_ExStyle_Old, $WS_EX_ACCEPTFILES)) + + ; add drop files support to treeview frame and listview frame + $i_ExStyle_Old = _WinAPI_GetWindowLong_mod(_GUIFrame_GetHandle($iFrame_A, 2), $GWL_EXSTYLE) + _WinAPI_SetWindowLong_mod(_GUIFrame_GetHandle($iFrame_A, 2), $GWL_EXSTYLE, BitOR($i_ExStyle_Old, $WS_EX_ACCEPTFILES)) + While True If $bTooltipActive Then ; check if cursor is still over listview @@ -415,7 +426,6 @@ Func _FilesAu3() EndIf Sleep(200) - WEnd EndFunc ;==>_FilesAu3 @@ -781,10 +791,17 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) _selectionChangedLV() Case $LVN_BEGINDRAG Local $tNMListView = DllStructCreate($tagNMLISTVIEW, $lParam) + Local $sItemText = _GUICtrlListView_GetItemText($tNMHDR.hwndFrom, $tNMLISTVIEW.item) + $sItemText = __TreeListExplorer_GetPath($hTLESystem) & $sItemText $bDragTreeList = True $sDragSrc = "List" + $hTreeItemOrig = _GUICtrlTreeView_GetSelection($g_hTreeView) + ; fire off adlib to get multiple selection drag details AdlibRegister("_ListGetSelections", 10) + + ; there is not supposed to be a Return value on LVN_BEGINDRAG + ; however it fixes an issue with built-in drag-drop mechanism (now that we use DoDragDrop) Return 0 Case $LVN_HOTTRACK ; Sent by a list-view control When the user moves the mouse over an item Local $tInfo2 = DllStructCreate($tagNMLISTVIEW, $lParam) @@ -845,10 +862,37 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) $aDragSource = "" Local $tTree = DllStructCreate($tagNMTREEVIEW, $lParam) Local $hDragItem = DllStructGetData($tTree, "NewhItem") + ;$sTreeDragItem = TreeItemToPath($g_hTreeView, $hDragItem) $aDragSource = TreeItemToPath($g_hTreeView, $hDragItem, True) $bDragTreeList = True $sDragSrc = "Tree" + $hTreeItemOrig = _GUICtrlTreeView_GetSelection($g_hTreeView) + + $sItemText = TreeItemToPath($g_hTreeView, $hDragItem) + + Local $pDataObj, $pDropSource + + ;Get an IDataObject representing the file to copy + $pDataObj = GetDataObjectOfFile($g_hGUI, $sItemText) + If Not @error Then + + ;Create an IDropSource to handle our end of the drag/drop operation. + $pDropSource = CreateDropSource() + + If Not @error Then + ;We allow DROPEFFECT_COPY and DROPEFFECT_LINK. We don't want to DROPEFFECT_MOVE the file!! + ;DoDragDrop($pDataObj, $pDropSource, BitOR($DROPEFFECT_COPY, $DROPEFFECT_LINK)) + _SHDoDragDrop($pDataObj, $pDropSource, BitOR($DROPEFFECT_COPY, $DROPEFFECT_LINK)) + + ;Operation done, destroy our drop source. (Can't just IUnknown_Release() this one!) + DestroyDropSource($pDropSource) + EndIf + + ;Relase the data object so the system can destroy it (prevent memory leaks) + _Release($pDataObj) + EndIf + EndSwitch EndSwitch @@ -1046,7 +1090,6 @@ Func _CleanExit() _GUICtrlHeader_Destroy($g_hHeader) _GUIToolTip_Destroy($hToolTip1) _GUIToolTip_Destroy($hToolTip2) - _GUIToolTip_Destroy($hToolTip3) GUIDelete($g_hGUI) _ClearDarkSizebox() @@ -1573,14 +1616,14 @@ Func ApplyDPI() EndFunc ;==>ApplyDPI Func _WinAPI_SetThreadDpiAwarenessContext($DPI_AWARENESS_CONTEXT_value) ; UEZ - Local $aResult = DllCall("user32.dll", "uint", "SetThreadDpiAwarenessContext", @AutoItX64 ? "int64" : "int", $DPI_AWARENESS_CONTEXT_value) ; requires Win10 v1703+ / Windows Server 2016+ + Local $aResult = DllCall('user32.dll', "uint", "SetThreadDpiAwarenessContext", @AutoItX64 ? "int64" : "int", $DPI_AWARENESS_CONTEXT_value) ; requires Win10 v1703+ / Windows Server 2016+ If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0) If Not $aResult[0] Then Return SetError(2, @extended, 0) Return $aResult[0] EndFunc ;==>_WinAPI_SetThreadDpiAwarenessContext Func _WinAPI_GetDpiForSystem() ; UEZ - Local $aResult = DllCall("user32.dll", "uint", "GetDpiForSystem") ; requires Win10 v1607+ / no server support + Local $aResult = DllCall('user32.dll', "uint", "GetDpiForSystem") ; requires Win10 v1607+ / no server support If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0) If Not $aResult[0] Then Return SetError(2, @extended, 0) Return $aResult[0] @@ -1798,146 +1841,8 @@ Func _EventsGUI() _resizeLVCols2() Case $GUI_EVENT_RESIZED _resizeLVCols2() - Case $GUI_EVENT_MOUSEMOVE - If Not $bDragTreeList Then ContinueCase - If Not $bDragToolActive Then - ; check drag source to determine where to fetch icon from - If $sDragSrc = "Tree" Then - $hIcon = _GUICtrlTreeView_GetImageListIconHandle($idTreeView, 0) ; always folder icon - _GUIToolTip_SetTitle($hToolTip3, 'File Operation', $hIcon) - ElseIf $sDragSrc = "List" Then - $iImgIndex = _GUICtrlListView_GetItemImage($g_hListview, $iListDragIndex) - $hIcon = _GUIImageList_GetIcon($hListImgList, $iImgIndex) - _GUIToolTip_SetTitle($hToolTip3, 'File Operation', $hIcon) - EndIf - ; temporarily delay regular listview tooltips - _GUICtrlListView_SetHoverTime($idListview, 50000) - _GUIToolTip_Activate($hToolTip3) - _GUIToolTip_TrackActivate($hToolTip3, True, $g_hGUI, $g_hGUI) - $bDragToolActive = True - EndIf - Local $aPosTool3 = MouseGetPos() - _GUIToolTip_TrackPosition($hToolTip3, $aPosTool3[0], $aPosTool3[1]) - - If Not $bTreeOrigStored Then - ; store handle for the original treeview selection to restore selection later - $hTreeItemOrig = _GUICtrlTreeView_GetSelection($g_hTreeView) - $bTreeOrigStored = True - EndIf - Local $aTreeList = GUIGetCursorInfo($g_hGUI) - Local $sTreeListItemText - Local Static $sTreeListItemTextPrev - Select - Case $aTreeList[4] = $idTreeView - Local $hItemHover = TreeItemFromPoint($g_hTreeView) - If $hItemHover <> 0 Then - ; bring focus to treeview to properly show DROPHILITE - _WinAPI_SetFocus($g_hTreeView) - _GUICtrlTreeView_SelectItem($g_hTreeView, $hItemHover) - _GUICtrlTreeView_SetState($g_hTreeView, $hTreeItemOrig, $TVIS_SELECTED, True) - Local $iTreeItem = TreeItemFromPoint($g_hTreeView) - $sTreeListItemText = _GUICtrlTreeView_GetText($g_hTreeView, $iTreeItem) - If $sTreeListItemText <> $sTreeListItemTextPrev Then - _GUIToolTip_UpdateTipText($hToolTip3, $g_hGUI, $g_hGUI, "Move to " & $sTreeListItemText) - EndIf - $sTreeListItemTextPrev = $sTreeListItemText - Else - ; restore original treeview selection if cursor leaves treeview - _GUICtrlTreeView_SelectItem($g_hTreeView, $hTreeItemOrig) - $bTreeOrigStored = False - EndIf - - Case $aTreeList[4] = $idListview - Local $iListHover = ListItemFromPoint($g_hListview) - If $iListHover >= 0 Then - ; bring focus to listview to show hot item (needed for listview to listview drag) - _WinAPI_SetFocus($g_hListview) - _GUICtrlListView_SetHotItem($idListview, $iListHover) - Local $iListDrop = ListItemFromPoint($g_hListview) - Local $sListDropPath = __TreeListExplorer_GetPath($hTLESystem) & _GUICtrlListView_GetItemText($idListview, $iListDrop, 0) - If __TreeListExplorer__PathIsFolder($sListDropPath) Then - $sTreeListItemText = _GUICtrlListView_GetItemText($idListview, $iListDrop, 0) - If $sTreeListItemTextPrev <> $sTreeListItemText Then - _GUIToolTip_UpdateTipText($hToolTip3, $g_hGUI, $g_hGUI, "Move to " & $sTreeListItemText) - EndIf - $sTreeListItemTextPrev = $sTreeListItemText - Else - $sTreeListItemText = __TreeListExplorer_GetPath($hTLESystem) - $sTreeListItemText = _StringBetween($sTreeListItemText, "\", "\")[UBound(_StringBetween($sTreeListItemText, "\", "\")) - 1] - If $sTreeListItemTextPrev <> $sTreeListItemText Then - _GUIToolTip_UpdateTipText($hToolTip3, $g_hGUI, $g_hGUI, "Move to " & $sTreeListItemText) - EndIf - $sTreeListItemTextPrev = $sTreeListItemText - EndIf - ElseIf $iListHover = -1 Then - $sTreeListItemText = __TreeListExplorer_GetPath($hTLESystem) - $sTreeListItemText = _StringBetween($sTreeListItemText, "\", "\")[UBound(_StringBetween($sTreeListItemText, "\", "\")) - 1] - If $sTreeListItemTextPrev <> $sTreeListItemText Then - _GUIToolTip_UpdateTipText($hToolTip3, $g_hGUI, $g_hGUI, "Move to " & $sTreeListItemText) - EndIf - $sTreeListItemTextPrev = $sTreeListItemText - EndIf - - Case Else - If $sTreeListItemTextPrev <> $sTreeListItemText Then - $sTreeListItemText = " " - _GUIToolTip_UpdateTipText($hToolTip3, $g_hGUI, $g_hGUI, $sTreeListItemText) - EndIf - $sTreeListItemTextPrev = $sTreeListItemText - EndSelect - - Case $GUI_EVENT_PRIMARYUP - Local $iTreeItem, $sTreeDropItem, $sDragDest - If $bDragTreeList Then - If $bDragToolActive Then - _GUIToolTip_TrackActivate($hToolTip3, False, $g_hGUI, $g_hGUI) - _GUIToolTip_Deactivate($hToolTip3) - ; restore original listview hover time - _GUICtrlListView_SetHoverTime($idListview, 500) - _GUIImageList_DestroyIcon($hIcon) - _GUIToolTip_SetTitle($hToolTip3, 'File Operation', $TTI_NONE) - $bDragToolActive = False - EndIf - $bDragTreeList = False - $bTreeOrigStored = False - ; restore proper state back to original treeview selection - _GUICtrlTreeView_SelectItem($g_hTreeView, $hTreeItemOrig) - Local $aTreeList = GUIGetCursorInfo($g_hGUI) - If $aTreeList[4] = $idTreeView Then - $iTreeItem = TreeItemFromPoint($g_hTreeView) - $sTreeDropItem = TreeItemToPath($g_hTreeView, $iTreeItem) - $sDragDest = $sTreeDropItem - - ; example showing which source files should go to which destination - _MsgExample($aDragSource, $sDragDest) - - ElseIf $aTreeList[4] = $idListview Then - Select - Case $sDragSrc = "Tree" ; drag and drop from treeview to listview - Local $sListDropItem = __TreeListExplorer_GetPath($hTLESystem) & _GUICtrlListView_GetItemText($idListview, _GUICtrlListView_GetHotItem($idListview), 0) - If __TreeListExplorer__PathIsFolder($sListDropItem) Then - $sDragDest = $sListDropItem - Else - $sDragDest = __TreeListExplorer_GetPath($hTLESystem) - EndIf - - Case $sDragSrc = "List" ; drag and drop from listview to listview - Local $iListDrop = ListItemFromPoint($g_hListview) - Local $sListDropItem = __TreeListExplorer_GetPath($hTLESystem) & _GUICtrlListView_GetItemText($idListview, $iListDrop, 0) - If __TreeListExplorer__PathIsFolder($sListDropItem) Then - $sDragDest = $sListDropItem - Else - $sDragDest = __TreeListExplorer_GetPath($hTLESystem) - EndIf - EndSelect - - ; example showing which source files should go to which destination - _MsgExample($aDragSource, $sDragDest) - - ElseIf $aTreeList[4] <> $idListview And $aTreeList[4] <> $idTreeView Then - MsgBox($MB_ICONERROR, "Example", "Cursor has been released in an area not yet supported by drag and drop.") - EndIf - EndIf + Case $GUI_EVENT_DROPPED + ConsoleWrite("drop detected" & @CRLF) EndSwitch EndFunc ;==>_EventsGUI @@ -2029,7 +1934,7 @@ EndFunc ;==>_PathInputChanged Func _drawUAHMenuNCBottomLine($hWnd) ; ahmet $rcClient = _WinAPI_GetClientRect($hWnd) - Local $aCall = DllCall('user32.dll', "int", "MapWindowPoints", _ + Local $aCall = DllCall($hUser32, "int", "MapWindowPoints", _ "hwnd", $hWnd, _ ; hWndFrom "hwnd", 0, _ ; hWndTo "ptr", DllStructGetPtr($rcClient), _ @@ -2080,22 +1985,565 @@ Func _ListGetSelections() $sListDragItems &= $aDragSource[$i] & " + " Next $sListDragItems = StringTrimRight($sListDragItems, 3) + + _ArrayDelete($aDragSource, 0) + + Local $pDataObj, $pDropSource + $pDataObj = GetDataObjectOfFile_B($aDragSource) + ;Create an IDropSource to handle our end of the drag/drop operation. + $pDropSource = CreateDropSource() + + _SHDoDragDrop($pDataObj, $pDropSource, BitOR($DROPEFFECT_COPY, $DROPEFFECT_LINK)) + + DestroyDropSource($pDropSource) + _Release($pDataObj) + + #cs ; old method + ; drag drop + Local $pDataObj, $pDropSource + + ;Get an IDataObject representing the file to copy + $pDataObj = GetDataObjectOfFile($g_hGUI, $aDragSource[1]) + If Not @error Then + + ;Create an IDropSource to handle our end of the drag/drop operation. + $pDropSource = CreateDropSource() + If Not @error Then + ;We allow DROPEFFECT_COPY and DROPEFFECT_LINK. We don't want to DROPEFFECT_MOVE the file!! + ;DoDragDrop($pDataObj, $pDropSource, BitOR($DROPEFFECT_COPY, $DROPEFFECT_LINK)) + _SHDoDragDrop_old($g_hGUI, $pDataObj, $pDropSource, BitOR($DROPEFFECT_COPY,$DROPEFFECT_LINK)) + + ;Operation done, destroy our drop source. (Can't just IUnknown_Release() this one!) + DestroyDropSource($pDropSource) + EndIf + + ;Relase the data object so the system can destroy it (prevent memory leaks) + _Release($pDataObj) + EndIf + #ce + AdlibUnRegister("_ListGetSelections") EndFunc ;==>_ListGetSelections Func TreeItemToPath($hTree, $hItem, $bArray = False) Local $sPath = StringReplace(_GUICtrlTreeView_GetTree($hTree, $hItem), "|", "\") $sPath = StringTrimLeft($sPath, StringInStr($sPath, "\")) ; remove this pc at the beginning + If StringInStr(FileGetAttrib($sPath), "D") Then $sPath &= "\" ; let folders end with \ + If $bArray Then + Local $aPath = _ArrayFromString($sPath) + _ArrayInsert($aPath, 0, 1) + Return $aPath + EndIf + Return $sPath +EndFunc ;==>TreeItemToPath - If StringInStr(FileGetAttrib($sPath), "D") Then - $sPath &= "\" ; let folders end with \ +Func WM_DROPFILES($hWnd, $iMsg, $wParam, $lParam) + #forceref $hWnd, $iMsg, $wParam, $lParam + ;First call with 0xFFFFFFFF, get number of files dropped + Local $aCall = DllCall($hShell32, "uint", "DragQueryFileW", "hwnd", $wParam, "uint", 0xFFFFFFFF, "ptr", 0, "int", 0) + If @error Then Return + Local $iFileCount = $aCall[0] + + Local $iBuffSize, $tBuffer, $sAttrib + For $i = 0 To $iFileCount - 1 + ;Second call call with 0 for buff size, retrieves required buff size for filename. + $aCall = DllCall($hShell32, "uint", "DragQueryFileW", "hwnd", $wParam, "uint", $i, "ptr", 0, "int", 0) + If @error Then ContinueLoop + $iBuffSize = $aCall[0] + 1 + + ;Create name buffer and fill. + $tBuffer = DllStructCreate(StringFormat("wchar fileName[%d]", $iBuffSize)) + $aCall = DllCall($hShell32, "uint", "DragQueryFileW", "hwnd", $wParam, "uint", $i, "struct*", $tBuffer, "int", $iBuffSize) + If @error Then ContinueLoop + + ConsoleWrite("file name: " & $tBuffer.fileName & @CRLF) + ConsoleWrite("handle: " & $hWnd & @CRLF) + If $hWnd = _GUIFrame_GetHandle($iFrame_A, 1) Then ConsoleWrite("dropped on treeview" & @CRLF) + If $hWnd = _GUIFrame_GetHandle($iFrame_A, 2) Then ConsoleWrite("dropped on listview" & @CRLF) + #cs + ;Only add file if is not hidden, not a dir, not already in the list! + If _GUICtrlListView_FindText($hListView, $tBuffer.fileName) = -1 Then + $sAttrib = FileGetAttrib($tBuffer.fileName) + If StringRegExp($sAttrib, "D|H") Then ContinueLoop + _GUICtrlListView_AddItem($hListView, $tBuffer.fileName) + EndIf + #ce + Next + + ; restore proper state back to original treeview selection + _GUICtrlTreeView_SelectItem($g_hTreeView, $hTreeItemOrig) + + Return +EndFunc + +;Convert @error codes from DllCall into win32 codes. +Func TranslateDllError($iError = @error) + Switch $iError + Case 0 + $iError = $ERROR_SUCCESS + Case 1 + $iError = $ERROR_DLL_INIT_FAILED + Case Else + $iError = $ERROR_INVALID_PARAMETER + EndSwitch +EndFunc + +Func CoTaskMemFree($pMemBlock) + DllCall("Ole32.dll", "none", "CoTaskMemFree", "ptr", $pMemBlock) +EndFunc ;==>CoTaskMemFree + +Func DoDragDrop($pDataObj, $pDropSource, $iOKEffects) + ;We must pass a IID_IDropSource ptr. + $pDropSource = _QueryInterface($pDropSource, $sIID_IDropSource) + _Release($pDropSource) + + Local $aCall = DllCall("ole32.dll", "long", "DoDragDrop", "ptr", $pDataObj, "ptr", $pDropSource, "dword", $iOKEffects, "ptr*", 0) + If @error Then Return SetError(@error, @extended, $aCall) + Return SetError($aCall[0], 0, $aCall[4]) +EndFunc ;==>DoDragDrop + +; DoDragDrop($pDataObj, $pDropSource, BitOR($DROPEFFECT_COPY, $DROPEFFECT_LINK)) +; _SHDoDragDrop($hGUI, $pDataObj, $pDropSource, BitOR($DROPEFFECT_COPY,$DROPEFFECT_LINK)) +Func _SHDoDragDrop_old($hWnd, ByRef $pDataObj, ByRef $pDropSource, $dwDropEffects) + DllCall($hShell32,"lresult","SHDoDragDrop", "hwnd", Null, "ptr", $pDataObj,"ptr", Null, "dword", BitOR($DROPEFFECT_COPY,$DROPEFFECT_LINK), "dword*", 0) +EndFunc + +Func _SHDoDragDrop($pDataObj, $pDropSource, $iOKEffects) + ;We must pass a IID_IDropSource ptr. + $pDropSource = _QueryInterface($pDropSource, $sIID_IDropSource) + _Release($pDropSource) + + ;Local $aCall = DllCall($hShell32, "long", "SHDoDragDrop", "hwnd", $g_hGUI, "ptr", $pDataObj, "ptr", $pDropSource, "dword", $iOKEffects, "ptr*", 0) + Local $aCall = DllCall($hShell32, "long", "SHDoDragDrop", "hwnd", Null, "ptr", $pDataObj, "ptr", Null, "dword", $iOKEffects, "ptr*", 0) + For $i = 0 To UBound($aCall) - 1 + ConsoleWrite("$aCall[" & $i & "] : " & Hex($aCall[$i], 1) & @CRLF) + Next + + If Hex($aCall[5], 1) = $DROPEFFECT_COPY Then ConsoleWrite("copy yay" & @CRLF) + + If @error Then Return SetError(@error, @extended, $aCall) + Return SetError($aCall[0], 0, $aCall[4]) +EndFunc ;==>_SHDoDragDrop + +Func GetDataObjectOfFile_B(ByRef $sPath) + Local $iCount = UBound($sPath) + If $iCount = 0 Then Return 0 + + Local $sParentPath = StringLeft($sPath[0], StringInStr($sPath[0], "\", 0, -1) - 1) + Local $pParentPidl = _WinAPI_ShellILCreateFromPath($sParentPath) + + Local $tPidls = DllStructCreate("ptr[" & $iCount & "]") + + Local $pFullPidl, $pRelativePidl, $last_SHITEMID + For $i = 0 To $iCount - 1 + $pFullPidl = _WinAPI_ShellILCreateFromPath($sPath[$i]) + $last_SHITEMID = DllCall($hShell32, "ptr", "ILFindLastID", "ptr", $pFullPidl)[0] + $pRelativePidl = DllCall($hShell32, "ptr", "ILClone", "ptr", $last_SHITEMID)[0] + DllStructSetData($tPidls, 1, $pRelativePidl, $i + 1) + DllCall($hShell32, "none", "ILFree", "ptr", $pFullPidl) + Next + + Local $tIID_IDataObject = _WinAPI_GUIDFromString($sIID_IDataObject) + Local $pIDataObject = __SHCreateDataObject($tIID_IDataObject, $pParentPidl, $iCount, DllStructGetPtr($tPidls), 0) + + DllCall($hShell32, "none", "ILFree", "ptr", $pParentPidl) + For $i = 1 To $iCount + DllCall($hShell32, "none", "ILFree", "ptr", DllStructGetData($tPidls, 1, $i)) + Next + + If Not $pIDataObject Then Return 0 + Return $pIDataObject +EndFunc + +Func GetDataObjectOfFile_C(ByRef $sPath) + If UBound($sPath) = 0 Then Return 0 + + Local $tIID_IDataObject = _WinAPI_GUIDFromString($sIID_IDataObject) + Local $pIDataObject = __SHCreateDataObject($tIID_IDataObject, 0, 0, 0, 0) + If Not $pIDataObject Then Return 0 + + Local Const $tag_IDataObject = _ + "GetData hresult(ptr;ptr*);" & _ + "GetDataHere hresult(ptr;ptr*);" & _ + "QueryGetData hresult(ptr);" & _ + "GetCanonicalFormatEtc hresult(ptr;ptr*);" & _ + "SetData hresult(ptr;ptr;bool);" & _ + "EnumFormatEtc hresult(dword;ptr*);" & _ + "DAdvise hresult(ptr;dword;ptr;dword*);" & _ + "DUnadvise hresult(dword);" & _ + "EnumDAdvise hresult(ptr*);" + Local $oIDataObject = ObjCreateInterface($pIDataObject, $sIID_IDataObject, $tag_IDataObject) + If Not IsObj($oIDataObject) Then + _Release($pIDataObject) + Return 0 + Endif + + Local $tFORMATETC, $tSTGMEDIUM + __Fill_tag_FORMATETC($tFORMATETC) + __Fill_tag_STGMEDIUM($tSTGMEDIUM, $sPath) + + $oIDataObject.SetData(DllStructGetPtr($tFORMATETC), DllStructGetPtr($tSTGMEDIUM), 1) + _AddRef($pIDataObject) + + Return $pIDataObject +EndFunc + +Func __Fill_tag_FORMATETC(Byref $tFORMATETC) + Local Const $CF_HDROP = 15 + Local Const $TYMED_HGLOBAL = 1 + + $tFORMATETC = DllStructCreate("ushort cfFormat; ptr ptd; uint dwAspect; int lindex; uint tymed") + DllStructSetData($tFORMATETC, "cfFormat", $CF_HDROP) + DllStructSetData($tFORMATETC, "dwAspect", 1) + DllStructSetData($tFORMATETC, "lindex", -1) + DllStructSetData($tFORMATETC, "tymed", $TYMED_HGLOBAL) +EndFunc + +Func __Fill_tag_STGMEDIUM(Byref $tSTGMEDIUM, Byref $aFiles) + Local Const $CF_HDROP = 15 + Local Const $TYMED_HGLOBAL = 1 + + Local $sFileList = "" + For $i = 0 To UBound($aFiles) - 1 + $sFileList &= $aFiles[$i] & Chr(0) + Next + $sFileList &= Chr(0) + + Local $iSize = 20 + (StringLen($sFileList) * 2) + + Local $hGlobal = DllCall($hKernel32, "ptr", "GlobalAlloc", "uint", 0x2042, "ulong_ptr", $iSize)[0] + Local $pLock = DllCall($hKernel32, "ptr", "GlobalLock", "ptr", $hGlobal)[0] + + Local $tDROPFILES = DllStructCreate("dword pFiles; int x; int y; bool fNC; bool fWide", $pLock) + DllStructSetData($tDROPFILES, "pFiles", 20) + DllStructSetData($tDROPFILES, "fWide", True) + + Local $tPaths = DllStructCreate("wchar[" & StringLen($sFileList) & "]", $pLock + 20) + DllStructSetData($tPaths, 1, $sFileList) + + DllCall($hKernel32, "bool", "GlobalUnlock", "ptr", $hGlobal) + + $tSTGMEDIUM = DllStructCreate("uint tymed; ptr hGlobal; ptr pUnkForRelease") + DllStructSetData($tSTGMEDIUM, "tymed", $TYMED_HGLOBAL) + DllStructSetData($tSTGMEDIUM, "hGlobal", $hGlobal) + DllStructSetData($tSTGMEDIUM, "pUnkForRelease", 0) +EndFunc + +Func __SHCreateDataObject($tIID_IDataObject, $ppidlFolder = 0, $cidl = 0, $papidl = 0, $pdtInner = 0) + Local $aRes = DllCall($hShell32, "long", "SHCreateDataObject", _ + "ptr", $ppidlFolder, _ + "uint", $cidl, _ + "ptr", $papidl, _ + "ptr", $pdtInner, _ + "struct*", $tIID_IDataObject, _ + "ptr*", 0) + If @error Then Return SetError(1, 0, $aRes[0]) + Return $aRes[6] +EndFunc + +Func GetDataObjectOfFile($hWnd, $sPath) + ;Get the path as an idList. This is allocated memory that we should free later on. + Local $aCall = DllCall($hShell32, "long", "SHParseDisplayName", "wstr", $sPath, "ptr", 0, "ptr*", 0, "ulong", 0, "ulong*", 0) + Local $iError = @error ? TranslateDllError() : $aCall[0] + If $iError Then Return SetError($iError, 0, False) + Local $pIdl = $aCall[3] + + ;From the idList, get two things: IShellFolder for the parent folder & the item's IDL relative to the parent folder. + Local $tIID_IShellFolder = _WinAPI_GUIDFromString($sIID_IShellFolder) + $aCall = DllCall($hShell32, "long", "SHBindToParent", "ptr", $pIdl, "struct*", $tIID_IShellFolder, "ptr*", 0, "ptr*", 0) + $iError = @error ? TranslateDllError() : $aCall[0] + If $iError Then Return SetError($iError, 0, False) + Local $pShellFolder = $aCall[3] + ;SHBindToParent does not allocate a new PID, so we're not responsible for freeing $pIdlChild. + Local $pIdlChild = $aCall[4] + + ;We have an interface tag for IShellFolder, so we can use ObjCreateInterface to "convert" it into an object datatype. + ;$oShellFolder will automatically release when it goes out of scope, so we don't need to manually _Release($pShellFolder). + Local $oShellFolder = ObjCreateInterface($pShellFolder, $sIID_IShellFolder, $tagIShellFolder) + Local $pDataObject, $tIID_IDataObject = _WinAPI_GUIDFromString($sIID_IDataObject) + $iError = $oShellFolder.GetUIObjectOf($hWnd, 1, $pIdlChild, $tIID_IDataObject, 0, $pDataObject) + + ;Free the IDL we initially created + CoTaskMemFree($pIdl) + + Return SetError($iError, 0, Ptr($pDataObject)) +EndFunc ;==>GetDataObjectOfFile + +Func CreateDropSource() + If Not $__g_hMthd_QueryInterface Then + $__g_hMthd_QueryInterface = DllCallbackRegister("__Mthd_QueryInterface", "long", "ptr;ptr;ptr") + $__g_hMthd_AddRef = DllCallbackRegister("__Mthd_AddRef", "long", "ptr") + $__g_hMthd_Release = DllCallbackRegister("__Mthd_Release", "long", "ptr") + + $__g_hMthd_QueryInterfaceThunk = DllCallbackRegister("__Mthd_QueryInterfaceThunk", "long", "ptr;ptr;ptr") + $__g_hMthd_AddRefThunk = DllCallbackRegister("__Mthd_AddRefThunk", "long", "ptr") + $__g_hMthd_ReleaseThunk = DllCallbackRegister("__Mthd_ReleaseThunk", "long", "ptr") EndIf - If Not $bArray Then - Return $sPath + If Not $__g_hMthd_QueryContinueDrag Then + $__g_hMthd_QueryContinueDrag = DllCallbackRegister("__Mthd_QueryContinueDrag", "long", "ptr;bool;dword") + $__g_hMthd_GiveFeedback = DllCallbackRegister("__Mthd_GiveFeedback", "long", "ptr;dword") EndIf - Local $aPath = _ArrayFromString($sPath) - _ArrayInsert($aPath, 0, 1) - Return $aPath -EndFunc ;==>TreeItemToPath + If Not $__g_hMthd_DragEnterTarget Then + $__g_hMthd_DragEnterTarget = DllCallbackRegister("__Mthd_DragEnterTarget", "long", "ptr;hwnd") + $__g_hMthd_DragLeaveTarget = DllCallbackRegister("__Mthd_DragLeaveTarget", "long", "ptr") + EndIf + + Local $iObjectId = UBound($__g_aObjects) + ReDim $__g_aObjects[$iObjectId + 1][UBound($__g_aObjects, 2)] + $__g_aObjects[0][0] += 1 + + Local $tUnknownVTab = DllStructCreate("ptr pFunc[3]") + $tUnknownVTab.pFunc(1) = DllCallbackGetPtr($__g_hMthd_QueryInterface) + $tUnknownVTab.pFunc(2) = DllCallbackGetPtr($__g_hMthd_AddRef) + $tUnknownVTab.pFunc(3) = DllCallbackGetPtr($__g_hMthd_Release) + + Local $tDropSrcVTab = DllStructCreate("ptr pFunc[5]") + $tDropSrcVTab.pFunc(1) = DllCallbackGetPtr($__g_hMthd_QueryInterfaceThunk) + $tDropSrcVTab.pFunc(2) = DllCallbackGetPtr($__g_hMthd_AddRefThunk) + $tDropSrcVTab.pFunc(3) = DllCallbackGetPtr($__g_hMthd_ReleaseThunk) + $tDropSrcVTab.pFunc(4) = DllCallbackGetPtr($__g_hMthd_QueryContinueDrag) + $tDropSrcVTab.pFunc(5) = DllCallbackGetPtr($__g_hMthd_GiveFeedback) + + Local $tDropSrcNotifyVTab = DllStructCreate("ptr pFunc[5]") + $tDropSrcNotifyVTab.pFunc(1) = DllCallbackGetPtr($__g_hMthd_QueryInterfaceThunk) + $tDropSrcNotifyVTab.pFunc(2) = DllCallbackGetPtr($__g_hMthd_AddRefThunk) + $tDropSrcNotifyVTab.pFunc(3) = DllCallbackGetPtr($__g_hMthd_ReleaseThunk) + $tDropSrcNotifyVTab.pFunc(4) = DllCallbackGetPtr($__g_hMthd_DragEnterTarget) + $tDropSrcNotifyVTab.pFunc(5) = DllCallbackGetPtr($__g_hMthd_DragLeaveTarget) + + Local $tagObject = "align 4;int iImplIfaces;ptr pVTab[3];int iRefCnt;" & _ + "byte IID_IUnknown[16];" & _ + "byte IID_IDropSource[16];" & _ + "byte IID_IDropSourceNotify[16];" & _ + "hwnd hTarget" + + Local $tObject = DllStructCreate($tagObject) + $tObject.pVTab(1) = DllStructGetPtr($tUnknownVTab) + $tObject.pVTab(2) = DllStructGetPtr($tDropSrcVTab) + $tObject.pVTab(3) = DllStructGetPtr($tDropSrcNotifyVTab) + + $tObject.iRefCnt = 1 + $tObject.iImplIfaces = 3 + _WinAPI_GUIDFromStringEx($sIID_IUnknown, DllStructGetPtr($tObject, "IID_IUnknown")) + _WinAPI_GUIDFromStringEx($sIID_IDropSource, DllStructGetPtr($tObject, "IID_IDropSource")) + _WinAPI_GUIDFromStringEx($sIID_IDropSourceNotify, DllStructGetPtr($tObject, "IID_IDropSourceNotify")) + + Local $pObject = DllStructGetPtr($tObject, "pVTab") + + $__g_aObjects[$iObjectId][0] = $pObject + $__g_aObjects[$iObjectId][1] = $tObject + $__g_aObjects[$iObjectId][2] = $tUnknownVTab + $__g_aObjects[$iObjectId][3] = $tDropSrcVTab + $__g_aObjects[$iObjectId][4] = $tDropSrcNotifyVTab + + Return $pObject +EndFunc ;==>CreateDropSource + +Func DestroyDropSource($pObject) + If (Not $pObject) Or (Not IsPtr($pObject)) Then Return SetError($ERROR_INVALID_PARAMETER, 0, False) + + For $i = 0 To UBound($__g_aObjects) - 1 + If $__g_aObjects[$i][0] = $pObject Then ExitLoop + Next + If $i = UBound($__g_aObjects) Then Return SetError($ERROR_INVALID_PARAMETER, 0, False) + + For $j = 0 To UBound($__g_aObjects, 2) - 1 + $__g_aObjects[$i][$j] = 0 + Next + $__g_aObjects[0][0] -= 1 + + If Not $__g_aObjects[0][0] Then + DllCallbackFree($__g_hMthd_QueryInterface) + DllCallbackFree($__g_hMthd_AddRef) + DllCallbackFree($__g_hMthd_Release) + DllCallbackFree($__g_hMthd_QueryInterfaceThunk) + DllCallbackFree($__g_hMthd_AddRefThunk) + DllCallbackFree($__g_hMthd_ReleaseThunk) + DllCallbackFree($__g_hMthd_QueryContinueDrag) + DllCallbackFree($__g_hMthd_GiveFeedback) + DllCallbackFree($__g_hMthd_DragEnterTarget) + DllCallbackFree($__g_hMthd_DragLeaveTarget) + + $__g_hMthd_QueryInterface = 0 + $__g_hMthd_AddRef = 0 + $__g_hMthd_Release = 0 + $__g_hMthd_QueryInterfaceThunk = 0 + $__g_hMthd_AddRefThunk = 0 + $__g_hMthd_ReleaseThunk = 0 + $__g_hMthd_QueryContinueDrag = 0 + $__g_hMthd_GiveFeedback = 0 + $__g_hMthd_DragEnterTarget = 0 + $__g_hMthd_DragLeaveTarget = 0 + EndIf +EndFunc ;==>DestroyDropSource + + +#Region Internal IUnknown Methods + +Func __Mthd_QueryInterface($pThis, $pIID, $ppObj) + Local $hResult = $S_OK + + Local $iIIDCnt = DllStructGetData(DllStructCreate("int", Ptr($pThis - 4)), 1) + Local $tThis = DllStructCreate(StringFormat("align 4;ptr pVTab[%d];int iRefCnt", $iIIDCnt), $pThis) + + Local $pTestIID = DllStructGetPtr($tThis, "iRefCnt") + 4 + If Not $ppObj Then + $hResult = $E_POINTER + Else + For $i = 0 To $iIIDCnt - 1 + If _WinAPI_StringFromGUID($pIID) = _WinAPI_StringFromGUID(Ptr($pTestIID)) Then + DllStructSetData(DllStructCreate("ptr", $ppObj), 1, Ptr($pThis + $i * $PTR_LEN)) + __Mthd_AddRef($pThis) + ExitLoop + EndIf + $pTestIID += 16 + Next + If $i = $iIIDCnt Then $hResult = $E_NOINTERFACE + + EndIf + Return $hResult +EndFunc ;==>__Mthd_QueryInterface + +Func __Mthd_AddRef($pThis) + Local $iImplIfaces = DllStructGetData(DllStructCreate("int", Ptr($pThis - 4)), 1) + Local $tThis = DllStructCreate(StringFormat("align 4;ptr pVTab[%d];int iRefCnt", $iImplIfaces), $pThis) + $tThis.iRefCnt += 1 + Return $tThis.iRefCnt +EndFunc ;==>__Mthd_AddRef + +Func __Mthd_Release($pThis) + Local $iImplIfaces = DllStructGetData(DllStructCreate("int", Ptr($pThis - 4)), 1) + Local $tThis = DllStructCreate(StringFormat("align 4;ptr pVTab[%d];int iRefCnt", $iImplIfaces), $pThis) + $tThis.iRefCnt -= 1 + Return $tThis.iRefCnt +EndFunc ;==>__Mthd_Release + +Func __Mthd_QueryInterfaceThunk($pThis, $pIID, $ppObj) + Local $hResult = $S_OK + Local $tIID = DllStructCreate($tagGUID, $pIID) + If _WinAPI_StringFromGUID($tIID) = $sIID_IUnknown Then + DllStructSetData(DllStructCreate("ptr", $ppObj), 1, $pThis) + Else + $pThis = Ptr($pThis - $PTR_LEN) + Local $pVTab = DllStructGetData(DllStructCreate("ptr", $pThis), 1) + Local $pFunc = DllStructGetData(DllStructCreate("ptr", $pVTab), 1) + Local $aCall = DllCallAddress("long", $pFunc, "ptr", $pThis, "ptr", $pIID, "ptr", $ppObj) + $hResult = $aCall[0] + EndIf + Return $hResult +EndFunc ;==>__Mthd_QueryInterfaceThunk + +Func __Mthd_AddRefThunk($pThis) + $pThis = Ptr($pThis - $PTR_LEN) + Return _AddRef($pThis) +EndFunc ;==>__Mthd_AddRefThunk + +Func __Mthd_ReleaseThunk($pThis) + $pThis = Ptr($pThis - $PTR_LEN) + Return _Release($pThis) +EndFunc ;==>__Mthd_ReleaseThunk +#EndRegion Internal IUnknown Methods + +#Region Internal IDataSource Methods + +Func __Mthd_QueryContinueDrag($pThis, $bEscapePressed, $iKeyState) + #forceref $pThis, $bEscapePressed, $iKeyState + +;~ Key State values may be combined. Test using BitAND! +;~ If BitAND($MK_RBUTTON, $iKeyState) Then ... + +;~ Key Constants: +;~ $MK_RBUTTON +;~ $MK_SHIFT +;~ $MK_CONTROL +;~ $MK_MBUTTON +;~ $MK_XBUTTON1 +;~ $MK_XBUTTON2 + + Local $iReturn = $S_OK + If $bEscapePressed Then + $iReturn = $DRAGDROP_S_CANCEL + Else + If Not BitAND($iKeyState, BitOR($MK_LBUTTON, $MK_RBUTTON)) Then $iReturn = $DRAGDROP_S_DROP + EndIf + + Return $iReturn +EndFunc ;==>__Mthd_QueryContinueDrag + + +Func __Mthd_GiveFeedback($pThis, $iEffect) + #forceref $pThis, $iEffect + +;~ Drop effect values may be combined. Test using BitAND! +;~ If BitAND($DROPEFFECT_COPY, $iEffect) Then ... + +;~ Effect Constants... +;~ $DROPEFFECT_NONE +;~ $DROPEFFECT_COPY +;~ $DROPEFFECT_MOVE +;~ $DROPEFFECT_LINK +;~ $DROPEFFECT_SCROLL + + Local $sTreeListItemText + Local Static $sTreeListItemTextPrev + + Select + Case $sTargetCtrl = 'Tree' + Local $hItemHover = TreeItemFromPoint($g_hTreeView) + If $hItemHover <> 0 Then + ; bring focus to treeview to properly show DROPHILITE + _WinAPI_SetFocus($g_hTreeView) + _GUICtrlTreeView_SelectItem($g_hTreeView, $hItemHover) + _GUICtrlTreeView_SetState($g_hTreeView, $hTreeItemOrig, $TVIS_SELECTED, True) + Else + ; restore original treeview selection if cursor leaves treeview + _GUICtrlTreeView_SelectItem($g_hTreeView, $hTreeItemOrig) + EndIf + Case $sTargetCtrl = 'List' + Local $iListHover = ListItemFromPoint($g_hListview) + If $iListHover >= 0 Then + ; bring focus to listview to show hot item (needed for listview to listview drag) + _WinAPI_SetFocus($g_hListview) + _GUICtrlListView_SetHotItem($idListview, $iListHover) + EndIf + Case Else + ; restore proper state back to original treeview selection + _GUICtrlTreeView_SelectItem($g_hTreeView, $hTreeItemOrig) + EndSelect + + Return $DRAGDROP_S_USEDEFAULTCURSORS +EndFunc ;==>__Mthd_GiveFeedback + +#EndRegion Internal IDataSource Methods + +#Region Internal IDataSourceNotify Methods +Func __Mthd_DragEnterTarget($pThis, $hTarget) + Local Const $iDataOffset = 52 + $PTR_LEN + Local $tData = DllStructCreate("align 4; hwnd hTarget", Ptr($pThis + $iDataOffset)) + DllStructSetData($tData, "hTarget", $hTarget) + Local $hTargetCtrl = DllStructSetData($tData, "hTarget", $hTarget) + If $hTargetCtrl = $g_hTreeView Then + ConsoleWrite("drag target is treeview" & @CRLF) + $sTargetCtrl = 'Tree' + EndIf + If $hTargetCtrl = $g_hListview Then + ConsoleWrite("drag target is listview" & @CRLF) + $sTargetCtrl = 'List' + EndIf + ;ConsoleWrite("target: " & DllStructSetData($tData, "hTarget", $hTarget) & @CRLF) + ;ConsoleWrite("parent: " & _WinAPI_GetAncestor(DllStructSetData($tData, "hTarget", $hTarget), $GA_PARENT) & @CRLF) + + Return $S_OK +EndFunc ;==>__Mthd_DragEnterTarget + +Func __Mthd_DragLeaveTarget($pThis) + Local Const $iDataOffset = 52 + $PTR_LEN + Local $tData = DllStructCreate("align 4; hwnd hTarget", Ptr($pThis + $iDataOffset)) + DllStructSetData($tData, "hTarget", 0) + $sTargetCtrl = '' + + Return $S_OK +EndFunc ;==>__Mthd_DragLeaveTarget +#EndRegion Internal IDataSourceNotify Methods From 75d70f92749a67faf2040b5fd721473ded453fa1 Mon Sep 17 00:00:00 2001 From: WildByDesign Date: Tue, 3 Feb 2026 11:06:10 -0500 Subject: [PATCH 02/14] Update drag and drop code - add drop target functionality --- lib/DropSourceObject.au3 | 347 ++++++------------------------- lib/DropTargetObject.au3 | 436 +++++++++++++++++++++++++++++++++++++++ lib/InternalObject.au3 | 156 ++++++++++++++ lib/ProjectConstants.au3 | 118 ++++++++++- src/desktop.ini | 2 + src/main.au3 | 338 ++++-------------------------- 6 files changed, 813 insertions(+), 584 deletions(-) create mode 100644 lib/DropTargetObject.au3 create mode 100644 lib/InternalObject.au3 create mode 100644 src/desktop.ini diff --git a/lib/DropSourceObject.au3 b/lib/DropSourceObject.au3 index 4dcd01b..b0ef5d8 100644 --- a/lib/DropSourceObject.au3 +++ b/lib/DropSourceObject.au3 @@ -1,266 +1,87 @@ #include-once -#include "ProjectConstants.au3" +#include "InternalObject.au3" #include "IUnknown.au3" -#include -#include -#include +Global $__g_iDropSourceCount -Global $g_hListview, $g_hTreeView, $sTargetCtrl, $hTLESystem - -; In this file we're probably just interested in these methods. The rest is just stuff to make our internal object work! -; __Mthd_QueryContinueDrag, __Mthd_GiveFeedback -; __Mthd_DragEnterTarget, __Mthd_DragLeaveTarget - -; __Mthd_QueryContinueDrag is called in a loop - it asks us if we want to continue the drag/drop. -; And we say: -; "drop!" if the left and right buttons are up. -; "cancel!" if the esc key is pressed. -; otherwise "Continue looping!" - -; __Mthd_GiveFeedback provides us with the oportunity to update the mouse cursor. -; We're delegating this to the system by returning DRAGDROP_S_USEDEFAULTCURSORS - -; __Mthd_DragEnterTarget & __Mthd_DragLeaveTarget lets us know what we're currently hovering over. (as a window handle) -; Just in case you want to do anything with that info!. - -;-------------------------------------------------------------------------------------------------------------- -; Our DropSource Object in memory... -;-------------------------------------------------------------------------------------------------------------- -; -; The left most column aren't part of the object - they're interface pointers. -; All of them are valid "object pointers" for our object. Regardless, some functions require us to provide a ptr to a specific interface. -; -; The "Thunk" methods are stubs, and redirect to the methods on pIUnkVtab. -; IIDs in aSupportedIIDs[] must be in the same order as the vtables in our layout. -; -; -; +- iIfaceCount -; | -; pIUnknown-----> +- pIUnkVtab --------> +- pQueryInterface -; | +- pAddRef -; | +- pRelease -; | -; pIDropSource -> += pIDrpSrcVTab -----> +- pQueryInterfaceThunk -; | +- pAddRefThunk -; | +- pReleaseThunk -; | +- pQueryContinueDrag -; | +- pGiveFeedback -; | -; pIDrpSrcNtfy -> += pIDrpSrcNtfyVTab--> +- pQueryInterfaceThunk -; | +- pAddRefThunk -; | +- pReleaseThunk -; | +- pDragEnterTarget -; | +- pDragLeaveTarget -; +- iRefCount -; | -; +- aSupportedIIDs[IID_IUnknown, IID_IDropSource, IID_IDropSourceNotify] -; | | -; +- hTarget -; -;-------------------------------------------------------------------------------------------------------------- - - - -Global $__g_aObjects[1][20] -Global $__g_hMthd_QueryInterface, $__g_hMthd_AddRef, $__g_hMthd_Release -Global $__g_hMthd_QueryInterfaceThunk, $__g_hMthd_AddRefThunk, $__g_hMthd_ReleaseThunk Global $__g_hMthd_QueryContinueDrag, $__g_hMthd_GiveFeedback Global $__g_hMthd_DragEnterTarget, $__g_hMthd_DragLeaveTarget +Global $tagSourceObjIntData = "hwnd hTarget;" + + Func CreateDropSource() - If Not $__g_hMthd_QueryInterface Then - $__g_hMthd_QueryInterface = DllCallbackRegister("__Mthd_QueryInterface", "long", "ptr;ptr;ptr") - $__g_hMthd_AddRef = DllCallbackRegister("__Mthd_AddRef", "long", "ptr") - $__g_hMthd_Release = DllCallbackRegister("__Mthd_Release", "long", "ptr") + $__g_iDropSourceCount += 1 - $__g_hMthd_QueryInterfaceThunk = DllCallbackRegister("__Mthd_QueryInterfaceThunk", "long", "ptr;ptr;ptr") - $__g_hMthd_AddRefThunk = DllCallbackRegister("__Mthd_AddRefThunk", "long", "ptr") - $__g_hMthd_ReleaseThunk = DllCallbackRegister("__Mthd_ReleaseThunk", "long", "ptr") - EndIf + Local $iObjectId = PrepareInternalObject(3) + Local $tObject = $__g_aObjects[$iObjectId][1] + Local $tSupportedIIDs = $__g_aObjects[$iObjectId][2] If Not $__g_hMthd_QueryContinueDrag Then $__g_hMthd_QueryContinueDrag = DllCallbackRegister("__Mthd_QueryContinueDrag", "long", "ptr;bool;dword") $__g_hMthd_GiveFeedback = DllCallbackRegister("__Mthd_GiveFeedback", "long", "ptr;dword") - EndIf - - If Not $__g_hMthd_DragEnterTarget Then $__g_hMthd_DragEnterTarget = DllCallbackRegister("__Mthd_DragEnterTarget", "long", "ptr;hwnd") $__g_hMthd_DragLeaveTarget = DllCallbackRegister("__Mthd_DragLeaveTarget", "long", "ptr") EndIf - Local $iObjectId = UBound($__g_aObjects) - ReDim $__g_aObjects[$iObjectId + 1][UBound($__g_aObjects, 2)] - $__g_aObjects[0][0] += 1 - - Local $tUnknownVTab = DllStructCreate("ptr pFunc[3]") - $tUnknownVTab.pFunc(1) = DllCallbackGetPtr($__g_hMthd_QueryInterface) - $tUnknownVTab.pFunc(2) = DllCallbackGetPtr($__g_hMthd_AddRef) - $tUnknownVTab.pFunc(3) = DllCallbackGetPtr($__g_hMthd_Release) - - Local $tDropSrcVTab = DllStructCreate("ptr pFunc[5]") - $tDropSrcVTab.pFunc(1) = DllCallbackGetPtr($__g_hMthd_QueryInterfaceThunk) - $tDropSrcVTab.pFunc(2) = DllCallbackGetPtr($__g_hMthd_AddRefThunk) - $tDropSrcVTab.pFunc(3) = DllCallbackGetPtr($__g_hMthd_ReleaseThunk) - $tDropSrcVTab.pFunc(4) = DllCallbackGetPtr($__g_hMthd_QueryContinueDrag) - $tDropSrcVTab.pFunc(5) = DllCallbackGetPtr($__g_hMthd_GiveFeedback) - - Local $tDropSrcNotifyVTab = DllStructCreate("ptr pFunc[5]") - $tDropSrcNotifyVTab.pFunc(1) = DllCallbackGetPtr($__g_hMthd_QueryInterfaceThunk) - $tDropSrcNotifyVTab.pFunc(2) = DllCallbackGetPtr($__g_hMthd_AddRefThunk) - $tDropSrcNotifyVTab.pFunc(3) = DllCallbackGetPtr($__g_hMthd_ReleaseThunk) - $tDropSrcNotifyVTab.pFunc(4) = DllCallbackGetPtr($__g_hMthd_DragEnterTarget) - $tDropSrcNotifyVTab.pFunc(5) = DllCallbackGetPtr($__g_hMthd_DragLeaveTarget) - - Local $tagObject = "align 4;int iImplIfaces;ptr pVTab[3];int iRefCnt;" & _ - "byte IID_IUnknown[16];" & _ - "byte IID_IDropSource[16];" & _ - "byte IID_IDropSourceNotify[16];" & _ - "hwnd hTarget" - - Local $tObject = DllStructCreate($tagObject) - $tObject.pVTab(1) = DllStructGetPtr($tUnknownVTab) - $tObject.pVTab(2) = DllStructGetPtr($tDropSrcVTab) - $tObject.pVTab(3) = DllStructGetPtr($tDropSrcNotifyVTab) - - $tObject.iRefCnt = 1 - $tObject.iImplIfaces = 3 - _WinAPI_GUIDFromStringEx($sIID_IUnknown, DllStructGetPtr($tObject, "IID_IUnknown")) - _WinAPI_GUIDFromStringEx($sIID_IDropSource, DllStructGetPtr($tObject, "IID_IDropSource")) - _WinAPI_GUIDFromStringEx($sIID_IDropSourceNotify, DllStructGetPtr($tObject, "IID_IDropSourceNotify")) - - Local $pObject = DllStructGetPtr($tObject, "pVTab") - - $__g_aObjects[$iObjectId][0] = $pObject - $__g_aObjects[$iObjectId][1] = $tObject - $__g_aObjects[$iObjectId][2] = $tUnknownVTab - $__g_aObjects[$iObjectId][3] = $tDropSrcVTab - $__g_aObjects[$iObjectId][4] = $tDropSrcNotifyVTab - - Return $pObject + Local $tIDropSrcVTab = DllStructCreate("ptr pFunc[5]") + $tIDropSrcVTab.pFunc(1) = DllCallbackGetPtr($__g_hMthd_QueryInterfaceThunk) + $tIDropSrcVTab.pFunc(2) = DllCallbackGetPtr($__g_hMthd_AddRefThunk) + $tIDropSrcVTab.pFunc(3) = DllCallbackGetPtr($__g_hMthd_ReleaseThunk) + $tIDropSrcVTab.pFunc(4) = DllCallbackGetPtr($__g_hMthd_QueryContinueDrag) + $tIDropSrcVTab.pFunc(5) = DllCallbackGetPtr($__g_hMthd_GiveFeedback) + + Local $tIDropSrcNotifyVTab = DllStructCreate("ptr pFunc[5]") + $tIDropSrcNotifyVTab.pFunc(1) = DllCallbackGetPtr($__g_hMthd_QueryInterfaceThunk) + $tIDropSrcNotifyVTab.pFunc(2) = DllCallbackGetPtr($__g_hMthd_AddRefThunk) + $tIDropSrcNotifyVTab.pFunc(3) = DllCallbackGetPtr($__g_hMthd_ReleaseThunk) + $tIDropSrcNotifyVTab.pFunc(4) = DllCallbackGetPtr($__g_hMthd_DragEnterTarget) + $tIDropSrcNotifyVTab.pFunc(5) = DllCallbackGetPtr($__g_hMthd_DragLeaveTarget) + + Local $tInternalData = DllStructCreate($tagSourceObjIntData) + + $tObject.pVTab(2) = DllStructGetPtr($tIDropSrcVTab) + $tObject.pVTab(3) = DllStructGetPtr($tIDropSrcNotifyVTab) + $tObject.pData = DllStructGetPtr($tInternalData) + _WinAPI_GUIDFromStringEx($sIID_IDropSource, DllStructGetPtr($tSupportedIIDs, 2)) + _WinAPI_GUIDFromStringEx($sIID_IDropSourceNotify, DllStructGetPtr($tSupportedIIDs, 3)) + + $__g_aObjects[$iObjectId][4] = $tIDropSrcVTab + $__g_aObjects[$iObjectId][5] = $tIDropSrcNotifyVTab + $__g_aObjects[$iObjectId][6] = $tInternalData + +;~ ConsoleWrite("IUnknown Location: " & DllStructGetPtr($tObject, "pVTab") & @CRLF) +;~ ConsoleWrite("IDropSource Location: " & DllStructGetPtr($tObject, "pVTab") + $PTR_LEN & @CRLF) +;~ ConsoleWrite("IDropNotify Location: " & DllStructGetPtr($tObject, "pVTab") + 2*$PTR_LEN & @CRLF) + + $__g_aObjects[$iObjectId][0] = DllStructGetPtr($tObject, "pVTab") + $PTR_LEN + Return $__g_aObjects[$iObjectId][0] EndFunc ;==>CreateDropSource Func DestroyDropSource($pObject) If (Not $pObject) Or (Not IsPtr($pObject)) Then Return SetError($ERROR_INVALID_PARAMETER, 0, False) - For $i = 0 To UBound($__g_aObjects) - 1 - If $__g_aObjects[$i][0] = $pObject Then ExitLoop - Next - If $i = UBound($__g_aObjects) Then Return SetError($ERROR_INVALID_PARAMETER, 0, False) - - For $j = 0 To UBound($__g_aObjects, 2) - 1 - $__g_aObjects[$i][$j] = 0 - Next - $__g_aObjects[0][0] -= 1 - - If Not $__g_aObjects[0][0] Then - DllCallbackFree($__g_hMthd_QueryInterface) - DllCallbackFree($__g_hMthd_AddRef) - DllCallbackFree($__g_hMthd_Release) - DllCallbackFree($__g_hMthd_QueryInterfaceThunk) - DllCallbackFree($__g_hMthd_AddRefThunk) - DllCallbackFree($__g_hMthd_ReleaseThunk) - DllCallbackFree($__g_hMthd_QueryContinueDrag) - DllCallbackFree($__g_hMthd_GiveFeedback) - DllCallbackFree($__g_hMthd_DragEnterTarget) - DllCallbackFree($__g_hMthd_DragLeaveTarget) - - $__g_hMthd_QueryInterface = 0 - $__g_hMthd_AddRef = 0 - $__g_hMthd_Release = 0 - $__g_hMthd_QueryInterfaceThunk = 0 - $__g_hMthd_AddRefThunk = 0 - $__g_hMthd_ReleaseThunk = 0 - $__g_hMthd_QueryContinueDrag = 0 - $__g_hMthd_GiveFeedback = 0 - $__g_hMthd_DragEnterTarget = 0 - $__g_hMthd_DragLeaveTarget = 0 + DestroyInternalObject($pObject) + If Not @error Then + $__g_iDropSourceCount -= 1 + If Not $__g_iDropSourceCount Then + DllCallbackFree($__g_hMthd_QueryContinueDrag) + DllCallbackFree($__g_hMthd_GiveFeedback) + DllCallbackFree($__g_hMthd_DragEnterTarget) + DllCallbackFree($__g_hMthd_DragLeaveTarget) + + $__g_hMthd_QueryContinueDrag = 0 + $__g_hMthd_GiveFeedback = 0 + $__g_hMthd_DragEnterTarget = 0 + $__g_hMthd_DragLeaveTarget = 0 + EndIf EndIf EndFunc ;==>DestroyDropSource -#Region Internal IUnknown Methods - -Func __Mthd_QueryInterface($pThis, $pIID, $ppObj) - Local $hResult = $S_OK - - Local $iIIDCnt = DllStructGetData(DllStructCreate("int", Ptr($pThis - 4)), 1) - Local $tThis = DllStructCreate(StringFormat("align 4;ptr pVTab[%d];int iRefCnt", $iIIDCnt), $pThis) - - Local $pTestIID = DllStructGetPtr($tThis, "iRefCnt") + 4 - If Not $ppObj Then - $hResult = $E_POINTER - Else - For $i = 0 To $iIIDCnt - 1 - If _WinAPI_StringFromGUID($pIID) = _WinAPI_StringFromGUID(Ptr($pTestIID)) Then - DllStructSetData(DllStructCreate("ptr", $ppObj), 1, Ptr($pThis + $i * $PTR_LEN)) - __Mthd_AddRef($pThis) - ExitLoop - EndIf - $pTestIID += 16 - Next - If $i = $iIIDCnt Then $hResult = $E_NOINTERFACE - - EndIf - Return $hResult -EndFunc ;==>__Mthd_QueryInterface - -Func __Mthd_AddRef($pThis) - Local $iImplIfaces = DllStructGetData(DllStructCreate("int", Ptr($pThis - 4)), 1) - Local $tThis = DllStructCreate(StringFormat("align 4;ptr pVTab[%d];int iRefCnt", $iImplIfaces), $pThis) - $tThis.iRefCnt += 1 - Return $tThis.iRefCnt -EndFunc ;==>__Mthd_AddRef - -Func __Mthd_Release($pThis) - Local $iImplIfaces = DllStructGetData(DllStructCreate("int", Ptr($pThis - 4)), 1) - Local $tThis = DllStructCreate(StringFormat("align 4;ptr pVTab[%d];int iRefCnt", $iImplIfaces), $pThis) - $tThis.iRefCnt -= 1 - Return $tThis.iRefCnt -EndFunc ;==>__Mthd_Release - -Func __Mthd_QueryInterfaceThunk($pThis, $pIID, $ppObj) - Local $hResult = $S_OK - Local $tIID = DllStructCreate($tagGUID, $pIID) - If _WinAPI_StringFromGUID($tIID) = $sIID_IUnknown Then - DllStructSetData(DllStructCreate("ptr", $ppObj), 1, $pThis) - Else - $pThis = Ptr($pThis - $PTR_LEN) - Local $pVTab = DllStructGetData(DllStructCreate("ptr", $pThis), 1) - Local $pFunc = DllStructGetData(DllStructCreate("ptr", $pVTab), 1) - Local $aCall = DllCallAddress("long", $pFunc, "ptr", $pThis, "ptr", $pIID, "ptr", $ppObj) - $hResult = $aCall[0] - EndIf - Return $hResult -EndFunc ;==>__Mthd_QueryInterfaceThunk - -Func __Mthd_AddRefThunk($pThis) - $pThis = Ptr($pThis - $PTR_LEN) - Return _AddRef($pThis) -EndFunc ;==>__Mthd_AddRefThunk - -Func __Mthd_ReleaseThunk($pThis) - $pThis = Ptr($pThis - $PTR_LEN) - Return _Release($pThis) -EndFunc ;==>__Mthd_ReleaseThunk -#EndRegion Internal IUnknown Methods - -#Region Internal IDataSource Methods - Func __Mthd_QueryContinueDrag($pThis, $bEscapePressed, $iKeyState) #forceref $pThis, $bEscapePressed, $iKeyState -;~ Key State values may be combined. Test using BitAND! -;~ If BitAND($MK_RBUTTON, $iKeyState) Then ... - -;~ Key Constants: -;~ $MK_RBUTTON -;~ $MK_SHIFT -;~ $MK_CONTROL -;~ $MK_MBUTTON -;~ $MK_XBUTTON1 -;~ $MK_XBUTTON2 - Local $iReturn = $S_OK If $bEscapePressed Then $iReturn = $DRAGDROP_S_CANCEL @@ -275,66 +96,28 @@ EndFunc ;==>__Mthd_QueryContinueDrag Func __Mthd_GiveFeedback($pThis, $iEffect) #forceref $pThis, $iEffect -;~ Drop effect values may be combined. Test using BitAND! -;~ If BitAND($DROPEFFECT_COPY, $iEffect) Then ... - -;~ Effect Constants... -;~ $DROPEFFECT_NONE -;~ $DROPEFFECT_COPY -;~ $DROPEFFECT_MOVE -;~ $DROPEFFECT_LINK -;~ $DROPEFFECT_SCROLL - - Select - Case $sTargetCtrl = 'Tree' - ; use __TreeListExplorer_GetPath($hTLESystem) to obtain initial tree path - ; reset selection back to original after - Local $hItemHover = TreeItemFromPoint2($g_hTreeView) - _WinAPI_SetFocus($g_hTreeView) - _GUICtrlTreeView_SelectItem($g_hTreeView, $hItemHover) - _GUICtrlTreeView_SetState($g_hTreeView, __TreeListExplorer_GetPath($hTLESystem), $TVIS_SELECTED, True) - Case $sTargetCtrl = 'List' - ; - Case Else - ; clear - EndSelect +;~ Local Const $iDataOffset = $PTR_LEN * 3 + 4 +;~ Local $pData = DllStructGetData(DllStructCreate("ptr", Ptr($pThis + $iDataOffset)), 1) +;~ Local $tData = DllStructCreate($tagSourceObjIntData, $pData) Return $DRAGDROP_S_USEDEFAULTCURSORS EndFunc ;==>__Mthd_GiveFeedback -#EndRegion Internal IDataSource Methods - -#Region Internal IDataSourceNotify Methods Func __Mthd_DragEnterTarget($pThis, $hTarget) - Local Const $iDataOffset = 52 + $PTR_LEN - Local $tData = DllStructCreate("align 4; hwnd hTarget", Ptr($pThis + $iDataOffset)) + Local Const $iDataOffset = $PTR_LEN * 2 + 4 + Local $pData = DllStructGetData(DllStructCreate("ptr", Ptr($pThis + $iDataOffset)), 1) + Local $tData = DllStructCreate($tagSourceObjIntData, $pData) DllStructSetData($tData, "hTarget", $hTarget) - Local $hTargetCtrl = DllStructSetData($tData, "hTarget", $hTarget) - If $hTargetCtrl = $g_hTreeView Then - ConsoleWrite("drag target is treeview" & @CRLF) - $sTargetCtrl = 'Tree' - EndIf - If $hTargetCtrl = $g_hListview Then - ConsoleWrite("drag target is listview" & @CRLF) - $sTargetCtrl = 'List' - EndIf - ;ConsoleWrite("target: " & DllStructSetData($tData, "hTarget", $hTarget) & @CRLF) - ;ConsoleWrite("parent: " & _WinAPI_GetAncestor(DllStructSetData($tData, "hTarget", $hTarget), $GA_PARENT) & @CRLF) Return $S_OK EndFunc ;==>__Mthd_DragEnterTarget Func __Mthd_DragLeaveTarget($pThis) - Local Const $iDataOffset = 52 + $PTR_LEN - Local $tData = DllStructCreate("align 4; hwnd hTarget", Ptr($pThis + $iDataOffset)) + #forceref $pThis + Local Const $iDataOffset = $PTR_LEN * 2 + 4 + Local $pData = DllStructGetData(DllStructCreate("ptr", Ptr($pThis + $iDataOffset)), 1) + Local $tData = DllStructCreate($tagSourceObjIntData, $pData) DllStructSetData($tData, "hTarget", 0) - $sTargetCtrl = '' Return $S_OK EndFunc ;==>__Mthd_DragLeaveTarget -#EndRegion Internal IDataSourceNotify Methods - -Func TreeItemFromPoint2($hWnd) - Local $tMPos = _WinAPI_GetMousePos(True, $hWnd) - Return _GUICtrlTreeView_HitTestItem($hWnd, DllStructGetData($tMPos, 1), DllStructGetData($tMPos, 2)) -EndFunc ;==>TreeItemFromPoint2 diff --git a/lib/DropTargetObject.au3 b/lib/DropTargetObject.au3 new file mode 100644 index 0000000..3054362 --- /dev/null +++ b/lib/DropTargetObject.au3 @@ -0,0 +1,436 @@ +#include-once +#include +#include +#include "InternalObject.au3" +#include "IUnknown.au3" +#include +#include +#include +#include +#include + +#include +#include "TreeListExplorer.au3" + +Global $__g_iDropTargetCount +Global $__g_hMthd_DragEnter, $__g_hMthd_DragOver, $__g_hMthd_DragLeave, $__g_hMthd_Drop +Global $tagTargetObjIntData = "hwnd hTarget;bool bAcceptDrop;ptr pDataObject;ptr pIDropTgtHelper" +Global Const $__g_iTargetObjDataOffset = $PTR_LEN * 2 + 4 + +Global $hTreeOrig + +Func CreateDropTarget($hTarget = 0) + $__g_iDropTargetCount += 1 + + Local $iObjectId = PrepareInternalObject(2) + Local $tObject = $__g_aObjects[$iObjectId][1] + Local $tSupportedIIDs = $__g_aObjects[$iObjectId][2] + + If Not $__g_hMthd_DragEnter Then + $__g_hMthd_DragEnter = DllCallbackRegister("__Mthd_DragEnter", "long", "ptr;ptr;dword;uint64;ptr") + $__g_hMthd_DragOver = DllCallbackRegister("__Mthd_DragOver", "long", "ptr;dword;uint64;ptr") + $__g_hMthd_DragLeave = DllCallbackRegister("__Mthd_DragLeave", "long", "ptr") + $__g_hMthd_Drop = DllCallbackRegister("__Mthd_Drop", "long", "ptr;ptr;dword;uint64;ptr") + EndIf + + Local $tIDropTgtVTab = DllStructCreate("ptr pFunc[7]") + $tIDropTgtVTab.pFunc(1) = DllCallbackGetPtr($__g_hMthd_QueryInterfaceThunk) + $tIDropTgtVTab.pFunc(2) = DllCallbackGetPtr($__g_hMthd_AddRefThunk) + $tIDropTgtVTab.pFunc(3) = DllCallbackGetPtr($__g_hMthd_ReleaseThunk) + $tIDropTgtVTab.pFunc(4) = DllCallbackGetPtr($__g_hMthd_DragEnter) + $tIDropTgtVTab.pFunc(5) = DllCallbackGetPtr($__g_hMthd_DragOver) + $tIDropTgtVTab.pFunc(6) = DllCallbackGetPtr($__g_hMthd_DragLeave) + $tIDropTgtVTab.pFunc(7) = DllCallbackGetPtr($__g_hMthd_Drop) + + Local $tInternalData = DllStructCreate($tagTargetObjIntData) + $tInternalData.hTarget = $hTarget + + $tObject.pVTab(2) = DllStructGetPtr($tIDropTgtVTab) + $tObject.pData = DllStructGetPtr($tInternalData) + _WinAPI_GUIDFromStringEx($sIID_IDropTarget, DllStructGetPtr($tSupportedIIDs, 2)) + + $__g_aObjects[$iObjectId][4] = $tIDropTgtVTab + $__g_aObjects[$iObjectId][5] = $tInternalData + + Local $oDropTgtHelper = ObjCreateInterface($sCLSID_DragDropHelper, $sIID_IDropTargetHelper, $tagIDropTargetHelper) + + Local $pIDropTgtHelper + $oDropTgtHelper.QueryInterface($sIID_IDropTargetHelper, $pIDropTgtHelper) + $tInternalData.pIDropTgtHelper = $pIDropTgtHelper + +;~ ConsoleWrite("IUnknown Location: " & DllStructGetPtr($tObject, "pVTab") & @CRLF) +;~ ConsoleWrite("IDropTarget Location: " & DllStructGetPtr($tObject, "pVTab") + $PTR_LEN & @CRLF) + + $__g_aObjects[$iObjectId][0] = DllStructGetPtr($tObject, "pVTab") + $PTR_LEN + Return $__g_aObjects[$iObjectId][0] +EndFunc ;==>CreateDropTarget + +Func DestroyDropTarget($pObject) + If (Not $pObject) Or (Not IsPtr($pObject)) Then Return SetError($ERROR_INVALID_PARAMETER, 0, False) + + Local $pData = DllStructGetData(DllStructCreate("ptr", Ptr($pObject + $__g_iTargetObjDataOffset)), 1) + Local $tData = DllStructCreate($tagTargetObjIntData, $pData) + _Release($tData.pIDropTgtHelper) + + DestroyInternalObject($pObject) + If Not @error Then + $__g_iDropTargetCount -= 1 + If Not $__g_iDropTargetCount Then + DllCallbackFree($__g_hMthd_DragEnter) + DllCallbackFree($__g_hMthd_DragOver) + DllCallbackFree($__g_hMthd_DragLeave) + DllCallbackFree($__g_hMthd_Drop) + + $__g_hMthd_DragEnter = 0 + $__g_hMthd_DragOver = 0 + $__g_hMthd_DragLeave = 0 + $__g_hMthd_Drop = 0 + EndIf + EndIf +EndFunc ;==>DestroyDropTarget + +Func __Mthd_DragEnter($pThis, $pDataOject, $iKeyState, $iPoint, $piEffect) + + #forceref $pThis, $pDataOject, $iKeyState, $iPoint, $piEffect + + Local $sDirText = "" + + Local $tPoint = DllStructCreate($tagPoint) + $tPoint.X = _WinAPI_LoDWord($iPoint) + $tPoint.Y = _WinAPI_HiDWord($iPoint) + + Local $pData = DllStructGetData(DllStructCreate("ptr", Ptr($pThis + $__g_iTargetObjDataOffset)), 1) + Local $tData = DllStructCreate($tagTargetObjIntData, $pData) + $tData.bAcceptDrop = False + $tData.pDataObject = $pDataOject + + Local $oDataObject = ObjCreateInterface($pDataOject, $sIID_IDataObject, $tagIDataObject) + ;Addref to counteract the automatic release() when $oDataObject falls out of scope. + $oDataObject.AddRef() + + ;Accept only if dataobject contains a HDrop. + Local $pIEnumFmtEtc + $oDataObject.EnumFormatEtc($DATADIR_GET, $pIEnumFmtEtc) + Local $oIEnumFmtEtc = ObjCreateInterface($pIEnumFmtEtc, $sIID_IEnumFORMATETC, $tagIEnumFORMATETC) + Local $tFormatEtc = DllStructCreate($tagFORMATETC) + Local $pFmtEtc = DllStructGetPtr($tFormatEtc), $iFetched + $oIEnumFmtEtc.Reset() + While $oIEnumFmtEtc.Next(1, $pFmtEtc, $iFetched) = $S_OK +;~ ConsoleWrite(Hex($tFormatEtc.cfFormat) & " " & _ClipBoard_GetFormatName($tFormatEtc.cfFormat) & @CRLF) + If $tFormatEtc.cfFormat = $CF_HDROP Then + $tData.bAcceptDrop = True + ExitLoop + EndIf + WEnd + + Switch _WinAPI_GetClassName($tData.hTarget) + Case $WC_LISTVIEW + ; + Case $WC_TREEVIEW + $hTreeOrig = _GUICtrlTreeView_GetSelection($tData.hTarget) + Case Else + $tData.bAcceptDrop = False + EndSwitch + + __DoDropResponse($tData, $iKeyState, $tPoint, $piEffect, $sDirText) + + Local $oIDropTgtHelper = ObjCreateInterface($tData.pIDropTgtHelper, $sIID_IDropTargetHelper, $tagIDropTargetHelper) + $oIDropTgtHelper.AddRef() + + $oIDropTgtHelper.DragEnter($tData.hTarget, $pDataOject, $tPoint, $piEffect) + + Return $S_OK +EndFunc ;==>__Mthd_DragEnter + +Func __Mthd_DragOver($pThis, $iKeyState, $iPoint, $piEffect) + + #forceref $pThis, $iKeyState, $iPoint, $piEffect + + Local $sDirText = "" + + Local $tPoint = DllStructCreate($tagPoint) + $tPoint.X = _WinAPI_LoDWord($iPoint) + $tPoint.Y = _WinAPI_HiDWord($iPoint) + + Local $pData = DllStructGetData(DllStructCreate("ptr", Ptr($pThis + $__g_iTargetObjDataOffset)), 1) + Local $tData = DllStructCreate($tagTargetObjIntData, $pData) + + _WinAPI_ScreenToClient($tData.hTarget, $tPoint) + + Switch _WinAPI_GetClassName($tData.hTarget) + Case $WC_LISTVIEW + Local $aListItem = _GUICtrlListView_HitTest($tData.hTarget, $tPoint.X, $tPoint.Y) + Local $sItemText = _GUICtrlListView_GetItemText($tData.hTarget, $aListItem[0]) + Local $sDirPath = __TreeListExplorer_GetPath(1) & $sItemText + If StringInStr(FileGetAttrib($sDirPath), "D") Then + $sDirText = $sItemText + Else + ; get the currently selected path + $sDirPath = __TreeListExplorer_GetPath(1) + ; obtain folder name only for drag tooltip + Local $aPath = _StringBetween($sDirPath, "\", "\") + $sDirText = $aPath[UBound($aPath) - 1] + EndIf + ; handle case when cursor is over ListView but not on item; need to show current directory as drop dir + If $sDirText = "" Then + ; get the currently selected path + $sDirPath = __TreeListExplorer_GetPath(1) + ; obtain folder name only for drag tooltip + Local $aPath = _StringBetween($sDirPath, "\", "\") + $sDirText = $aPath[UBound($aPath) - 1] + EndIf + ;Local $sDirText = _GUICtrlListView_GetItemText($tData.hTarget, _GUICtrlListView_GetHotItem($tData.hTarget), 0) + ;$aListItem[0] + If $aListItem[0] >= 0 Then + ; bring focus to listview to show hot item (needed for listview to listview drag) + _WinAPI_SetFocus($tData.hTarget) + _GUICtrlListView_SetHotItem($tData.hTarget, $aListItem[0]) + EndIf + Case $WC_TREEVIEW + ;Local $tMPos = _WinAPI_GetMousePos(True, $tData.hTarget) + ;Local $tMPos = _WinAPI_GetMousePos() + Local $hTreeItem = _GUICtrlTreeView_HitTestItem($tData.hTarget, $tPoint.X, $tPoint.Y) + $sDirText = _GUICtrlTreeView_GetText($tData.hTarget, $hTreeItem) + If $hTreeItem <> 0 Then + ; bring focus to treeview to properly show DROPHILITE + _WinAPI_SetFocus($tData.hTarget) + _GUICtrlTreeView_SelectItem($tData.hTarget, $hTreeItem) + _GUICtrlTreeView_SetState($tData.hTarget, $hTreeOrig, $TVIS_SELECTED, True) + EndIf + Case Else + $sDirText = "" + EndSwitch + + __DoDropResponse($tData, $iKeyState, $tPoint, $piEffect, $sDirText) + + Local $oIDropTgtHelper = ObjCreateInterface($tData.pIDropTgtHelper, $sIID_IDropTargetHelper, $tagIDropTargetHelper) + $oIDropTgtHelper.AddRef() + $oIDropTgtHelper.DragOver($tPoint, $piEffect) + + Return $S_OK +EndFunc ;==>__Mthd_DragOver + +Func __Mthd_DragLeave($pThis) + #forceref $pThis + Local $pData = DllStructGetData(DllStructCreate("ptr", Ptr($pThis + $__g_iTargetObjDataOffset)), 1) + Local $tData = DllStructCreate($tagTargetObjIntData, $pData) + + __SetDropDescription($tData.pDataObject, $DROPIMAGE_INVALID) + + Local $oIDropTgtHelper = ObjCreateInterface($tData.pIDropTgtHelper, $sIID_IDropTargetHelper, $tagIDropTargetHelper) + $oIDropTgtHelper.AddRef() + $oIDropTgtHelper.DragLeave() + + Switch _WinAPI_GetClassName($tData.hTarget) + Case $WC_LISTVIEW + ;_GUICtrlListView_SetInsertMark($tData.hTarget, -1) + Case $WC_TREEVIEW + ; restore original treeview selection if cursor leaves treeview + _GUICtrlTreeView_SelectItem($tData.hTarget, $hTreeOrig) + EndSwitch + + $tData.bAcceptDrop = False + $tData.pDataObject = 0 + + Return $S_OK +EndFunc ;==>__Mthd_DragLeave + +Func __Mthd_Drop($pThis, $pDataOject, $iKeyState, $iPoint, $piEffect) + #forceref $pThis, $iKeyState, $iPoint, $piEffect + + Local $sDirText = "" + + Local $tPoint = DllStructCreate($tagPoint) + $tPoint.X = _WinAPI_LoDWord($iPoint) + $tPoint.Y = _WinAPI_HiDWord($iPoint) + + Local $pData = DllStructGetData(DllStructCreate("ptr", Ptr($pThis + $__g_iTargetObjDataOffset)), 1) + Local $tData = DllStructCreate($tagTargetObjIntData, $pData) + + Local $vItem = __DoDropResponse($tData, $iKeyState, $tPoint, $piEffect, $sDirText) + If @extended Then $vItem += 1 + + Local $oIDropTgtHelper = ObjCreateInterface($tData.pIDropTgtHelper, $sIID_IDropTargetHelper, $tagIDropTargetHelper) + $oIDropTgtHelper.AddRef() + $oIDropTgtHelper.Drop($pDataOject, $tPoint, $piEffect) + + Local $tEffect = DllStructCreate("dword iEffect", $piEffect) + If $tEffect.iEffect <> $DROPEFFECT_NONE Then + + Local $tFormatEtc = DllStructCreate($tagFORMATETC) + $tFormatEtc.cfFormat = $CF_HDROP + $tFormatEtc.iIndex = -1 + $tFormatEtc.tymed = $TYMED_HGLOBAL + + Local $oDataObject = ObjCreateInterface($pDataOject, $sIID_IDataObject, $tagIDataObject) + Local $tStgMedium = DllStructCreate($tagSTGMEDIUM) + $oDataObject.AddRef() + $oDataObject.GetData($tFormatEtc, $tStgMedium) + + Local $asFilenames = _WinAPI_DragQueryFileEx($tStgMedium.handle) + + Switch _WinAPI_GetClassName($tData.hTarget) + Case $WC_LISTVIEW + For $i = 1 To $asFilenames[0] + ;_GUICtrlListView_InsertItem($tData.hTarget, $asFilenames[$i], $vItem) + $vItem += 1 + Next + ;_GUICtrlListView_SetInsertMark($tData.hTarget, -1) + + Case $WC_TREEVIEW + Local $hInsAfter = _GUICtrlTreeView_GetPrev($tData.hTarget, $vItem) + If Not $hInsAfter Then $hInsAfter = $TVI_FIRST + For $i = 1 To $asFilenames[0] + ;$hInsAfter = _GUICtrlTreeView_InsertItem($tData.hTarget, $asFilenames[$i], 0, $hInsAfter) + Next + ;_GUICtrlTreeView_SetInsertMark($tData.hTarget, 0) + EndSwitch + EndIf + + ;__SetPerformedDropEffect($pDataOject, $piEffect) + + $tData.bAcceptDrop = False + $tData.pDataObject = 0 + + Return $S_OK +EndFunc ;==>__Mthd_Drop + +Func __DoInsertMark($hTarget, $tPoint) + Return +EndFunc + +Func __DoInsertMark_orig($hTarget, $tPoint) + Local $vItem = -1, $bAfter = False + _WinAPI_ScreenToClient($hTarget, $tPoint) + + Switch _WinAPI_GetClassName($hTarget) + Case $WC_LISTVIEW + Local $tLVINSERTMARK = DllStructCreate($tagLVINSERTMARK) + $tLVINSERTMARK.Size = DllStructGetSize($tLVINSERTMARK) + If _SendMessage($hTarget, $LVM_INSERTMARKHITTEST, $tPoint, $tLVINSERTMARK, 0, "struct*", "struct*") Then + If _SendMessage($hTarget, $LVM_SETINSERTMARK, 0, $tLVINSERTMARK, 0, "wparam", "struct*") Then $vItem = $tLVINSERTMARK.Item + $bAfter = BitAND($tLVINSERTMARK.Flags, $LVIM_AFTER) + EndIf + + Case $WC_TREEVIEW + Local $tTVHITTESTINFO = DllStructCreate($tagTVHITTESTINFO) + $tTVHITTESTINFO.X = $tPoint.X + $tTVHITTESTINFO.Y = $tPoint.Y + If _SendMessage($hTarget, $TVM_HITTEST, $tPoint, $tTVHITTESTINFO, 0, "struct*", "struct*") Then + If _SendMessage($hTarget, $TVM_SETINSERTMARK, 0, $tTVHITTESTINFO.Item, 0, "wparam", "handle") Then $vItem = $tTVHITTESTINFO.Item + EndIf + + EndSwitch + + Return SetExtended($bAfter, $vItem) +EndFunc + +Func __SetDropDescription($pDataObject, $iType, $sMessage = "", $sInsert = "") + Local $tFormatEtc = DllStructCreate($tagFORMATETC) + $tFormatEtc.cfFormat = _ClipBoard_RegisterFormat($CFSTR_DROPDESCRIPTION) + $tFormatEtc.ptd = 0 + $tFormatEtc.aspect = $DVASPECT_CONTENT + $tFormatEtc.index = -1 + $tFormatEtc.tymed = $TYMED_HGLOBAL + + Local $tDropDesc = DllStructCreate($tagDROPDESCRIPTION) + Local $hGblMem = _MemGlobalAlloc(DllStructGetSize($tDropDesc), $GPTR) + Local $pDropDesc = _MemGlobalLock($hGblMem) + $tDropDesc = DllStructCreate($tagDROPDESCRIPTION, $pDropDesc) + $tDropDesc.iType = $iType + $tDropDesc.sMessage = $sMessage + $tDropDesc.sInsert = $sInsert + _MemGlobalUnlock($hGblMem) + + Local $tStgMedium = DllStructCreate($tagSTGMEDIUM) + $tStgMedium.tymed = $TYMED_HGLOBAL + $tStgMedium.handle = $hGblMem + $tStgMedium.pUnkForRelease = 0 + + Local $oDataObj = ObjCreateInterface($pDataObject, $sIID_IDataObject, $tagIDataObject) + $oDataObj.AddRef() + $oDataObj.SetData($tFormatEtc, $tStgMedium, 1) +EndFunc + +Func __DoDropResponse($tData, $iKeyState, $tPoint, $piEffect, $sDirText) + + #forceref $tData, $iKeyState, $tPoint, $piEffect + + Local $vItem, $bAfter + Local $iRetEffect = $DROPEFFECT_NONE + Local $tEffect = DllStructCreate("dword iEffect", $piEffect) + + ;Only Accept copy ops (will expand this at some point!) + + If $tData.bAcceptDrop Then + If BitAND($tEffect.iEffect, $DROPEFFECT_MOVE) Then $iRetEffect = $DROPEFFECT_MOVE + If BitAND($tEffect.iEffect, $DROPEFFECT_COPY) Then + If BitAND($iKeyState, $MK_CONTROL) Or $iRetEffect = $DROPEFFECT_NONE Then + $iRetEffect = $DROPEFFECT_COPY + EndIf + EndIf + If BitAND($tEffect.iEffect, $DROPEFFECT_LINK) Then + If BitAND($iKeyState, $MK_ALT) Or $iRetEffect = $DROPEFFECT_NONE Then + $iRetEffect = $DROPEFFECT_LINK + EndIf + EndIf + EndIf + + $tEffect.iEffect = $iRetEffect + If $tEffect.iEffect <> $DROPEFFECT_NONE Then + ;$vItem = __DoInsertMark($tData.hTarget, $tPoint) + $bAfter = @extended + Else + Switch _WinAPI_GetClassName($tData.hTarget) + Case $WC_LISTVIEW + ;_GUICtrlListView_SetInsertMark($tData.hTarget, -1) + $vItem = -1 + + Case $WC_TREEVIEW + ;_GUICtrlTreeView_SetInsertMark($tData.hTarget, 0) + $vItem = 0 + + EndSwitch + EndIf + + Switch $tEffect.iEffect + Case $DROPEFFECT_NONE + __SetDropDescription($tData.pDataObject, $DROPIMAGE_NONE, "No Op %1", $sDirText) + + Case $DROPEFFECT_LINK + __SetDropDescription($tData.pDataObject, $DROPIMAGE_LINK, "Link to %1", $sDirText) + + Case $DROPEFFECT_COPY + __SetDropDescription($tData.pDataObject, $DROPIMAGE_COPY, "Copy to %1", $sDirText) + + Case $DROPEFFECT_MOVE + __SetDropDescription($tData.pDataObject, $DROPIMAGE_MOVE, "Move to %1", $sDirText) + + EndSwitch + + Return SetExtended($bAfter, $vItem) +EndFunc + +Func __SetPerformedDropEffect($pDataObject, $iDropEffect) + Local $tFormatEtc = DllStructCreate($tagFORMATETC) + $tFormatEtc.cfFormat = _ClipBoard_RegisterFormat($CFSTR_PERFORMEDDROPEFFECT) + $tFormatEtc.ptd = 0 + $tFormatEtc.aspect = $DVASPECT_CONTENT + $tFormatEtc.index = -1 + $tFormatEtc.tymed = $TYMED_HGLOBAL + + Local $hGblMem = _MemGlobalAlloc(4, $GPTR) + Local $pDropEffect = _MemGlobalLock($hGblMem) + Local $tDropEffect = DllStructCreate("dword iEffect", $pDropEffect) + $tDropEffect.iEffect = $iDropEffect + _MemGlobalUnlock($hGblMem) + + Local $tStgMedium = DllStructCreate($tagSTGMEDIUM) + $tStgMedium.tymed = $TYMED_HGLOBAL + $tStgMedium.handle = $hGblMem + $tStgMedium.pUnkForRelease = 0 + + Local $oDataObj = ObjCreateInterface($pDataObject, $sIID_IDataObject, $tagIDataObject) + $oDataObj.AddRef() + $oDataObj.SetData($tFormatEtc, $tStgMedium, 1) +EndFunc diff --git a/lib/InternalObject.au3 b/lib/InternalObject.au3 new file mode 100644 index 0000000..3e454ae --- /dev/null +++ b/lib/InternalObject.au3 @@ -0,0 +1,156 @@ +#include-once +#include "ProjectConstants.au3" +#include "IUnknown.au3" + +Global $__g_aObjects[1][20] +Global $__g_hMthd_QueryInterface, $__g_hMthd_AddRef, $__g_hMthd_Release +Global $__g_hMthd_QueryInterfaceThunk, $__g_hMthd_AddRefThunk, $__g_hMthd_ReleaseThunk + +Func PrepareInternalObject($iImplIfaces) + If Not $__g_hMthd_QueryInterface Then + $__g_hMthd_QueryInterface = DllCallbackRegister("__Mthd_QueryInterface", "long", "ptr;ptr;ptr") + $__g_hMthd_AddRef = DllCallbackRegister("__Mthd_AddRef", "long", "ptr") + $__g_hMthd_Release = DllCallbackRegister("__Mthd_Release", "long", "ptr") + $__g_hMthd_QueryInterfaceThunk = DllCallbackRegister("__Mthd_QueryInterfaceThunk", "long", "ptr;ptr;ptr") + $__g_hMthd_AddRefThunk = DllCallbackRegister("__Mthd_AddRefThunk", "long", "ptr") + $__g_hMthd_ReleaseThunk = DllCallbackRegister("__Mthd_ReleaseThunk", "long", "ptr") + EndIf + + Local $iObjectId = UBound($__g_aObjects) + ReDim $__g_aObjects[$iObjectId + 1][UBound($__g_aObjects, 2)] + $__g_aObjects[0][0] += 1 + + Local $tIUnknownVTab = DllStructCreate("ptr pFunc[3]") + $tIUnknownVTab.pFunc(1) = DllCallbackGetPtr($__g_hMthd_QueryInterface) + $tIUnknownVTab.pFunc(2) = DllCallbackGetPtr($__g_hMthd_AddRef) + $tIUnknownVTab.pFunc(3) = DllCallbackGetPtr($__g_hMthd_Release) + + Local $tagSupportedIIDs + For $i = 1 To $iImplIfaces + $tagSupportedIIDs &= "byte[16];" + Next + Local $tSupportedIIDs = DllStructCreate($tagSupportedIIDs) + _WinAPI_GUIDFromStringEx($sIID_IUnknown, DllStructGetPtr($tSupportedIIDs, 1)) + + Local $tagObject = StringFormat("align 4;int iImplIfaces;ptr pVTab[%d];int iRefCnt;" & _ + "ptr pSupportedIIDs;ptr pData", $iImplIfaces) + + Local $tObject = DllStructCreate($tagObject) + $tObject.iRefCnt = 1 + $tObject.iImplIfaces = $iImplIfaces + $tObject.pVTab(1) = DllStructGetPtr($tIUnknownVTab) + $tObject.pSupportedIIDs = DllStructGetPtr($tSupportedIIDs) + + Local $pObject = DllStructGetPtr($tObject, "pVTab") + + $__g_aObjects[$iObjectId][0] = $pObject + $__g_aObjects[$iObjectId][1] = $tObject + $__g_aObjects[$iObjectId][2] = $tSupportedIIDs + $__g_aObjects[$iObjectId][3] = $tIUnknownVTab + + Return $iObjectId +EndFunc + +Func DestroyInternalObject($pObject) + If (Not $pObject) Or (Not IsPtr($pObject)) Then Return SetError($ERROR_INVALID_PARAMETER, 0, False) + + For $i = 0 To UBound($__g_aObjects) - 1 + If $__g_aObjects[$i][0] = $pObject Then ExitLoop + Next + If $i = UBound($__g_aObjects) Then Return SetError($ERROR_INVALID_PARAMETER, 0, False) + + For $j = 0 To UBound($__g_aObjects, 2) - 1 + $__g_aObjects[$i][$j] = 0 + Next + $__g_aObjects[0][0] -= 1 + + If Not $__g_aObjects[0][0] Then + DllCallbackFree($__g_hMthd_QueryInterface) + DllCallbackFree($__g_hMthd_AddRef) + DllCallbackFree($__g_hMthd_Release) + DllCallbackFree($__g_hMthd_QueryInterfaceThunk) + DllCallbackFree($__g_hMthd_AddRefThunk) + DllCallbackFree($__g_hMthd_ReleaseThunk) + + $__g_hMthd_QueryInterface = 0 + $__g_hMthd_AddRef = 0 + $__g_hMthd_Release = 0 + $__g_hMthd_QueryInterfaceThunk = 0 + $__g_hMthd_AddRefThunk = 0 + $__g_hMthd_ReleaseThunk = 0 + EndIf +EndFunc ;==>DestroyDropSource + + +#Region Internal IUnknown Methods + +Func __Mthd_QueryInterface($pThis, $pIID, $ppObj) +;~ ConsoleWrite("QI: " & _WinAPI_StringFromGUID($pIID) & @CRLF) + + Local $hResult = $S_OK + + Local $iIIDCnt = DllStructGetData(DllStructCreate("int", Ptr($pThis - 4)), 1) + Local $tThis = DllStructCreate(StringFormat("align 4;ptr pVTab[%d];int iRefCnt;ptr pSupportedIIDs", $iIIDCnt), $pThis) + Local $pTestIID = $tThis.pSupportedIIDs + + If Not $ppObj Then + $hResult = $E_POINTER + Else + For $i = 0 To $iIIDCnt - 1 + If _WinAPI_StringFromGUID($pIID) = _WinAPI_StringFromGUID(Ptr($pTestIID)) Then + DllStructSetData(DllStructCreate("ptr", $ppObj), 1, Ptr($pThis + $i * $PTR_LEN)) +;~ ConsoleWrite("FOUND: " & $pThis + $i * $PTR_LEN & @CRLF) + + __Mthd_AddRef($pThis) + ExitLoop + EndIf + $pTestIID += 16 + Next + If $i = $iIIDCnt Then $hResult = $E_NOINTERFACE + + EndIf + + Return $hResult +EndFunc ;==>__Mthd_QueryInterface + +Func __Mthd_AddRef($pThis) + + Local $iImplIfaces = DllStructGetData(DllStructCreate("int", Ptr($pThis - 4)), 1) + Local $tThis = DllStructCreate(StringFormat("align 4;ptr pVTab[%d];int iRefCnt", $iImplIfaces), $pThis) + $tThis.iRefCnt += 1 + + Return $tThis.iRefCnt +EndFunc ;==>__Mthd_AddRef + +Func __Mthd_Release($pThis) + Local $iImplIfaces = DllStructGetData(DllStructCreate("int", Ptr($pThis - 4)), 1) + Local $tThis = DllStructCreate(StringFormat("align 4;ptr pVTab[%d];int iRefCnt", $iImplIfaces), $pThis) + $tThis.iRefCnt -= 1 + Return $tThis.iRefCnt +EndFunc ;==>__Mthd_Release + +Func __Mthd_QueryInterfaceThunk($pThis, $pIID, $ppObj) + Local $hResult = $S_OK + Local $tIID = DllStructCreate($tagGUID, $pIID) + If _WinAPI_StringFromGUID($tIID) = $sIID_IUnknown Then + DllStructSetData(DllStructCreate("ptr", $ppObj), 1, $pThis) + Else + $pThis = Ptr($pThis - $PTR_LEN) + Local $pVTab = DllStructGetData(DllStructCreate("ptr", $pThis), 1) + Local $pFunc = DllStructGetData(DllStructCreate("ptr", $pVTab), 1) + Local $aCall = DllCallAddress("long", $pFunc, "ptr", $pThis, "ptr", $pIID, "ptr", $ppObj) + $hResult = $aCall[0] + EndIf + Return $hResult +EndFunc ;==>__Mthd_QueryInterfaceThunk + +Func __Mthd_AddRefThunk($pThis) + $pThis = Ptr($pThis - $PTR_LEN) + Return _AddRef($pThis) +EndFunc ;==>__Mthd_AddRefThunk + +Func __Mthd_ReleaseThunk($pThis) + $pThis = Ptr($pThis - $PTR_LEN) + Return _Release($pThis) +EndFunc ;==>__Mthd_ReleaseThunk +#EndRegion Internal IUnknown Methods diff --git a/lib/ProjectConstants.au3 b/lib/ProjectConstants.au3 index c1c0020..79e6fb8 100644 --- a/lib/ProjectConstants.au3 +++ b/lib/ProjectConstants.au3 @@ -5,15 +5,45 @@ #include #include #include +#include +Global Const $S_FALSE = 1 Global Const $PTR_LEN = @AutoItX64 ? 8 : 4 +Global Const $sCLSID_DragDropHelper = "{4657278A-411B-11D2-839A-00C04FD918D0}" Global Const $sIID_IUnknown = "{00000000-0000-0000-C000-000000000046}" Global Const $sIID_IShellFolder = "{000214E6-0000-0000-C000-000000000046}" Global Const $sIID_IDataObject = "{0000010e-0000-0000-C000-000000000046}" Global Const $sIID_IDropSource = "{00000121-0000-0000-C000-000000000046}" Global Const $sIID_IDropSourceNotify = "{0000012B-0000-0000-C000-000000000046}" +Global Const $sIID_IEnumFORMATETC = "{00000103-0000-0000-C000-000000000046}" +Global Const $sIID_IDropTarget = "{00000122-0000-0000-C000-000000000046}" +Global Const $sIID_IDragSourceHelper = "{DE5BF786-477A-11D2-839D-00C04FD918D0}" +Global Const $sIID_IDragSourceHelper2 = "{83E07D0D-0C5F-4163-BF1A-60B274051E40}" +Global Const $sIID_IDropTargetHelper = "{4657278B-411B-11D2-839A-00C04FD918D0}" +Global Const $CLSCTX_INPROC_SERVER = 0x01 +Global Const $CLSCTX_INPROC_HANDLER = 0x2 +Global Const $CLSCTX_LOCAL_SERVER = 0x4 +Global Const $CLSCTX_REMOTE_SERVER = 0x10 +Global Const $CLSCTX_NO_CODE_DOWNLOAD = 0x400 +Global Const $CLSCTX_NO_CUSTOM_MARSHAL = 0x1000 +Global Const $CLSCTX_ENABLE_CODE_DOWNLOAD = 0x2000 +Global Const $CLSCTX_NO_FAILURE_LOG = 0x4000 +Global Const $CLSCTX_DISABLE_AAA = 0x8000 +Global Const $CLSCTX_ENABLE_AAA = 0x10000 +Global Const $CLSCTX_FROM_DEFAULT_CONTEXT = 0x20000 +Global Const $CLSCTX_ACTIVATE_X86_SERVER = 0x40000 +Global Const $CLSCTX_ACTIVATE_32_BIT_SERVER = $CLSCTX_ACTIVATE_X86_SERVER +Global Const $CLSCTX_ACTIVATE_64_BIT_SERVER = 0x80000 +Global Const $CLSCTX_ENABLE_CLOAKING = 0x100000 +Global Const $CLSCTX_APPCONTAINER = 0x400000 +Global Const $CLSCTX_ACTIVATE_AAA_AS_IU = 0x800000 +Global Const $CLSCTX_ACTIVATE_ARM32_SERVER = 0x2000000 +Global Const $CLSCTX_ALLOW_LOWER_TRUST_REGISTRATION = 0x4000000 +Global Const $CLSCTX_ALL = BitOR($CLSCTX_INPROC_SERVER, $CLSCTX_INPROC_HANDLER, $CLSCTX_LOCAL_SERVER, $CLSCTX_REMOTE_SERVER) + +Global Const $CFSTR_PERFORMEDDROPEFFECT = "Performed DropEffect" Global Const $DRAGDROP_S_DROP = 0x00040100 Global Const $DRAGDROP_S_CANCEL = 0x00040101 @@ -32,17 +62,99 @@ Global Const $MK_RBUTTON = 0x0002 Global Const $MK_SHIFT = 0x0004 Global Const $MK_CONTROL = 0x0008 Global Const $MK_MBUTTON = 0x0010 +Global Const $MK_ALT = 0x0020 Global Const $MK_XBUTTON1 = 0x0020 Global Const $MK_XBUTTON2 = 0x0040 +Global Const $TYMED_HGLOBAL = 1 +Global Const $TYMED_FILE = 2 +Global Const $TYMED_ISTREAM = 4 +Global Const $TYMED_ISTORAGE = 8 +Global Const $TYMED_GDI = 16 +Global Const $TYMED_MFPICT = 32 +Global Const $TYMED_ENHMF = 64 +Global Const $TYMED_NULL = 0 + +Global Const $DVASPECT_CONTENT = 1 +Global Const $DVASPECT_THUMBNAIL = 2 +Global Const $DVASPECT_ICON = 4 +Global Const $DVASPECT_DOCPRINT = 8 + +Global Const $DV_E_FORMATETC = 0x80040064 +Global Const $DV_E_DVTARGETDEVICE = 0x80040065 +Global Const $DV_E_STGMEDIUM = 0x80040066 +Global Const $DV_E_STATDATA = 0x80040067 +Global Const $DV_E_LINDEX = 0x80040068 +Global Const $DV_E_TYMED = 0x80040069 +Global Const $DV_E_CLIPFORMAT = 0x8004006A +Global Const $DV_E_DVASPECT = 0x8004006B +Global Const $DV_E_DVTARGETDEVICE_SIZE = 0x8004006C +Global Const $DV_E_NOIVIEWOBJECT = 0x8004006D + +Global Const $DATADIR_GET = 1 +Global Const $DATADIR_SET = 2 + +Global Const $CFSTR_DROPDESCRIPTION = "DropDescription" + +Global Const $DROPIMAGE_INVALID = -1 +Global Const $DROPIMAGE_NONE = 0 +Global Const $DROPIMAGE_COPY = 1 +Global Const $DROPIMAGE_MOVE = 2 +Global Const $DROPIMAGE_LINK = 4 +Global Const $DROPIMAGE_LABEL = 6 +Global Const $DROPIMAGE_WARNING = 7 +Global Const $DROPIMAGE_NOIMAGE = 8 + +Global Const $DSH_ALLOWDROPDESCRIPTIONTEXT = 0x0001 + +Global Const $tagFORMATETC = "struct;word cfFormat;ptr ptd;dword aspect;long index;dword tymed;endstruct" +Global Const $tagSTGMEDIUM = "struct;dword tymed;ptr handle;ptr pUnkForRelease;endstruct" +Global Const $tagDROPFILES = "struct;dword pFiles;long pt[2];bool fNC;bool fWide;endstruct" +Global Const $tagSHDRAGIMAGE = "struct;long aiDragImageSize[2];long aiOffset[2];handle hDragImage;dword iColorKey;endstruct" +Global Const $tagDROPDESCRIPTION = "struct;int iType;wchar sMessage[260];wchar sInsert[260];endstruct" +Global Const $tagSHFILEINFOW = "struct;handle hIcon;int iIcon;dword iAttributes;wchar sDisplayName[260];wchar sTypeName[80];endstruct;" + +;~ "ParseDisplayName hresult(hwnd; ptr; wstr; ulong*; ptr*; ulong*);" & _ + Global Const $tagIShellFolder = _ - "ParseDisplayName hresult(hwnd; ptr*; wstr; ulong*; ptr*; ulong*);" & _ + "ParseDisplayName hresult(hwnd; ptr; wstr; ulong*; ptr*; ulong*);" & _ "EnumObjects hresult(hwnd; ulong; ptr*);" & _ "BindToObject hresult(ptr; ptr*; struct*; ptr*);" & _ "BindToStorage hresult(ptr; ptr*; struct*; ptr*);" & _ "CompareIDs hresult(lparam; ptr; ptr);" & _ "CreateViewObject hresult(hwnd; struct*; ptr*);" & _ "GetAttributesOf hresult(uint; ptr; ulong*);" & _ - "GetUIObjectOf hresult(hwnd; uint; ptr*; struct*; uint*; ptr*);" & _ + "GetUIObjectOf hresult(hwnd; uint; ptr; struct*; uint*; ptr*);" & _ "GetDisplayNameOf hresult(ptr; ulong; ptr*);" & _ - "SetNameOf hresult(hwnd; ptr; wstr; ulong; ptr*);" \ No newline at end of file + "SetNameOf hresult(hwnd; ptr; wstr; ulong; ptr*);" + +Global Const $tagIDataObject = _ + "GetData hresult(struct*; struct*);" & _ + "GetDataHere hresult(struct*; struct*);" & _ + "QueryGetData hresult(struct*);" & _ + "GetCanonicalFormatEtc hresult(struct*; struct*);" & _ + "SetData hresult(struct*; struct*; bool);" & _ + "EnumFormatEtc hresult(dword; ptr*);" & _ + "DAdvise hresult(struct*; dword; ptr*; dword*);" & _ + "DUnadvise hresult(dword);" & _ + "EnumDAdvise hresult(ptr*);" + +Global Const $tagIEnumFORMATETC = _ + "Next hresult(ulong; ptr; ulong*);" & _ + "Skip hresult(ulong);" & _ + "Reset hresult();" & _ + "Clone hresult(ptr*);" + +Global Const $tagIDragSourceHelper = _ + "InitializeFromBitmap hresult(struct*; ptr);" & _ + "InitializeFromWindow hresult(hwnd; ptr; ptr);" + +Global Const $tagIDragSourceHelper2 = $tagIDragSourceHelper & _ + "SetFlags hresult(dword);" + +Global Const $tagIDropTargetHelper = _ + "DragEnter hresult(hwnd; ptr; struct*; dword);" & _ + "DragLeave hresult();" & _ + "DragOver hresult(struct*; dword);" & _ + "Drop hresult(ptr; struct*; dword);" & _ + "Show hresult(bool);" diff --git a/src/desktop.ini b/src/desktop.ini new file mode 100644 index 0000000..d1ead95 --- /dev/null +++ b/src/desktop.ini @@ -0,0 +1,2 @@ +[LocalizedFileNames] +Command Prompt.lnk=@%SystemRoot%\system32\shell32.dll,-22022 diff --git a/src/main.au3 b/src/main.au3 index 4b73b85..6d18f93 100644 --- a/src/main.au3 +++ b/src/main.au3 @@ -15,7 +15,8 @@ #include "../lib/History.au3" #include "../lib/TreeListExplorer.au3" #include "../lib/ProjectConstants.au3" -#include "../lib/IUnknown.au3" +#include "../lib/DropSourceObject.au3" +#include "../lib/DropTargetObject.au3" ; CREDITS: ; Kanashius TreeListExplorer UDF @@ -43,6 +44,7 @@ $iDPI = ApplyDPI() #include "../lib/ModernMenuRaw.au3" Opt("GUIOnEventMode", 1) +Opt("GUICloseOnESC", 0) Global $hTLESystem, $iFrame_A, $hSeparatorFrame, $aWinSize2, $idInputPath, $g_hInputPath, $g_hStatus, $idTreeView Global $g_hGUI, $g_hChild, $g_hHeader, $g_hListview, $idListview, $iHeaderHeight, $hParentFrame, $g_iIconWidth, $g_hTreeView @@ -51,6 +53,7 @@ Global $idPropertiesItem, $idPropertiesLV, $sCurrentPath Global $hListImgList, $iListDragIndex, $aDragSource, $sTargetCtrl, $hTreeItemOrig, $hIcon Global $sBack, $sForward, $sUpLevel, $sRefresh Global $bDragTreeList = False, $sDragSrc, $sTreeDragItem, $sListDragItems, $bDragToolActive = False +Global $pLVDropTarget, $pTVDropTarget Global $bPathInputChanged = False, $bLoadStatus = False, $bCursorOverride = False Global $idExitItem, $idAboutItem Global $hCursor, $hProc @@ -64,12 +67,6 @@ Global $aPosTip, $iOldaPos0, $iOldaPos1 ; force light mode ;$isDarkMode = False -Global $__g_aObjects[1][20] -Global $__g_hMthd_QueryInterface, $__g_hMthd_AddRef, $__g_hMthd_Release -Global $__g_hMthd_QueryInterfaceThunk, $__g_hMthd_AddRefThunk, $__g_hMthd_ReleaseThunk -Global $__g_hMthd_QueryContinueDrag, $__g_hMthd_GiveFeedback -Global $__g_hMthd_DragEnterTarget, $__g_hMthd_DragLeaveTarget - Global $hKernel32 = DllOpen('kernel32.dll') Global $hGdi32 = DllOpen('gdi32.dll') Global $hUser32 = DllOpen('user32.dll') @@ -298,6 +295,13 @@ Func _FilesAu3() $g_hListview = GUICtrlGetHandle($idListview) + ;Create Target for our GUI & register. + $pLVDropTarget = CreateDropTarget($g_hListview) + RegisterDragDrop($g_hListview, $pLVDropTarget) + + $pTVDropTarget = CreateDropTarget($g_hTreeView) + RegisterDragDrop($g_hTreeView, $pTVDropTarget) + _GUIToolTip_AddTool($hToolTip1, $g_hGUI, "", $g_hListview) ; right align Size column @@ -1090,6 +1094,10 @@ Func _CleanExit() _GUICtrlHeader_Destroy($g_hHeader) _GUIToolTip_Destroy($hToolTip1) _GUIToolTip_Destroy($hToolTip2) + RevokeDragDrop($g_hListview) + DestroyDropTarget($pLVDropTarget) + RevokeDragDrop($g_hTreeView) + DestroyDropTarget($pTVDropTarget) GUIDelete($g_hGUI) _ClearDarkSizebox() @@ -1606,7 +1614,7 @@ EndFunc ;==>WM_MOVE Func ApplyDPI() ; apply System DPI awareness and calculate factor ; Returns DPI scaling factor (1.0 = 100%), defaults to 1.0 on error - _WinAPI_SetThreadDpiAwarenessContext($DPI_AWARENESS_CONTEXT_SYSTEM_AWARE) + _WinAPI_SetProcessDpiAwarenessContext($DPI_AWARENESS_CONTEXT_SYSTEM_AWARE) If @error Then Return 1 Local $iDPI2 = Round(_WinAPI_GetDpiForSystem() / 96, 2) @@ -1615,12 +1623,12 @@ Func ApplyDPI() Return $iDPI2 EndFunc ;==>ApplyDPI -Func _WinAPI_SetThreadDpiAwarenessContext($DPI_AWARENESS_CONTEXT_value) ; UEZ - Local $aResult = DllCall('user32.dll', "uint", "SetThreadDpiAwarenessContext", @AutoItX64 ? "int64" : "int", $DPI_AWARENESS_CONTEXT_value) ; requires Win10 v1703+ / Windows Server 2016+ - If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0) - If Not $aResult[0] Then Return SetError(2, @extended, 0) - Return $aResult[0] -EndFunc ;==>_WinAPI_SetThreadDpiAwarenessContext +Func _WinAPI_SetProcessDpiAwarenessContext($DPI_AWARENESS_CONTEXT_value) ; UEZ + Local $aResult = DllCall("user32.dll", "bool", "SetProcessDpiAwarenessContext", @AutoItX64 ? "int64" : "int", $DPI_AWARENESS_CONTEXT_value) ;requires Win10 v1703+ / Windows Server 2016+ + If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0) + If Not $aResult[0] Then Return SetError(2, @extended, 0) + Return $aResult[0] +EndFunc ;==>_WinAPI_SetProcessDpiAwarenessContext Func _WinAPI_GetDpiForSystem() ; UEZ Local $aResult = DllCall('user32.dll', "uint", "GetDpiForSystem") ; requires Win10 v1607+ / no server support @@ -2115,11 +2123,8 @@ Func _SHDoDragDrop($pDataObj, $pDropSource, $iOKEffects) ;Local $aCall = DllCall($hShell32, "long", "SHDoDragDrop", "hwnd", $g_hGUI, "ptr", $pDataObj, "ptr", $pDropSource, "dword", $iOKEffects, "ptr*", 0) Local $aCall = DllCall($hShell32, "long", "SHDoDragDrop", "hwnd", Null, "ptr", $pDataObj, "ptr", Null, "dword", $iOKEffects, "ptr*", 0) - For $i = 0 To UBound($aCall) - 1 - ConsoleWrite("$aCall[" & $i & "] : " & Hex($aCall[$i], 1) & @CRLF) - Next - If Hex($aCall[5], 1) = $DROPEFFECT_COPY Then ConsoleWrite("copy yay" & @CRLF) + If Hex($aCall[5], 1) = $DROPEFFECT_COPY Then ConsoleWrite("copy success" & @CRLF) If @error Then Return SetError(@error, @extended, $aCall) Return SetError($aCall[0], 0, $aCall[4]) @@ -2243,25 +2248,27 @@ EndFunc Func GetDataObjectOfFile($hWnd, $sPath) ;Get the path as an idList. This is allocated memory that we should free later on. - Local $aCall = DllCall($hShell32, "long", "SHParseDisplayName", "wstr", $sPath, "ptr", 0, "ptr*", 0, "ulong", 0, "ulong*", 0) + Local $aCall = DllCall("Shell32.dll", "long", "SHParseDisplayName", "wstr", $sPath, "ptr", 0, "ptr*", 0, "ulong", 0, "ulong*", 0) Local $iError = @error ? TranslateDllError() : $aCall[0] If $iError Then Return SetError($iError, 0, False) Local $pIdl = $aCall[3] ;From the idList, get two things: IShellFolder for the parent folder & the item's IDL relative to the parent folder. Local $tIID_IShellFolder = _WinAPI_GUIDFromString($sIID_IShellFolder) - $aCall = DllCall($hShell32, "long", "SHBindToParent", "ptr", $pIdl, "struct*", $tIID_IShellFolder, "ptr*", 0, "ptr*", 0) + $aCall = DllCall("Shell32.dll", "long", "SHBindToParent", "ptr", $pIdl, "struct*", $tIID_IShellFolder, "ptr*", 0, "ptr*", 0) $iError = @error ? TranslateDllError() : $aCall[0] If $iError Then Return SetError($iError, 0, False) Local $pShellFolder = $aCall[3] ;SHBindToParent does not allocate a new PID, so we're not responsible for freeing $pIdlChild. - Local $pIdlChild = $aCall[4] + Local $tpIdlChild = DllStructCreate("ptr") + DllStructSetData($tpIdlChild, 1, $aCall[4]) + Local $ppIdlChild = DllStructGetPtr($tpIdlChild) ;We have an interface tag for IShellFolder, so we can use ObjCreateInterface to "convert" it into an object datatype. ;$oShellFolder will automatically release when it goes out of scope, so we don't need to manually _Release($pShellFolder). Local $oShellFolder = ObjCreateInterface($pShellFolder, $sIID_IShellFolder, $tagIShellFolder) Local $pDataObject, $tIID_IDataObject = _WinAPI_GUIDFromString($sIID_IDataObject) - $iError = $oShellFolder.GetUIObjectOf($hWnd, 1, $pIdlChild, $tIID_IDataObject, 0, $pDataObject) + $iError = $oShellFolder.GetUIObjectOf($hWnd, 1, $ppIdlChild, $tIID_IDataObject, 0, $pDataObject) ;Free the IDL we initially created CoTaskMemFree($pIdl) @@ -2269,281 +2276,14 @@ Func GetDataObjectOfFile($hWnd, $sPath) Return SetError($iError, 0, Ptr($pDataObject)) EndFunc ;==>GetDataObjectOfFile -Func CreateDropSource() - If Not $__g_hMthd_QueryInterface Then - $__g_hMthd_QueryInterface = DllCallbackRegister("__Mthd_QueryInterface", "long", "ptr;ptr;ptr") - $__g_hMthd_AddRef = DllCallbackRegister("__Mthd_AddRef", "long", "ptr") - $__g_hMthd_Release = DllCallbackRegister("__Mthd_Release", "long", "ptr") - - $__g_hMthd_QueryInterfaceThunk = DllCallbackRegister("__Mthd_QueryInterfaceThunk", "long", "ptr;ptr;ptr") - $__g_hMthd_AddRefThunk = DllCallbackRegister("__Mthd_AddRefThunk", "long", "ptr") - $__g_hMthd_ReleaseThunk = DllCallbackRegister("__Mthd_ReleaseThunk", "long", "ptr") - EndIf - - If Not $__g_hMthd_QueryContinueDrag Then - $__g_hMthd_QueryContinueDrag = DllCallbackRegister("__Mthd_QueryContinueDrag", "long", "ptr;bool;dword") - $__g_hMthd_GiveFeedback = DllCallbackRegister("__Mthd_GiveFeedback", "long", "ptr;dword") - EndIf - - If Not $__g_hMthd_DragEnterTarget Then - $__g_hMthd_DragEnterTarget = DllCallbackRegister("__Mthd_DragEnterTarget", "long", "ptr;hwnd") - $__g_hMthd_DragLeaveTarget = DllCallbackRegister("__Mthd_DragLeaveTarget", "long", "ptr") - EndIf - - Local $iObjectId = UBound($__g_aObjects) - ReDim $__g_aObjects[$iObjectId + 1][UBound($__g_aObjects, 2)] - $__g_aObjects[0][0] += 1 - - Local $tUnknownVTab = DllStructCreate("ptr pFunc[3]") - $tUnknownVTab.pFunc(1) = DllCallbackGetPtr($__g_hMthd_QueryInterface) - $tUnknownVTab.pFunc(2) = DllCallbackGetPtr($__g_hMthd_AddRef) - $tUnknownVTab.pFunc(3) = DllCallbackGetPtr($__g_hMthd_Release) - - Local $tDropSrcVTab = DllStructCreate("ptr pFunc[5]") - $tDropSrcVTab.pFunc(1) = DllCallbackGetPtr($__g_hMthd_QueryInterfaceThunk) - $tDropSrcVTab.pFunc(2) = DllCallbackGetPtr($__g_hMthd_AddRefThunk) - $tDropSrcVTab.pFunc(3) = DllCallbackGetPtr($__g_hMthd_ReleaseThunk) - $tDropSrcVTab.pFunc(4) = DllCallbackGetPtr($__g_hMthd_QueryContinueDrag) - $tDropSrcVTab.pFunc(5) = DllCallbackGetPtr($__g_hMthd_GiveFeedback) - - Local $tDropSrcNotifyVTab = DllStructCreate("ptr pFunc[5]") - $tDropSrcNotifyVTab.pFunc(1) = DllCallbackGetPtr($__g_hMthd_QueryInterfaceThunk) - $tDropSrcNotifyVTab.pFunc(2) = DllCallbackGetPtr($__g_hMthd_AddRefThunk) - $tDropSrcNotifyVTab.pFunc(3) = DllCallbackGetPtr($__g_hMthd_ReleaseThunk) - $tDropSrcNotifyVTab.pFunc(4) = DllCallbackGetPtr($__g_hMthd_DragEnterTarget) - $tDropSrcNotifyVTab.pFunc(5) = DllCallbackGetPtr($__g_hMthd_DragLeaveTarget) - - Local $tagObject = "align 4;int iImplIfaces;ptr pVTab[3];int iRefCnt;" & _ - "byte IID_IUnknown[16];" & _ - "byte IID_IDropSource[16];" & _ - "byte IID_IDropSourceNotify[16];" & _ - "hwnd hTarget" - - Local $tObject = DllStructCreate($tagObject) - $tObject.pVTab(1) = DllStructGetPtr($tUnknownVTab) - $tObject.pVTab(2) = DllStructGetPtr($tDropSrcVTab) - $tObject.pVTab(3) = DllStructGetPtr($tDropSrcNotifyVTab) - - $tObject.iRefCnt = 1 - $tObject.iImplIfaces = 3 - _WinAPI_GUIDFromStringEx($sIID_IUnknown, DllStructGetPtr($tObject, "IID_IUnknown")) - _WinAPI_GUIDFromStringEx($sIID_IDropSource, DllStructGetPtr($tObject, "IID_IDropSource")) - _WinAPI_GUIDFromStringEx($sIID_IDropSourceNotify, DllStructGetPtr($tObject, "IID_IDropSourceNotify")) - - Local $pObject = DllStructGetPtr($tObject, "pVTab") - - $__g_aObjects[$iObjectId][0] = $pObject - $__g_aObjects[$iObjectId][1] = $tObject - $__g_aObjects[$iObjectId][2] = $tUnknownVTab - $__g_aObjects[$iObjectId][3] = $tDropSrcVTab - $__g_aObjects[$iObjectId][4] = $tDropSrcNotifyVTab - - Return $pObject -EndFunc ;==>CreateDropSource - -Func DestroyDropSource($pObject) - If (Not $pObject) Or (Not IsPtr($pObject)) Then Return SetError($ERROR_INVALID_PARAMETER, 0, False) - - For $i = 0 To UBound($__g_aObjects) - 1 - If $__g_aObjects[$i][0] = $pObject Then ExitLoop - Next - If $i = UBound($__g_aObjects) Then Return SetError($ERROR_INVALID_PARAMETER, 0, False) - - For $j = 0 To UBound($__g_aObjects, 2) - 1 - $__g_aObjects[$i][$j] = 0 - Next - $__g_aObjects[0][0] -= 1 - - If Not $__g_aObjects[0][0] Then - DllCallbackFree($__g_hMthd_QueryInterface) - DllCallbackFree($__g_hMthd_AddRef) - DllCallbackFree($__g_hMthd_Release) - DllCallbackFree($__g_hMthd_QueryInterfaceThunk) - DllCallbackFree($__g_hMthd_AddRefThunk) - DllCallbackFree($__g_hMthd_ReleaseThunk) - DllCallbackFree($__g_hMthd_QueryContinueDrag) - DllCallbackFree($__g_hMthd_GiveFeedback) - DllCallbackFree($__g_hMthd_DragEnterTarget) - DllCallbackFree($__g_hMthd_DragLeaveTarget) - - $__g_hMthd_QueryInterface = 0 - $__g_hMthd_AddRef = 0 - $__g_hMthd_Release = 0 - $__g_hMthd_QueryInterfaceThunk = 0 - $__g_hMthd_AddRefThunk = 0 - $__g_hMthd_ReleaseThunk = 0 - $__g_hMthd_QueryContinueDrag = 0 - $__g_hMthd_GiveFeedback = 0 - $__g_hMthd_DragEnterTarget = 0 - $__g_hMthd_DragLeaveTarget = 0 - EndIf -EndFunc ;==>DestroyDropSource - - -#Region Internal IUnknown Methods - -Func __Mthd_QueryInterface($pThis, $pIID, $ppObj) - Local $hResult = $S_OK - - Local $iIIDCnt = DllStructGetData(DllStructCreate("int", Ptr($pThis - 4)), 1) - Local $tThis = DllStructCreate(StringFormat("align 4;ptr pVTab[%d];int iRefCnt", $iIIDCnt), $pThis) - - Local $pTestIID = DllStructGetPtr($tThis, "iRefCnt") + 4 - If Not $ppObj Then - $hResult = $E_POINTER - Else - For $i = 0 To $iIIDCnt - 1 - If _WinAPI_StringFromGUID($pIID) = _WinAPI_StringFromGUID(Ptr($pTestIID)) Then - DllStructSetData(DllStructCreate("ptr", $ppObj), 1, Ptr($pThis + $i * $PTR_LEN)) - __Mthd_AddRef($pThis) - ExitLoop - EndIf - $pTestIID += 16 - Next - If $i = $iIIDCnt Then $hResult = $E_NOINTERFACE - - EndIf - Return $hResult -EndFunc ;==>__Mthd_QueryInterface - -Func __Mthd_AddRef($pThis) - Local $iImplIfaces = DllStructGetData(DllStructCreate("int", Ptr($pThis - 4)), 1) - Local $tThis = DllStructCreate(StringFormat("align 4;ptr pVTab[%d];int iRefCnt", $iImplIfaces), $pThis) - $tThis.iRefCnt += 1 - Return $tThis.iRefCnt -EndFunc ;==>__Mthd_AddRef - -Func __Mthd_Release($pThis) - Local $iImplIfaces = DllStructGetData(DllStructCreate("int", Ptr($pThis - 4)), 1) - Local $tThis = DllStructCreate(StringFormat("align 4;ptr pVTab[%d];int iRefCnt", $iImplIfaces), $pThis) - $tThis.iRefCnt -= 1 - Return $tThis.iRefCnt -EndFunc ;==>__Mthd_Release - -Func __Mthd_QueryInterfaceThunk($pThis, $pIID, $ppObj) - Local $hResult = $S_OK - Local $tIID = DllStructCreate($tagGUID, $pIID) - If _WinAPI_StringFromGUID($tIID) = $sIID_IUnknown Then - DllStructSetData(DllStructCreate("ptr", $ppObj), 1, $pThis) - Else - $pThis = Ptr($pThis - $PTR_LEN) - Local $pVTab = DllStructGetData(DllStructCreate("ptr", $pThis), 1) - Local $pFunc = DllStructGetData(DllStructCreate("ptr", $pVTab), 1) - Local $aCall = DllCallAddress("long", $pFunc, "ptr", $pThis, "ptr", $pIID, "ptr", $ppObj) - $hResult = $aCall[0] - EndIf - Return $hResult -EndFunc ;==>__Mthd_QueryInterfaceThunk - -Func __Mthd_AddRefThunk($pThis) - $pThis = Ptr($pThis - $PTR_LEN) - Return _AddRef($pThis) -EndFunc ;==>__Mthd_AddRefThunk - -Func __Mthd_ReleaseThunk($pThis) - $pThis = Ptr($pThis - $PTR_LEN) - Return _Release($pThis) -EndFunc ;==>__Mthd_ReleaseThunk -#EndRegion Internal IUnknown Methods - -#Region Internal IDataSource Methods - -Func __Mthd_QueryContinueDrag($pThis, $bEscapePressed, $iKeyState) - #forceref $pThis, $bEscapePressed, $iKeyState - -;~ Key State values may be combined. Test using BitAND! -;~ If BitAND($MK_RBUTTON, $iKeyState) Then ... - -;~ Key Constants: -;~ $MK_RBUTTON -;~ $MK_SHIFT -;~ $MK_CONTROL -;~ $MK_MBUTTON -;~ $MK_XBUTTON1 -;~ $MK_XBUTTON2 - - Local $iReturn = $S_OK - If $bEscapePressed Then - $iReturn = $DRAGDROP_S_CANCEL - Else - If Not BitAND($iKeyState, BitOR($MK_LBUTTON, $MK_RBUTTON)) Then $iReturn = $DRAGDROP_S_DROP - EndIf - - Return $iReturn -EndFunc ;==>__Mthd_QueryContinueDrag - - -Func __Mthd_GiveFeedback($pThis, $iEffect) - #forceref $pThis, $iEffect - -;~ Drop effect values may be combined. Test using BitAND! -;~ If BitAND($DROPEFFECT_COPY, $iEffect) Then ... - -;~ Effect Constants... -;~ $DROPEFFECT_NONE -;~ $DROPEFFECT_COPY -;~ $DROPEFFECT_MOVE -;~ $DROPEFFECT_LINK -;~ $DROPEFFECT_SCROLL - - Local $sTreeListItemText - Local Static $sTreeListItemTextPrev - - Select - Case $sTargetCtrl = 'Tree' - Local $hItemHover = TreeItemFromPoint($g_hTreeView) - If $hItemHover <> 0 Then - ; bring focus to treeview to properly show DROPHILITE - _WinAPI_SetFocus($g_hTreeView) - _GUICtrlTreeView_SelectItem($g_hTreeView, $hItemHover) - _GUICtrlTreeView_SetState($g_hTreeView, $hTreeItemOrig, $TVIS_SELECTED, True) - Else - ; restore original treeview selection if cursor leaves treeview - _GUICtrlTreeView_SelectItem($g_hTreeView, $hTreeItemOrig) - EndIf - Case $sTargetCtrl = 'List' - Local $iListHover = ListItemFromPoint($g_hListview) - If $iListHover >= 0 Then - ; bring focus to listview to show hot item (needed for listview to listview drag) - _WinAPI_SetFocus($g_hListview) - _GUICtrlListView_SetHotItem($idListview, $iListHover) - EndIf - Case Else - ; restore proper state back to original treeview selection - _GUICtrlTreeView_SelectItem($g_hTreeView, $hTreeItemOrig) - EndSelect - - Return $DRAGDROP_S_USEDEFAULTCURSORS -EndFunc ;==>__Mthd_GiveFeedback - -#EndRegion Internal IDataSource Methods - -#Region Internal IDataSourceNotify Methods -Func __Mthd_DragEnterTarget($pThis, $hTarget) - Local Const $iDataOffset = 52 + $PTR_LEN - Local $tData = DllStructCreate("align 4; hwnd hTarget", Ptr($pThis + $iDataOffset)) - DllStructSetData($tData, "hTarget", $hTarget) - Local $hTargetCtrl = DllStructSetData($tData, "hTarget", $hTarget) - If $hTargetCtrl = $g_hTreeView Then - ConsoleWrite("drag target is treeview" & @CRLF) - $sTargetCtrl = 'Tree' - EndIf - If $hTargetCtrl = $g_hListview Then - ConsoleWrite("drag target is listview" & @CRLF) - $sTargetCtrl = 'List' - EndIf - ;ConsoleWrite("target: " & DllStructSetData($tData, "hTarget", $hTarget) & @CRLF) - ;ConsoleWrite("parent: " & _WinAPI_GetAncestor(DllStructSetData($tData, "hTarget", $hTarget), $GA_PARENT) & @CRLF) - - Return $S_OK -EndFunc ;==>__Mthd_DragEnterTarget - -Func __Mthd_DragLeaveTarget($pThis) - Local Const $iDataOffset = 52 + $PTR_LEN - Local $tData = DllStructCreate("align 4; hwnd hTarget", Ptr($pThis + $iDataOffset)) - DllStructSetData($tData, "hTarget", 0) - $sTargetCtrl = '' +Func RegisterDragDrop($hWnd, $pDropTarget) + Local $aCall = DllCall("ole32.dll", "long", "RegisterDragDrop", "hwnd", $hWnd, "ptr", $pDropTarget) + If @error Then Return SetError(TranslateDllError(), 0, False) + Return SetError($aCall[0], 0, $aCall[0] = $S_OK) +EndFunc - Return $S_OK -EndFunc ;==>__Mthd_DragLeaveTarget -#EndRegion Internal IDataSourceNotify Methods +Func RevokeDragDrop($hWnd) + Local $aCall = DllCall("ole32.dll", "long", "RevokeDragDrop", "hwnd", $hWnd) + If @error Then Return SetError(TranslateDllError(), 0, False) + Return SetError($aCall[0], 0, $aCall[0] = $S_OK) +EndFunc From 0711b526cca24debc8fea25a23af5193f531e1b0 Mon Sep 17 00:00:00 2001 From: WildByDesign Date: Tue, 3 Feb 2026 12:40:13 -0500 Subject: [PATCH 03/14] Clean up ListView drag and drop code --- src/main.au3 | 102 ++++++++++----------------------------------------- 1 file changed, 20 insertions(+), 82 deletions(-) diff --git a/src/main.au3 b/src/main.au3 index 6d18f93..c5b29c5 100644 --- a/src/main.au3 +++ b/src/main.au3 @@ -50,9 +50,9 @@ Global $hTLESystem, $iFrame_A, $hSeparatorFrame, $aWinSize2, $idInputPath, $g_hI Global $g_hGUI, $g_hChild, $g_hHeader, $g_hListview, $idListview, $iHeaderHeight, $hParentFrame, $g_iIconWidth, $g_hTreeView Global $g_hSizebox, $g_hOldProc, $g_iHeight, $g_hDots Global $idPropertiesItem, $idPropertiesLV, $sCurrentPath -Global $hListImgList, $iListDragIndex, $aDragSource, $sTargetCtrl, $hTreeItemOrig, $hIcon +Global $hListImgList, $iListDragIndex, $sTargetCtrl, $hTreeItemOrig, $hIcon Global $sBack, $sForward, $sUpLevel, $sRefresh -Global $bDragTreeList = False, $sDragSrc, $sTreeDragItem, $sListDragItems, $bDragToolActive = False +Global $sTreeDragItem, $sListDragItems, $bDragToolActive = False Global $pLVDropTarget, $pTVDropTarget Global $bPathInputChanged = False, $bLoadStatus = False, $bCursorOverride = False Global $idExitItem, $idAboutItem @@ -793,16 +793,26 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) Case $LVN_ITEMCHANGED ; item selection(s) have changed _selectionChangedLV() - Case $LVN_BEGINDRAG + Case $LVN_BEGINDRAG, $LVN_BEGINRDRAG Local $tNMListView = DllStructCreate($tagNMLISTVIEW, $lParam) - Local $sItemText = _GUICtrlListView_GetItemText($tNMHDR.hwndFrom, $tNMLISTVIEW.item) - $sItemText = __TreeListExplorer_GetPath($hTLESystem) & $sItemText - $bDragTreeList = True - $sDragSrc = "List" $hTreeItemOrig = _GUICtrlTreeView_GetSelection($g_hTreeView) - ; fire off adlib to get multiple selection drag details - AdlibRegister("_ListGetSelections", 10) + ; create array with list of selected listview items + Local $aItems = _GUICtrlListView_GetSelectedIndices($tNMHDR.hwndFrom, True) + For $i = 1 To $aItems[0] + $aItems[$i] = __TreeListExplorer_GetPath($hTLESystem) & _GUICtrlListView_GetItemText($tNMHDR.hwndFrom, $aItems[$i]) + Next + _ArrayDelete($aItems, 0) + + Local $pDataObj, $pDropSource + $pDataObj = GetDataObjectOfFile_B($aItems) + ;Create an IDropSource to handle our end of the drag/drop operation. + $pDropSource = CreateDropSource() + + _SHDoDragDrop($pDataObj, $pDropSource, BitOR($DROPEFFECT_COPY, $DROPEFFECT_LINK)) + + DestroyDropSource($pDropSource) + _Release($pDataObj) ; there is not supposed to be a Return value on LVN_BEGINDRAG ; however it fixes an issue with built-in drag-drop mechanism (now that we use DoDragDrop) @@ -863,17 +873,11 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) Case $g_hTreeView Switch $iCode Case $TVN_BEGINDRAGA, $TVN_BEGINDRAGW - $aDragSource = "" Local $tTree = DllStructCreate($tagNMTREEVIEW, $lParam) Local $hDragItem = DllStructGetData($tTree, "NewhItem") - ;$sTreeDragItem = TreeItemToPath($g_hTreeView, $hDragItem) - $aDragSource = TreeItemToPath($g_hTreeView, $hDragItem, True) - $bDragTreeList = True - $sDragSrc = "Tree" - $hTreeItemOrig = _GUICtrlTreeView_GetSelection($g_hTreeView) - $sItemText = TreeItemToPath($g_hTreeView, $hDragItem) + Local $sItemText = TreeItemToPath($g_hTreeView, $hDragItem) Local $pDataObj, $pDropSource @@ -1854,18 +1858,6 @@ Func _EventsGUI() EndSwitch EndFunc ;==>_EventsGUI -Func _MsgExample($aDragSource, $sDestination) - Local $sMsg - $sMsg = "Source Files: " & @CRLF - For $i = 1 To $aDragSource[0] - $sMsg &= $aDragSource[$i] & @CRLF - Next - $sMsg &= @CRLF - $sMsg &= "Destination: " & @CRLF - $sMsg &= $sDestination - MsgBox(0, "Example", $sMsg) -EndFunc ;==>_MsgExample - Func TreeItemFromPoint($hWnd) Local $tMPos = _WinAPI_GetMousePos(True, $hWnd) Return _GUICtrlTreeView_HitTestItem($hWnd, DllStructGetData($tMPos, 1), DllStructGetData($tMPos, 2)) @@ -1979,60 +1971,6 @@ Func WM_WINDOWPOSCHANGED_Handler($hWnd, $iMsg, $wParam, $lParam) Return $GUI_RUNDEFMSG EndFunc ;==>WM_WINDOWPOSCHANGED_Handler -Func _ListGetSelections() - $sListDragItems = "" - $aDragSource = "" - $aDragSource = _GUICtrlListView_GetSelectedIndices($g_hListview, True) - If $aDragSource[0] = 1 Then - $iListDragIndex = $aDragSource[1] - Else - $iListDragIndex = $aDragSource[1] - EndIf - For $i = 1 To $aDragSource[0] - $aDragSource[$i] = __TreeListExplorer_GetPath($hTLESystem) & _GUICtrlListView_GetItemText($idListview, $aDragSource[$i], 0) - $sListDragItems &= $aDragSource[$i] & " + " - Next - $sListDragItems = StringTrimRight($sListDragItems, 3) - - _ArrayDelete($aDragSource, 0) - - Local $pDataObj, $pDropSource - $pDataObj = GetDataObjectOfFile_B($aDragSource) - ;Create an IDropSource to handle our end of the drag/drop operation. - $pDropSource = CreateDropSource() - - _SHDoDragDrop($pDataObj, $pDropSource, BitOR($DROPEFFECT_COPY, $DROPEFFECT_LINK)) - - DestroyDropSource($pDropSource) - _Release($pDataObj) - - #cs ; old method - ; drag drop - Local $pDataObj, $pDropSource - - ;Get an IDataObject representing the file to copy - $pDataObj = GetDataObjectOfFile($g_hGUI, $aDragSource[1]) - If Not @error Then - - ;Create an IDropSource to handle our end of the drag/drop operation. - $pDropSource = CreateDropSource() - If Not @error Then - ;We allow DROPEFFECT_COPY and DROPEFFECT_LINK. We don't want to DROPEFFECT_MOVE the file!! - ;DoDragDrop($pDataObj, $pDropSource, BitOR($DROPEFFECT_COPY, $DROPEFFECT_LINK)) - _SHDoDragDrop_old($g_hGUI, $pDataObj, $pDropSource, BitOR($DROPEFFECT_COPY,$DROPEFFECT_LINK)) - - ;Operation done, destroy our drop source. (Can't just IUnknown_Release() this one!) - DestroyDropSource($pDropSource) - EndIf - - ;Relase the data object so the system can destroy it (prevent memory leaks) - _Release($pDataObj) - EndIf - #ce - - AdlibUnRegister("_ListGetSelections") -EndFunc ;==>_ListGetSelections - Func TreeItemToPath($hTree, $hItem, $bArray = False) Local $sPath = StringReplace(_GUICtrlTreeView_GetTree($hTree, $hItem), "|", "\") $sPath = StringTrimLeft($sPath, StringInStr($sPath, "\")) ; remove this pc at the beginning From aeee555ce0f810ffda9dee774e1ee5c828e761e7 Mon Sep 17 00:00:00 2001 From: WildByDesign Date: Wed, 4 Feb 2026 06:14:59 -0500 Subject: [PATCH 04/14] Improve DROPHILITE in ListView - show DROPHILITE on folders only --- lib/DropTargetObject.au3 | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/lib/DropTargetObject.au3 b/lib/DropTargetObject.au3 index 3054362..b750100 100644 --- a/lib/DropTargetObject.au3 +++ b/lib/DropTargetObject.au3 @@ -18,6 +18,7 @@ Global $tagTargetObjIntData = "hwnd hTarget;bool bAcceptDrop;ptr pDataObject;ptr Global Const $__g_iTargetObjDataOffset = $PTR_LEN * 2 + 4 Global $hTreeOrig +Global $iPreviousHot Func CreateDropTarget($hTarget = 0) $__g_iDropTargetCount += 1 @@ -147,6 +148,7 @@ Func __Mthd_DragOver($pThis, $iKeyState, $iPoint, $piEffect) #forceref $pThis, $iKeyState, $iPoint, $piEffect Local $sDirText = "" + Local $bIsFolder Local $tPoint = DllStructCreate($tagPoint) $tPoint.X = _WinAPI_LoDWord($iPoint) @@ -161,9 +163,10 @@ Func __Mthd_DragOver($pThis, $iKeyState, $iPoint, $piEffect) Case $WC_LISTVIEW Local $aListItem = _GUICtrlListView_HitTest($tData.hTarget, $tPoint.X, $tPoint.Y) Local $sItemText = _GUICtrlListView_GetItemText($tData.hTarget, $aListItem[0]) - Local $sDirPath = __TreeListExplorer_GetPath(1) & $sItemText - If StringInStr(FileGetAttrib($sDirPath), "D") Then + Local $sFullPath = __TreeListExplorer_GetPath(1) & $sItemText + If StringInStr(FileGetAttrib($sFullPath), "D") Then $sDirText = $sItemText + $bIsFolder = True Else ; get the currently selected path $sDirPath = __TreeListExplorer_GetPath(1) @@ -179,12 +182,21 @@ Func __Mthd_DragOver($pThis, $iKeyState, $iPoint, $piEffect) Local $aPath = _StringBetween($sDirPath, "\", "\") $sDirText = $aPath[UBound($aPath) - 1] EndIf - ;Local $sDirText = _GUICtrlListView_GetItemText($tData.hTarget, _GUICtrlListView_GetHotItem($tData.hTarget), 0) - ;$aListItem[0] + + ; clear previously DROPHILITED listview item + _GUICtrlListView_SetItemState($tData.hTarget, $iPreviousHot, 0, $LVIS_DROPHILITED) + If $aListItem[0] >= 0 Then + $iPreviousHot = $aListItem[0] ; bring focus to listview to show hot item (needed for listview to listview drag) _WinAPI_SetFocus($tData.hTarget) - _GUICtrlListView_SetHotItem($tData.hTarget, $aListItem[0]) + ;_GUICtrlListView_SetHotItem($tData.hTarget, $aListItem[0]) + If $bIsFolder Then + _GUICtrlListView_SetItemState($tData.hTarget, $aListItem[0], $LVIS_DROPHILITED, $LVIS_DROPHILITED) + EndIf + Else + ; clear previously DROPHILITED listview item + _GUICtrlListView_SetItemState($tData.hTarget, $iPreviousHot, 0, $LVIS_DROPHILITED) EndIf Case $WC_TREEVIEW ;Local $tMPos = _WinAPI_GetMousePos(True, $tData.hTarget) @@ -223,7 +235,8 @@ Func __Mthd_DragLeave($pThis) Switch _WinAPI_GetClassName($tData.hTarget) Case $WC_LISTVIEW - ;_GUICtrlListView_SetInsertMark($tData.hTarget, -1) + ; clear previously DROPHILITED listview item + _GUICtrlListView_SetItemState($tData.hTarget, $iPreviousHot, 0, $LVIS_DROPHILITED) Case $WC_TREEVIEW ; restore original treeview selection if cursor leaves treeview _GUICtrlTreeView_SelectItem($tData.hTarget, $hTreeOrig) @@ -271,6 +284,8 @@ Func __Mthd_Drop($pThis, $pDataOject, $iKeyState, $iPoint, $piEffect) Switch _WinAPI_GetClassName($tData.hTarget) Case $WC_LISTVIEW + ; clear previously DROPHILITED listview item + _GUICtrlListView_SetItemState($tData.hTarget, $iPreviousHot, 0, $LVIS_DROPHILITED) For $i = 1 To $asFilenames[0] ;_GUICtrlListView_InsertItem($tData.hTarget, $asFilenames[$i], $vItem) $vItem += 1 From b7f0a1cd0ff9716a12213d927fe3ade86e9745fd Mon Sep 17 00:00:00 2001 From: WildByDesign Date: Wed, 4 Feb 2026 07:58:53 -0500 Subject: [PATCH 05/14] Delete src/desktop.ini --- src/desktop.ini | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 src/desktop.ini diff --git a/src/desktop.ini b/src/desktop.ini deleted file mode 100644 index d1ead95..0000000 --- a/src/desktop.ini +++ /dev/null @@ -1,2 +0,0 @@ -[LocalizedFileNames] -Command Prompt.lnk=@%SystemRoot%\system32\shell32.dll,-22022 From 88a793c6a1b85e4ea3227c9382b2913d819af932 Mon Sep 17 00:00:00 2001 From: WildByDesign Date: Wed, 4 Feb 2026 08:03:14 -0500 Subject: [PATCH 06/14] Drag and drop cleanup - tidy up some of the new drag and drop code - remove old (unused) drag and drop code --- .gitignore | 1 + lib/DropTargetObject.au3 | 2 + src/main.au3 | 213 +++++++-------------------------------- 3 files changed, 39 insertions(+), 177 deletions(-) diff --git a/.gitignore b/.gitignore index d5da268..a4863f2 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ temp/ Au3ChangelogUpdater.exe package.json +lib/desktop.ini diff --git a/lib/DropTargetObject.au3 b/lib/DropTargetObject.au3 index b750100..7cdc447 100644 --- a/lib/DropTargetObject.au3 +++ b/lib/DropTargetObject.au3 @@ -293,6 +293,8 @@ Func __Mthd_Drop($pThis, $pDataOject, $iKeyState, $iPoint, $piEffect) ;_GUICtrlListView_SetInsertMark($tData.hTarget, -1) Case $WC_TREEVIEW + ; restore original treeview selection if cursor leaves treeview + _GUICtrlTreeView_SelectItem($tData.hTarget, $hTreeOrig) Local $hInsAfter = _GUICtrlTreeView_GetPrev($tData.hTarget, $vItem) If Not $hInsAfter Then $hInsAfter = $TVI_FIRST For $i = 1 To $asFilenames[0] diff --git a/src/main.au3 b/src/main.au3 index c5b29c5..87ee745 100644 --- a/src/main.au3 +++ b/src/main.au3 @@ -323,7 +323,6 @@ Func _FilesAu3() ; Set resizing flag for all created frames _GUIFrame_ResizeSet(0) - GUIRegisterMsg($WM_DROPFILES, "WM_DROPFILES") GUIRegisterMsg($WM_COMMAND, "WM_COMMAND2") GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY2") @@ -802,10 +801,9 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) For $i = 1 To $aItems[0] $aItems[$i] = __TreeListExplorer_GetPath($hTLESystem) & _GUICtrlListView_GetItemText($tNMHDR.hwndFrom, $aItems[$i]) Next - _ArrayDelete($aItems, 0) Local $pDataObj, $pDropSource - $pDataObj = GetDataObjectOfFile_B($aItems) + $pDataObj = GetDataObjectOfFiles($hWnd, $aItems) ;Create an IDropSource to handle our end of the drag/drop operation. $pDropSource = CreateDropSource() @@ -882,7 +880,7 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) Local $pDataObj, $pDropSource ;Get an IDataObject representing the file to copy - $pDataObj = GetDataObjectOfFile($g_hGUI, $sItemText) + $pDataObj = GetDataObjectOfFile($hWnd, $sItemText) If Not @error Then ;Create an IDropSource to handle our end of the drag/drop operation. @@ -1983,45 +1981,6 @@ Func TreeItemToPath($hTree, $hItem, $bArray = False) Return $sPath EndFunc ;==>TreeItemToPath -Func WM_DROPFILES($hWnd, $iMsg, $wParam, $lParam) - #forceref $hWnd, $iMsg, $wParam, $lParam - ;First call with 0xFFFFFFFF, get number of files dropped - Local $aCall = DllCall($hShell32, "uint", "DragQueryFileW", "hwnd", $wParam, "uint", 0xFFFFFFFF, "ptr", 0, "int", 0) - If @error Then Return - Local $iFileCount = $aCall[0] - - Local $iBuffSize, $tBuffer, $sAttrib - For $i = 0 To $iFileCount - 1 - ;Second call call with 0 for buff size, retrieves required buff size for filename. - $aCall = DllCall($hShell32, "uint", "DragQueryFileW", "hwnd", $wParam, "uint", $i, "ptr", 0, "int", 0) - If @error Then ContinueLoop - $iBuffSize = $aCall[0] + 1 - - ;Create name buffer and fill. - $tBuffer = DllStructCreate(StringFormat("wchar fileName[%d]", $iBuffSize)) - $aCall = DllCall($hShell32, "uint", "DragQueryFileW", "hwnd", $wParam, "uint", $i, "struct*", $tBuffer, "int", $iBuffSize) - If @error Then ContinueLoop - - ConsoleWrite("file name: " & $tBuffer.fileName & @CRLF) - ConsoleWrite("handle: " & $hWnd & @CRLF) - If $hWnd = _GUIFrame_GetHandle($iFrame_A, 1) Then ConsoleWrite("dropped on treeview" & @CRLF) - If $hWnd = _GUIFrame_GetHandle($iFrame_A, 2) Then ConsoleWrite("dropped on listview" & @CRLF) - #cs - ;Only add file if is not hidden, not a dir, not already in the list! - If _GUICtrlListView_FindText($hListView, $tBuffer.fileName) = -1 Then - $sAttrib = FileGetAttrib($tBuffer.fileName) - If StringRegExp($sAttrib, "D|H") Then ContinueLoop - _GUICtrlListView_AddItem($hListView, $tBuffer.fileName) - EndIf - #ce - Next - - ; restore proper state back to original treeview selection - _GUICtrlTreeView_SelectItem($g_hTreeView, $hTreeItemOrig) - - Return -EndFunc - ;Convert @error codes from DllCall into win32 codes. Func TranslateDllError($iError = @error) Switch $iError @@ -2038,22 +1997,6 @@ Func CoTaskMemFree($pMemBlock) DllCall("Ole32.dll", "none", "CoTaskMemFree", "ptr", $pMemBlock) EndFunc ;==>CoTaskMemFree -Func DoDragDrop($pDataObj, $pDropSource, $iOKEffects) - ;We must pass a IID_IDropSource ptr. - $pDropSource = _QueryInterface($pDropSource, $sIID_IDropSource) - _Release($pDropSource) - - Local $aCall = DllCall("ole32.dll", "long", "DoDragDrop", "ptr", $pDataObj, "ptr", $pDropSource, "dword", $iOKEffects, "ptr*", 0) - If @error Then Return SetError(@error, @extended, $aCall) - Return SetError($aCall[0], 0, $aCall[4]) -EndFunc ;==>DoDragDrop - -; DoDragDrop($pDataObj, $pDropSource, BitOR($DROPEFFECT_COPY, $DROPEFFECT_LINK)) -; _SHDoDragDrop($hGUI, $pDataObj, $pDropSource, BitOR($DROPEFFECT_COPY,$DROPEFFECT_LINK)) -Func _SHDoDragDrop_old($hWnd, ByRef $pDataObj, ByRef $pDropSource, $dwDropEffects) - DllCall($hShell32,"lresult","SHDoDragDrop", "hwnd", Null, "ptr", $pDataObj,"ptr", Null, "dword", BitOR($DROPEFFECT_COPY,$DROPEFFECT_LINK), "dword*", 0) -EndFunc - Func _SHDoDragDrop($pDataObj, $pDropSource, $iOKEffects) ;We must pass a IID_IDropSource ptr. $pDropSource = _QueryInterface($pDropSource, $sIID_IDropSource) @@ -2068,122 +2011,6 @@ Func _SHDoDragDrop($pDataObj, $pDropSource, $iOKEffects) Return SetError($aCall[0], 0, $aCall[4]) EndFunc ;==>_SHDoDragDrop -Func GetDataObjectOfFile_B(ByRef $sPath) - Local $iCount = UBound($sPath) - If $iCount = 0 Then Return 0 - - Local $sParentPath = StringLeft($sPath[0], StringInStr($sPath[0], "\", 0, -1) - 1) - Local $pParentPidl = _WinAPI_ShellILCreateFromPath($sParentPath) - - Local $tPidls = DllStructCreate("ptr[" & $iCount & "]") - - Local $pFullPidl, $pRelativePidl, $last_SHITEMID - For $i = 0 To $iCount - 1 - $pFullPidl = _WinAPI_ShellILCreateFromPath($sPath[$i]) - $last_SHITEMID = DllCall($hShell32, "ptr", "ILFindLastID", "ptr", $pFullPidl)[0] - $pRelativePidl = DllCall($hShell32, "ptr", "ILClone", "ptr", $last_SHITEMID)[0] - DllStructSetData($tPidls, 1, $pRelativePidl, $i + 1) - DllCall($hShell32, "none", "ILFree", "ptr", $pFullPidl) - Next - - Local $tIID_IDataObject = _WinAPI_GUIDFromString($sIID_IDataObject) - Local $pIDataObject = __SHCreateDataObject($tIID_IDataObject, $pParentPidl, $iCount, DllStructGetPtr($tPidls), 0) - - DllCall($hShell32, "none", "ILFree", "ptr", $pParentPidl) - For $i = 1 To $iCount - DllCall($hShell32, "none", "ILFree", "ptr", DllStructGetData($tPidls, 1, $i)) - Next - - If Not $pIDataObject Then Return 0 - Return $pIDataObject -EndFunc - -Func GetDataObjectOfFile_C(ByRef $sPath) - If UBound($sPath) = 0 Then Return 0 - - Local $tIID_IDataObject = _WinAPI_GUIDFromString($sIID_IDataObject) - Local $pIDataObject = __SHCreateDataObject($tIID_IDataObject, 0, 0, 0, 0) - If Not $pIDataObject Then Return 0 - - Local Const $tag_IDataObject = _ - "GetData hresult(ptr;ptr*);" & _ - "GetDataHere hresult(ptr;ptr*);" & _ - "QueryGetData hresult(ptr);" & _ - "GetCanonicalFormatEtc hresult(ptr;ptr*);" & _ - "SetData hresult(ptr;ptr;bool);" & _ - "EnumFormatEtc hresult(dword;ptr*);" & _ - "DAdvise hresult(ptr;dword;ptr;dword*);" & _ - "DUnadvise hresult(dword);" & _ - "EnumDAdvise hresult(ptr*);" - Local $oIDataObject = ObjCreateInterface($pIDataObject, $sIID_IDataObject, $tag_IDataObject) - If Not IsObj($oIDataObject) Then - _Release($pIDataObject) - Return 0 - Endif - - Local $tFORMATETC, $tSTGMEDIUM - __Fill_tag_FORMATETC($tFORMATETC) - __Fill_tag_STGMEDIUM($tSTGMEDIUM, $sPath) - - $oIDataObject.SetData(DllStructGetPtr($tFORMATETC), DllStructGetPtr($tSTGMEDIUM), 1) - _AddRef($pIDataObject) - - Return $pIDataObject -EndFunc - -Func __Fill_tag_FORMATETC(Byref $tFORMATETC) - Local Const $CF_HDROP = 15 - Local Const $TYMED_HGLOBAL = 1 - - $tFORMATETC = DllStructCreate("ushort cfFormat; ptr ptd; uint dwAspect; int lindex; uint tymed") - DllStructSetData($tFORMATETC, "cfFormat", $CF_HDROP) - DllStructSetData($tFORMATETC, "dwAspect", 1) - DllStructSetData($tFORMATETC, "lindex", -1) - DllStructSetData($tFORMATETC, "tymed", $TYMED_HGLOBAL) -EndFunc - -Func __Fill_tag_STGMEDIUM(Byref $tSTGMEDIUM, Byref $aFiles) - Local Const $CF_HDROP = 15 - Local Const $TYMED_HGLOBAL = 1 - - Local $sFileList = "" - For $i = 0 To UBound($aFiles) - 1 - $sFileList &= $aFiles[$i] & Chr(0) - Next - $sFileList &= Chr(0) - - Local $iSize = 20 + (StringLen($sFileList) * 2) - - Local $hGlobal = DllCall($hKernel32, "ptr", "GlobalAlloc", "uint", 0x2042, "ulong_ptr", $iSize)[0] - Local $pLock = DllCall($hKernel32, "ptr", "GlobalLock", "ptr", $hGlobal)[0] - - Local $tDROPFILES = DllStructCreate("dword pFiles; int x; int y; bool fNC; bool fWide", $pLock) - DllStructSetData($tDROPFILES, "pFiles", 20) - DllStructSetData($tDROPFILES, "fWide", True) - - Local $tPaths = DllStructCreate("wchar[" & StringLen($sFileList) & "]", $pLock + 20) - DllStructSetData($tPaths, 1, $sFileList) - - DllCall($hKernel32, "bool", "GlobalUnlock", "ptr", $hGlobal) - - $tSTGMEDIUM = DllStructCreate("uint tymed; ptr hGlobal; ptr pUnkForRelease") - DllStructSetData($tSTGMEDIUM, "tymed", $TYMED_HGLOBAL) - DllStructSetData($tSTGMEDIUM, "hGlobal", $hGlobal) - DllStructSetData($tSTGMEDIUM, "pUnkForRelease", 0) -EndFunc - -Func __SHCreateDataObject($tIID_IDataObject, $ppidlFolder = 0, $cidl = 0, $papidl = 0, $pdtInner = 0) - Local $aRes = DllCall($hShell32, "long", "SHCreateDataObject", _ - "ptr", $ppidlFolder, _ - "uint", $cidl, _ - "ptr", $papidl, _ - "ptr", $pdtInner, _ - "struct*", $tIID_IDataObject, _ - "ptr*", 0) - If @error Then Return SetError(1, 0, $aRes[0]) - Return $aRes[6] -EndFunc - Func GetDataObjectOfFile($hWnd, $sPath) ;Get the path as an idList. This is allocated memory that we should free later on. Local $aCall = DllCall("Shell32.dll", "long", "SHParseDisplayName", "wstr", $sPath, "ptr", 0, "ptr*", 0, "ulong", 0, "ulong*", 0) @@ -2214,14 +2041,46 @@ Func GetDataObjectOfFile($hWnd, $sPath) Return SetError($iError, 0, Ptr($pDataObject)) EndFunc ;==>GetDataObjectOfFile +Func GetDataObjectOfFiles($hWnd, $asPaths) + ;If we use the DesktopFolder object as the parent, children can all be defined by normal file paths. + ;So we don't need to worry about sibling folders to the root etc... + + Local $aCall = DllCall("Shell32.dll", "long", "SHGetDesktopFolder", "ptr*", 0) + Local $iError = @error ? TranslateDllError() : $aCall[0] + If $iError Then Return SetError($iError, 0, False) + + Local $pShellFolder = $aCall[1] + Local $tChildren = DllStructCreate(StringFormat("ptr pIdls[%d]", UBound($asPaths))) + + Local $iEaten, $pChildIDL, $iAttributes + Local $oShellFolder = ObjCreateInterface($pShellFolder, $sIID_IShellFolder, $tagIShellFolder) + + For $i = 1 To $asPaths[0] + $oShellFolder.ParseDisplayName($hWnd, 0, $asPaths[$i], $iEaten, $pChildIDL, $iAttributes) + $tChildren.pIdls(($i)) = $pChildIDL + Next + + ;We have an interface tag for IShellFolder, so we can use ObjCreateInterface to "convert" it into an object datatype. + ;$oShellFolder will automatically release when it goes out of scope, so we don't need to manually _Release($pShellFolder). + Local $pDataObject, $tIID_IDataObject = _WinAPI_GUIDFromString($sIID_IDataObject) + $iError = $oShellFolder.GetUIObjectOf($hWnd, $asPaths[0], DllStructGetPtr($tChildren), $tIID_IDataObject, 0, $pDataObject) + + ;Free the IDLs now we have a data object. + For $i = 1 To $asPaths[0] + CoTaskMemFree($tChildren.pIdls(($i)) & @CRLF) + Next + + Return SetError($iError, 0, Ptr($pDataObject)) +EndFunc ;==>GetDataObjectOfFiles + Func RegisterDragDrop($hWnd, $pDropTarget) Local $aCall = DllCall("ole32.dll", "long", "RegisterDragDrop", "hwnd", $hWnd, "ptr", $pDropTarget) If @error Then Return SetError(TranslateDllError(), 0, False) Return SetError($aCall[0], 0, $aCall[0] = $S_OK) -EndFunc +EndFunc ;==>RegisterDragDrop Func RevokeDragDrop($hWnd) Local $aCall = DllCall("ole32.dll", "long", "RevokeDragDrop", "hwnd", $hWnd) If @error Then Return SetError(TranslateDllError(), 0, False) Return SetError($aCall[0], 0, $aCall[0] = $S_OK) -EndFunc +EndFunc ;==>RevokeDragDrop From e137df406bd86954aa4f9c33cbbe9dfd2b0f0b41 Mon Sep 17 00:00:00 2001 From: WildByDesign Date: Sat, 7 Feb 2026 18:53:02 -0500 Subject: [PATCH 07/14] Add IFileOperation functions - adds CopyItems and MoveItems - future possibilities for DeleteItem(s), RenameItem(s), etc. --- lib/DropTargetObject.au3 | 293 +++++++++++++++++++------------- lib/IFileOperation.au3 | 125 ++++++++++++++ lib/SharedFunctions.au3 | 229 ++++++++++++++++++++++++++ src/main.au3 | 348 ++++++++++++++++----------------------- 4 files changed, 674 insertions(+), 321 deletions(-) create mode 100644 lib/IFileOperation.au3 create mode 100644 lib/SharedFunctions.au3 diff --git a/lib/DropTargetObject.au3 b/lib/DropTargetObject.au3 index 7cdc447..6bccb75 100644 --- a/lib/DropTargetObject.au3 +++ b/lib/DropTargetObject.au3 @@ -11,6 +11,8 @@ #include #include "TreeListExplorer.au3" +#include "IFileOperation.au3" +#include "SharedFunctions.au3" Global $__g_iDropTargetCount Global $__g_hMthd_DragEnter, $__g_hMthd_DragOver, $__g_hMthd_DragLeave, $__g_hMthd_Drop @@ -18,7 +20,8 @@ Global $tagTargetObjIntData = "hwnd hTarget;bool bAcceptDrop;ptr pDataObject;ptr Global Const $__g_iTargetObjDataOffset = $PTR_LEN * 2 + 4 Global $hTreeOrig -Global $iPreviousHot +Global $iPreviousHot, $sDropTV, $iFinalEffect +Global $sSourceDrive, $sSourcePath, $bIsSameDrive, $bIsSameFolder Func CreateDropTarget($hTarget = 0) $__g_iDropTargetCount += 1 @@ -90,9 +93,9 @@ Func DestroyDropTarget($pObject) EndIf EndFunc ;==>DestroyDropTarget -Func __Mthd_DragEnter($pThis, $pDataOject, $iKeyState, $iPoint, $piEffect) +Func __Mthd_DragEnter($pThis, $pDataObject, $iKeyState, $iPoint, $piEffect) - #forceref $pThis, $pDataOject, $iKeyState, $iPoint, $piEffect + #forceref $pThis, $pDataObject, $iKeyState, $iPoint, $piEffect Local $sDirText = "" @@ -103,9 +106,9 @@ Func __Mthd_DragEnter($pThis, $pDataOject, $iKeyState, $iPoint, $piEffect) Local $pData = DllStructGetData(DllStructCreate("ptr", Ptr($pThis + $__g_iTargetObjDataOffset)), 1) Local $tData = DllStructCreate($tagTargetObjIntData, $pData) $tData.bAcceptDrop = False - $tData.pDataObject = $pDataOject + $tData.pDataObject = $pDataObject - Local $oDataObject = ObjCreateInterface($pDataOject, $sIID_IDataObject, $tagIDataObject) + Local $oDataObject = ObjCreateInterface($pDataObject, $sIID_IDataObject, $tagIDataObject) ;Addref to counteract the automatic release() when $oDataObject falls out of scope. $oDataObject.AddRef() @@ -124,7 +127,28 @@ Func __Mthd_DragEnter($pThis, $pDataOject, $iKeyState, $iPoint, $piEffect) EndIf WEnd - Switch _WinAPI_GetClassName($tData.hTarget) + ; test getting filename to compare + Local $tFormatEtc = DllStructCreate($tagFORMATETC) + $tFormatEtc.cfFormat = $CF_HDROP + $tFormatEtc.iIndex = -1 + $tFormatEtc.tymed = $TYMED_HGLOBAL + + Local $oDataObject = ObjCreateInterface($pDataObject, $sIID_IDataObject, $tagIDataObject) + Local $tStgMedium = DllStructCreate($tagSTGMEDIUM) + $oDataObject.AddRef() + $oDataObject.GetData($tFormatEtc, $tStgMedium) + + Local $asFilenames = _WinAPI_DragQueryFileEx($tStgMedium.handle) + Local $sPathName = $asFilenames[1] + If StringInStr(FileGetAttrib($sPathName), "D") Then + $sPathName = $sPathName & "\" + EndIf + Local $aPath = _PathSplit_mod($sPathName) + $sSourceDrive = $aPath[$PATH_DRIVE] + $sSourcePath = $aPath[$PATH_DRIVE] & $aPath[$PATH_DIRECTORY] + ; test + + Switch _WinAPI_GetClassName_mod($tData.hTarget) Case $WC_LISTVIEW ; Case $WC_TREEVIEW @@ -138,7 +162,7 @@ Func __Mthd_DragEnter($pThis, $pDataOject, $iKeyState, $iPoint, $piEffect) Local $oIDropTgtHelper = ObjCreateInterface($tData.pIDropTgtHelper, $sIID_IDropTargetHelper, $tagIDropTargetHelper) $oIDropTgtHelper.AddRef() - $oIDropTgtHelper.DragEnter($tData.hTarget, $pDataOject, $tPoint, $piEffect) + $oIDropTgtHelper.DragEnter($tData.hTarget, $pDataObject, $tPoint, $piEffect) Return $S_OK EndFunc ;==>__Mthd_DragEnter @@ -149,6 +173,7 @@ Func __Mthd_DragOver($pThis, $iKeyState, $iPoint, $piEffect) Local $sDirText = "" Local $bIsFolder + Local $sDestDrive, $sDestPath Local $tPoint = DllStructCreate($tagPoint) $tPoint.X = _WinAPI_LoDWord($iPoint) @@ -157,30 +182,35 @@ Func __Mthd_DragOver($pThis, $iKeyState, $iPoint, $piEffect) Local $pData = DllStructGetData(DllStructCreate("ptr", Ptr($pThis + $__g_iTargetObjDataOffset)), 1) Local $tData = DllStructCreate($tagTargetObjIntData, $pData) - _WinAPI_ScreenToClient($tData.hTarget, $tPoint) + _WinAPI_ScreenToClient_mod($tData.hTarget, $tPoint) - Switch _WinAPI_GetClassName($tData.hTarget) + Switch _WinAPI_GetClassName_mod($tData.hTarget) Case $WC_LISTVIEW Local $aListItem = _GUICtrlListView_HitTest($tData.hTarget, $tPoint.X, $tPoint.Y) Local $sItemText = _GUICtrlListView_GetItemText($tData.hTarget, $aListItem[0]) Local $sFullPath = __TreeListExplorer_GetPath(1) & $sItemText - If StringInStr(FileGetAttrib($sFullPath), "D") Then - $sDirText = $sItemText - $bIsFolder = True - Else + ;ConsoleWrite("$sFullPath: " & $sFullPath & @CRLF) + If Not $sItemText Then ; get the currently selected path $sDirPath = __TreeListExplorer_GetPath(1) ; obtain folder name only for drag tooltip Local $aPath = _StringBetween($sDirPath, "\", "\") $sDirText = $aPath[UBound($aPath) - 1] - EndIf - ; handle case when cursor is over ListView but not on item; need to show current directory as drop dir - If $sDirText = "" Then + ; get full path for comparison + $sDestPath = $sDirPath + ElseIf StringInStr(FileGetAttrib($sFullPath), "D") Then + $sDirText = $sItemText + $bIsFolder = True + ; get full path for comparison + $sDestPath = $sFullPath & "\" + Else ; get the currently selected path $sDirPath = __TreeListExplorer_GetPath(1) ; obtain folder name only for drag tooltip Local $aPath = _StringBetween($sDirPath, "\", "\") $sDirText = $aPath[UBound($aPath) - 1] + ; get full path for comparison + $sDestPath = $sDirPath EndIf ; clear previously DROPHILITED listview item @@ -190,7 +220,6 @@ Func __Mthd_DragOver($pThis, $iKeyState, $iPoint, $piEffect) $iPreviousHot = $aListItem[0] ; bring focus to listview to show hot item (needed for listview to listview drag) _WinAPI_SetFocus($tData.hTarget) - ;_GUICtrlListView_SetHotItem($tData.hTarget, $aListItem[0]) If $bIsFolder Then _GUICtrlListView_SetItemState($tData.hTarget, $aListItem[0], $LVIS_DROPHILITED, $LVIS_DROPHILITED) EndIf @@ -199,8 +228,6 @@ Func __Mthd_DragOver($pThis, $iKeyState, $iPoint, $piEffect) _GUICtrlListView_SetItemState($tData.hTarget, $iPreviousHot, 0, $LVIS_DROPHILITED) EndIf Case $WC_TREEVIEW - ;Local $tMPos = _WinAPI_GetMousePos(True, $tData.hTarget) - ;Local $tMPos = _WinAPI_GetMousePos() Local $hTreeItem = _GUICtrlTreeView_HitTestItem($tData.hTarget, $tPoint.X, $tPoint.Y) $sDirText = _GUICtrlTreeView_GetText($tData.hTarget, $hTreeItem) If $hTreeItem <> 0 Then @@ -208,12 +235,32 @@ Func __Mthd_DragOver($pThis, $iKeyState, $iPoint, $piEffect) _WinAPI_SetFocus($tData.hTarget) _GUICtrlTreeView_SelectItem($tData.hTarget, $hTreeItem) _GUICtrlTreeView_SetState($tData.hTarget, $hTreeOrig, $TVIS_SELECTED, True) + ; get full path for comparison + $sDestPath = TreeItemToPath($tData.hTarget, $hTreeItem) + $sDropTV = $sDestPath EndIf Case Else $sDirText = "" EndSwitch - __DoDropResponse($tData, $iKeyState, $tPoint, $piEffect, $sDirText) + ; compare source and target to determine if they are on the same drive + If StringInStr($sDestPath, $sSourceDrive) Then + $bIsSameDrive = True + Else + $bIsSameDrive = False + EndIf + + ; compare source and target to determine if they are the same + If $sDestPath = $sSourcePath Then + $bIsSameFolder = True + Else + $bIsSameFolder = False + EndIf + + __DoDropResponse($tData, $iKeyState, $tPoint, $piEffect, $sDirText, $bIsSameDrive, $bIsSameFolder) + + Local $tEffect = DllStructCreate("dword iEffect", $piEffect) + $iFinalEffect = $tEffect.iEffect Local $oIDropTgtHelper = ObjCreateInterface($tData.pIDropTgtHelper, $sIID_IDropTargetHelper, $tagIDropTargetHelper) $oIDropTgtHelper.AddRef() @@ -233,7 +280,7 @@ Func __Mthd_DragLeave($pThis) $oIDropTgtHelper.AddRef() $oIDropTgtHelper.DragLeave() - Switch _WinAPI_GetClassName($tData.hTarget) + Switch _WinAPI_GetClassName_mod($tData.hTarget) Case $WC_LISTVIEW ; clear previously DROPHILITED listview item _GUICtrlListView_SetItemState($tData.hTarget, $iPreviousHot, 0, $LVIS_DROPHILITED) @@ -248,10 +295,11 @@ Func __Mthd_DragLeave($pThis) Return $S_OK EndFunc ;==>__Mthd_DragLeave -Func __Mthd_Drop($pThis, $pDataOject, $iKeyState, $iPoint, $piEffect) +Func __Mthd_Drop($pThis, $pDataObject, $iKeyState, $iPoint, $piEffect) #forceref $pThis, $iKeyState, $iPoint, $piEffect Local $sDirText = "" + Local $bIsFolder, $iFlags, $sAction Local $tPoint = DllStructCreate($tagPoint) $tPoint.X = _WinAPI_LoDWord($iPoint) @@ -260,12 +308,13 @@ Func __Mthd_Drop($pThis, $pDataOject, $iKeyState, $iPoint, $piEffect) Local $pData = DllStructGetData(DllStructCreate("ptr", Ptr($pThis + $__g_iTargetObjDataOffset)), 1) Local $tData = DllStructCreate($tagTargetObjIntData, $pData) - Local $vItem = __DoDropResponse($tData, $iKeyState, $tPoint, $piEffect, $sDirText) - If @extended Then $vItem += 1 + _WinAPI_ScreenToClient_mod($tData.hTarget, $tPoint) + + __DoDropResponse($tData, $iKeyState, $tPoint, $piEffect, $sDirText) Local $oIDropTgtHelper = ObjCreateInterface($tData.pIDropTgtHelper, $sIID_IDropTargetHelper, $tagIDropTargetHelper) $oIDropTgtHelper.AddRef() - $oIDropTgtHelper.Drop($pDataOject, $tPoint, $piEffect) + $oIDropTgtHelper.Drop($pDataObject, $tPoint, $piEffect) Local $tEffect = DllStructCreate("dword iEffect", $piEffect) If $tEffect.iEffect <> $DROPEFFECT_NONE Then @@ -275,73 +324,97 @@ Func __Mthd_Drop($pThis, $pDataOject, $iKeyState, $iPoint, $piEffect) $tFormatEtc.iIndex = -1 $tFormatEtc.tymed = $TYMED_HGLOBAL - Local $oDataObject = ObjCreateInterface($pDataOject, $sIID_IDataObject, $tagIDataObject) + Local $oDataObject = ObjCreateInterface($pDataObject, $sIID_IDataObject, $tagIDataObject) Local $tStgMedium = DllStructCreate($tagSTGMEDIUM) $oDataObject.AddRef() $oDataObject.GetData($tFormatEtc, $tStgMedium) Local $asFilenames = _WinAPI_DragQueryFileEx($tStgMedium.handle) - Switch _WinAPI_GetClassName($tData.hTarget) + Switch _WinAPI_GetClassName_mod($tData.hTarget) Case $WC_LISTVIEW ; clear previously DROPHILITED listview item _GUICtrlListView_SetItemState($tData.hTarget, $iPreviousHot, 0, $LVIS_DROPHILITED) - For $i = 1 To $asFilenames[0] - ;_GUICtrlListView_InsertItem($tData.hTarget, $asFilenames[$i], $vItem) - $vItem += 1 - Next - ;_GUICtrlListView_SetInsertMark($tData.hTarget, -1) + + Local $aListItem = _GUICtrlListView_HitTest($tData.hTarget, $tPoint.X, $tPoint.Y) + Local $sItemText = _GUICtrlListView_GetItemText($tData.hTarget, $aListItem[0]) + Local $sFullPath = __TreeListExplorer_GetPath(1) & $sItemText + If StringInStr(FileGetAttrib($sFullPath), "D") Then + $sDirText = $sItemText + $sFullPath = $sFullPath + $bIsFolder = True + Else + ; get the currently selected path + $sDirPath = __TreeListExplorer_GetPath(1) + $sFullPath = $sDirPath + ; obtain folder name only for drag tooltip + Local $aPath = _StringBetween($sDirPath, "\", "\") + $sDirText = $aPath[UBound($aPath) - 1] + EndIf + ; handle case when cursor is over ListView but not on item; current directory becomes drop dir + If $sDirText = "" Then + ; get the currently selected path + $sDirPath = __TreeListExplorer_GetPath(1) + $sFullPath = $sDirPath + ; obtain folder name only for drag tooltip + Local $aPath = _StringBetween($sDirPath, "\", "\") + $sDirText = $aPath[UBound($aPath) - 1] + EndIf + + ; determine if IFileOperation needs to copy or move files + Switch $iFinalEffect + Case $DROPEFFECT_COPY + $iFlags = BitOR($FOFX_ADDUNDORECORD, $FOFX_RECYCLEONDELETE, $FOFX_NOCOPYHOOKS) + $sAction = "CopyItems" + ConsoleWrite("copy took place on listview" & @CRLF) + _IFileOperationFile($pDataObject, $sFullPath, $sAction, $iFlags) + __TreeListExplorer_Reload(1) + Case $DROPEFFECT_MOVE + $iFlags = BitOR($FOFX_ADDUNDORECORD, $FOFX_RECYCLEONDELETE, $FOFX_NOCOPYHOOKS) + $sAction = "MoveItems" + ConsoleWrite("move took place on listview" & @CRLF) + _IFileOperationFile($pDataObject, $sFullPath, $sAction, $iFlags) + ; send response back to source to indicate that file move has been handled + $tEffect.iEffect = $DROPEFFECT_NONE + __SetPerformedDropEffect($pDataObject, $DROPEFFECT_NONE) + __TreeListExplorer_Reload(1) + EndSwitch Case $WC_TREEVIEW - ; restore original treeview selection if cursor leaves treeview + ; restore original treeview selection _GUICtrlTreeView_SelectItem($tData.hTarget, $hTreeOrig) - Local $hInsAfter = _GUICtrlTreeView_GetPrev($tData.hTarget, $vItem) - If Not $hInsAfter Then $hInsAfter = $TVI_FIRST - For $i = 1 To $asFilenames[0] - ;$hInsAfter = _GUICtrlTreeView_InsertItem($tData.hTarget, $asFilenames[$i], 0, $hInsAfter) - Next - ;_GUICtrlTreeView_SetInsertMark($tData.hTarget, 0) + + ; full treeview drop path is most recently DROPHILITED item + Local $sFullPath =$sDropTV + + ; determine if IFileOperation needs to copy or move files + Switch $iFinalEffect + Case $DROPEFFECT_COPY + $iFlags = BitOR($FOFX_ADDUNDORECORD, $FOFX_RECYCLEONDELETE, $FOFX_NOCOPYHOOKS) + $sAction = "CopyItems" + ConsoleWrite("copy took place on treeview" & @CRLF) + _IFileOperationFile($pDataObject, $sFullPath, $sAction, $iFlags) + __TreeListExplorer_Reload(1) + Case $DROPEFFECT_MOVE + $iFlags = BitOR($FOFX_ADDUNDORECORD, $FOFX_RECYCLEONDELETE, $FOFX_NOCOPYHOOKS) + $sAction = "MoveItems" + ConsoleWrite("move took place on treeview" & @CRLF) + _IFileOperationFile($pDataObject, $sFullPath, $sAction, $iFlags) + ; send response back to source to indicate that file move has been handled + $tEffect.iEffect = $DROPEFFECT_NONE + __SetPerformedDropEffect($pDataObject, $DROPEFFECT_NONE) + __TreeListExplorer_Reload(1) + EndSwitch + EndSwitch EndIf - ;__SetPerformedDropEffect($pDataOject, $piEffect) - $tData.bAcceptDrop = False $tData.pDataObject = 0 Return $S_OK EndFunc ;==>__Mthd_Drop -Func __DoInsertMark($hTarget, $tPoint) - Return -EndFunc - -Func __DoInsertMark_orig($hTarget, $tPoint) - Local $vItem = -1, $bAfter = False - _WinAPI_ScreenToClient($hTarget, $tPoint) - - Switch _WinAPI_GetClassName($hTarget) - Case $WC_LISTVIEW - Local $tLVINSERTMARK = DllStructCreate($tagLVINSERTMARK) - $tLVINSERTMARK.Size = DllStructGetSize($tLVINSERTMARK) - If _SendMessage($hTarget, $LVM_INSERTMARKHITTEST, $tPoint, $tLVINSERTMARK, 0, "struct*", "struct*") Then - If _SendMessage($hTarget, $LVM_SETINSERTMARK, 0, $tLVINSERTMARK, 0, "wparam", "struct*") Then $vItem = $tLVINSERTMARK.Item - $bAfter = BitAND($tLVINSERTMARK.Flags, $LVIM_AFTER) - EndIf - - Case $WC_TREEVIEW - Local $tTVHITTESTINFO = DllStructCreate($tagTVHITTESTINFO) - $tTVHITTESTINFO.X = $tPoint.X - $tTVHITTESTINFO.Y = $tPoint.Y - If _SendMessage($hTarget, $TVM_HITTEST, $tPoint, $tTVHITTESTINFO, 0, "struct*", "struct*") Then - If _SendMessage($hTarget, $TVM_SETINSERTMARK, 0, $tTVHITTESTINFO.Item, 0, "wparam", "handle") Then $vItem = $tTVHITTESTINFO.Item - EndIf - - EndSwitch - - Return SetExtended($bAfter, $vItem) -EndFunc - Func __SetDropDescription($pDataObject, $iType, $sMessage = "", $sInsert = "") Local $tFormatEtc = DllStructCreate($tagFORMATETC) $tFormatEtc.cfFormat = _ClipBoard_RegisterFormat($CFSTR_DROPDESCRIPTION) @@ -367,52 +440,45 @@ Func __SetDropDescription($pDataObject, $iType, $sMessage = "", $sInsert = "") Local $oDataObj = ObjCreateInterface($pDataObject, $sIID_IDataObject, $tagIDataObject) $oDataObj.AddRef() $oDataObj.SetData($tFormatEtc, $tStgMedium, 1) -EndFunc +EndFunc ;==>__SetDropDescription -Func __DoDropResponse($tData, $iKeyState, $tPoint, $piEffect, $sDirText) +Func __DoDropResponse($tData, $iKeyState, $tPoint, $piEffect, $sDirText, $bIsSameDrive = False, $bIsSameFolder = False) #forceref $tData, $iKeyState, $tPoint, $piEffect - Local $vItem, $bAfter - Local $iRetEffect = $DROPEFFECT_NONE - Local $tEffect = DllStructCreate("dword iEffect", $piEffect) - - ;Only Accept copy ops (will expand this at some point!) - - If $tData.bAcceptDrop Then - If BitAND($tEffect.iEffect, $DROPEFFECT_MOVE) Then $iRetEffect = $DROPEFFECT_MOVE - If BitAND($tEffect.iEffect, $DROPEFFECT_COPY) Then - If BitAND($iKeyState, $MK_CONTROL) Or $iRetEffect = $DROPEFFECT_NONE Then - $iRetEffect = $DROPEFFECT_COPY - EndIf - EndIf - If BitAND($tEffect.iEffect, $DROPEFFECT_LINK) Then - If BitAND($iKeyState, $MK_ALT) Or $iRetEffect = $DROPEFFECT_NONE Then - $iRetEffect = $DROPEFFECT_LINK - EndIf - EndIf - EndIf - - $tEffect.iEffect = $iRetEffect - If $tEffect.iEffect <> $DROPEFFECT_NONE Then - ;$vItem = __DoInsertMark($tData.hTarget, $tPoint) - $bAfter = @extended - Else - Switch _WinAPI_GetClassName($tData.hTarget) - Case $WC_LISTVIEW - ;_GUICtrlListView_SetInsertMark($tData.hTarget, -1) - $vItem = -1 - - Case $WC_TREEVIEW - ;_GUICtrlTreeView_SetInsertMark($tData.hTarget, 0) - $vItem = 0 - - EndSwitch - EndIf + Local $iRetEffect = $DROPEFFECT_NONE, $iReqOp + Local $tEffect = DllStructCreate("dword iEffect", $piEffect) + + ;See what the user is asking for based on key modifiers. + If $tData.bAcceptDrop Then + Switch BitAND($iKeyState, BitOR($MK_CONTROL, $MK_ALT, $MK_SHIFT)) + Case BitOr($MK_CONTROL, $MK_ALT), 0 + $iReqOp = $DROPEFFECT_MOVE + Case $MK_CONTROL + $iReqOp = $DROPEFFECT_COPY + Case BitOR($MK_CONTROL, $MK_SHIFT), $MK_ALT + $iReqOp = $DROPEFFECT_LINK + EndSwitch + + ;If move is legally an option + If BitAND($tEffect.iEffect, $DROPEFFECT_MOVE) Then + If $iReqOp = $DROPEFFECT_MOVE And $bIsSameDrive Then $iRetEffect = $DROPEFFECT_MOVE + EndIf + ;If copy is legally an option + If BitAND($tEffect.iEffect, $DROPEFFECT_COPY) Then + If $iReqOp = $DROPEFFECT_COPY Or $iRetEffect = $DROPEFFECT_NONE Then $iRetEffect = $DROPEFFECT_COPY + EndIf + ;If link is legally an option + If BitAND($tEffect.iEffect, $DROPEFFECT_LINK) Then + If $iReqOp = $DROPEFFECT_LINK Or $iRetEffect = $DROPEFFECT_NONE Then $iRetEffect = $DROPEFFECT_LINK + EndIf + If $bIsSameFolder Then $iRetEffect = $DROPEFFECT_NONE + EndIf + $tEffect.iEffect = $iRetEffect Switch $tEffect.iEffect Case $DROPEFFECT_NONE - __SetDropDescription($tData.pDataObject, $DROPIMAGE_NONE, "No Op %1", $sDirText) + __SetDropDescription($tData.pDataObject, $DROPIMAGE_NOIMAGE, "", "") Case $DROPEFFECT_LINK __SetDropDescription($tData.pDataObject, $DROPIMAGE_LINK, "Link to %1", $sDirText) @@ -422,11 +488,10 @@ Func __DoDropResponse($tData, $iKeyState, $tPoint, $piEffect, $sDirText) Case $DROPEFFECT_MOVE __SetDropDescription($tData.pDataObject, $DROPIMAGE_MOVE, "Move to %1", $sDirText) - EndSwitch - Return SetExtended($bAfter, $vItem) -EndFunc + Return +EndFunc ;==>__DoDropResponse Func __SetPerformedDropEffect($pDataObject, $iDropEffect) Local $tFormatEtc = DllStructCreate($tagFORMATETC) @@ -450,4 +515,4 @@ Func __SetPerformedDropEffect($pDataObject, $iDropEffect) Local $oDataObj = ObjCreateInterface($pDataObject, $sIID_IDataObject, $tagIDataObject) $oDataObj.AddRef() $oDataObj.SetData($tFormatEtc, $tStgMedium, 1) -EndFunc +EndFunc ;==>__SetPerformedDropEffect diff --git a/lib/IFileOperation.au3 b/lib/IFileOperation.au3 new file mode 100644 index 0000000..b907603 --- /dev/null +++ b/lib/IFileOperation.au3 @@ -0,0 +1,125 @@ +#include-once + +#include + +; originally from Danyfirex + +Global Const $FOFX_ADDUNDORECORD = 0x20000000 +Global Const $FOFX_NOSKIPJUNCTIONS = 0x00010000 +Global Const $FOFX_PREFERHARDLINK = 0x00020000 +Global Const $FOFX_SHOWELEVATIONPROMPT = 0x00040000 +Global Const $FOFX_EARLYFAILURE = 0x00100000 +Global Const $FOFX_PRESERVEFILEEXTENSIONS = 0x00200000 +Global Const $FOFX_KEEPNEWERFILE = 0x00400000 +Global Const $FOFX_NOCOPYHOOKS = 0x00800000 +Global Const $FOFX_NOMINIMIZEBOX = 0x01000000 +Global Const $FOFX_MOVEACLSACROSSVOLUMES = 0x02000000 +Global Const $FOFX_DONTDISPLAYSOURCEPATH = 0x04000000 +Global Const $FOFX_DONTDISPLAYDESTPATH = 0x08000000 +Global Const $FOFX_RECYCLEONDELETE = 0x00080000 +Global Const $FOFX_REQUIREELEVATION = 0x10000000 +Global Const $FOFX_COPYASDOWNLOAD = 0x40000000 +Global Const $FOFX_DONTDISPLAYLOCATIONS = 0x80000000 + + +Global Const $IID_IShellItem = "{43826d1e-e718-42ee-bc55-a1e261c37bfe}" +Global Const $dtag_IShellItem = _ + "BindToHandler hresult(ptr;clsid;clsid;ptr*);" & _ + "GetParent hresult(ptr*);" & _ + "GetDisplayName hresult(int;ptr*);" & _ + "GetAttributes hresult(int;int*);" & _ + "Compare hresult(ptr;int;int*);" + +Global Const $IID_IShellItemArray = "{b63ea76d-1f85-456f-a19c-48159efa858b}" +Global Const $dtagIShellItemArray = "BindToHandler hresult();GetPropertyStore hresult();" & _ + "GetPropertyDescriptionList hresult();GetAttributes hresult();GetCount hresult(dword*);" & _ + "GetItemAt hresult();EnumItems hresult();" + +Global Const $BHID_EnumItems = "{94F60519-2850-4924-AA5A-D15E84868039}" +Global Const $IID_IEnumShellItems = "{70629033-e363-4a28-a567-0db78006e6d7}" +Global Const $dtagIEnumShellItems = "Next hresult(ulong;ptr*;ulong*);Skip hresult();Reset hresult();Clone hresult();" + + +Global Const $CLSID_IFileOperation = "{3AD05575-8857-4850-9277-11B85BDB8E09}" +Global Const $IID_IFileOperation = "{947AAB5F-0A5C-4C13-B4D6-4BF7836FC9F8}" +Global Const $dtagIFileOperation = "Advise hresult(ptr;dword*);" & _ + "Unadvise hresult(dword);" & _ + "SetOperationFlags hresult(dword);" & _ + "SetProgressMessage hresult(wstr);" & _ + "SetProgressDialog hresult(ptr);" & _ + "SetProperties hresult(ptr);" & _ + "SetOwnerWindow hresult(hwnd);" & _ + "ApplyPropertiesToItem hresult(ptr);" & _ + "ApplyPropertiesToItems hresult(ptr);" & _ + "RenameItem hresult(ptr;wstr;ptr);" & _ + "RenameItems hresult(ptr;wstr);" & _ + "MoveItem hresult(ptr;ptr;wstr;ptr);" & _ + "MoveItems hresult(ptr;ptr);" & _ + "CopyItem hresult(ptr;ptr;wstr;ptr);" & _ + "CopyItems hresult(ptr;ptr);" & _ + "DeleteItem hresult(ptr;ptr);" & _ + "DeleteItems hresult(ptr);" & _ + "NewItem hresult(ptr;dword;wstr;wstr;ptr);" & _ + "PerformOperations hresult();" & _ + "GetAnyOperationsAborted hresult(ptr*);" + +; Local $iFlags = BitOR($FOF_NOERRORUI, $FOFX_KEEPNEWERFILE, $FOFX_NOCOPYHOOKS, $FOF_NOCONFIRMATION) +; FOFX_ADDUNDORECORD (preferred) +; FOFX_RECYCLEONDELETE +; FOFX_NOCOPYHOOKS + +;Local $sAction = "CopyItems" +;Local $sAction = "MoveItems" + +;_IFileOperationFile($pDataObj, $sPathTo, $sAction, $iFlags) + +Func _IFileOperationFile($pDataObj, $sPathTo, $sAction, $iFlags = 0) + + If Not FileExists($sPathTo) Then + DirCreate($sPathTo) + EndIf + + + Local $tIIDIShellItem = CLSIDFromString($IID_IShellItem) + Local $tIIDIShellItemArray = CLSIDFromString($IID_IShellItemArray) + + + Local $oIFileOperation = ObjCreateInterface($CLSID_IFileOperation, $IID_IFileOperation, $dtagIFileOperation) + If Not IsObj($oIFileOperation) Then Return SetError(2, 0, False) + + Local $pIShellItemTo = 0 + + _SHCreateItemFromParsingName($sPathTo, 0, DllStructGetPtr($tIIDIShellItem), $pIShellItemTo) + + + If Not $pIShellItemTo Then Return SetError(3, 0, False) + + $oIFileOperation.SetOperationFlags($iFlags) + + Switch $sAction + Case "CopyItems" + $oIFileOperation.CopyItems($pDataObj, $pIShellItemTo) + Case "MoveItems" + $oIFileOperation.MoveItems($pDataObj, $pIShellItemTo) + EndSwitch + + Return $oIFileOperation.PerformOperations() = 0 + +EndFunc ;==>_IFileOperationFile + + +Func _SHCreateItemFromParsingName($szPath, $pbc, $riid, ByRef $pv) + Local $aRes = DllCall("shell32.dll", "long", "SHCreateItemFromParsingName", "wstr", $szPath, "ptr", $pbc, "ptr", $riid, "ptr*", 0) + If @error Then Return SetError(1, 0, @error) + $pv = $aRes[4] + Return $aRes[0] +EndFunc ;==>_SHCreateItemFromParsingName + + +Func CLSIDFromString($sString) + Local $tCLSID = DllStructCreate("dword;word;word;byte[8]") + Local $aRet = DllCall("Ole32.dll", "long", "CLSIDFromString", "wstr", $sString, "ptr", DllStructGetPtr($tCLSID)) + If @error Then Return SetError(1, 0, @error) + If $aRet[0] <> 0 Then Return SetError(2, $aRet[0], 0) + Return $tCLSID +EndFunc ;==>CLSIDFromString diff --git a/lib/SharedFunctions.au3 b/lib/SharedFunctions.au3 new file mode 100644 index 0000000..4e09bff --- /dev/null +++ b/lib/SharedFunctions.au3 @@ -0,0 +1,229 @@ +#include-once + +#include +#include +#include + +Global $hKernel32, $hGdi32, $hUser32, $hShlwapi, $hShell32 + +Func __Timer_QueryPerformanceFrequency_mod() + Local $aCall = DllCall($hKernel32, "bool", "QueryPerformanceFrequency", "int64*", 0) + If @error Then Return SetError(@error, @extended, 0) + Return SetExtended($aCall[0], $aCall[1]) +EndFunc ;==>__Timer_QueryPerformanceFrequency_mod + +Func __Timer_QueryPerformanceCounter_mod() + Local $aCall = DllCall($hKernel32, "bool", "QueryPerformanceCounter", "int64*", 0) + If @error Then Return SetError(@error, @extended, -1) + Return SetExtended($aCall[0], $aCall[1]) +EndFunc ;==>__Timer_QueryPerformanceCounter_mod + +Func _Timer_Diff_mod($iTimeStamp) + Return 1000 * (__Timer_QueryPerformanceCounter_mod() - $iTimeStamp) / __Timer_QueryPerformanceFrequency_mod() +EndFunc ;==>_Timer_Diff_mod + +Func _Timer_Init_mod() + Return __Timer_QueryPerformanceCounter_mod() +EndFunc ;==>_Timer_Init_mod + +Func _WinAPI_ReleaseDC_mod($hWnd, $hDC) + Local $aCall = DllCall($hUser32, "int", "ReleaseDC", "hwnd", $hWnd, "handle", $hDC) + If @error Then Return SetError(@error, @extended, False) + + Return $aCall[0] +EndFunc ;==>_WinAPI_ReleaseDC_mod + +Func _WinAPI_GetDCEx_mod($hWnd, $hRgn, $iFlags) + Local $aCall = DllCall($hUser32, 'handle', 'GetDCEx', 'hwnd', $hWnd, 'handle', $hRgn, 'dword', $iFlags) + If @error Then Return SetError(@error, @extended, 0) + + Return $aCall[0] +EndFunc ;==>_WinAPI_GetDCEx_mod + +Func _WinAPI_CreateRectRgn_mod($iLeftRect, $iTopRect, $iRightRect, $iBottomRect) + Local $aCall = DllCall($hGdi32, "handle", "CreateRectRgn", "int", $iLeftRect, "int", $iTopRect, "int", $iRightRect, _ + "int", $iBottomRect) + If @error Then Return SetError(@error, @extended, 0) + + Return $aCall[0] +EndFunc ;==>_WinAPI_CreateRectRgn_mod + +Func _WinAPI_OffsetRect_mod(ByRef $tRECT, $iDX, $iDY) + Local $aCall = DllCall($hUser32, 'bool', 'OffsetRect', 'struct*', $tRECT, 'int', $iDX, 'int', $iDY) + If @error Then Return SetError(@error, @extended, 0) + + Return $aCall[0] +EndFunc ;==>_WinAPI_OffsetRect_mod + +Func _WinAPI_GetWindowRect_mod($hWnd) + Local $tRECT = DllStructCreate($tagRECT) + Local $aCall = DllCall($hUser32, "bool", "GetWindowRect", "hwnd", $hWnd, "struct*", $tRECT) + If @error Or Not $aCall[0] Then Return SetError(@error + 10, @extended, 0) + + Return $tRECT +EndFunc ;==>_WinAPI_GetWindowRect_mod + +Func _WinAPI_ShellGetFileInfo_mod($sFilePath, $iFlags, $iAttributes, ByRef $tSHFILEINFO) + Local $aCall = DllCall($hShell32, 'dword_ptr', 'SHGetFileInfoW', 'wstr', $sFilePath, 'dword', $iAttributes, _ + 'struct*', $tSHFILEINFO, 'uint', DllStructGetSize($tSHFILEINFO), 'uint', $iFlags) + If @error Then Return SetError(@error, @extended, 0) + + Return $aCall[0] +EndFunc ;==>_WinAPI_ShellGetFileInfo_mod + +Func _WinAPI_GetClientRect_mod($hWnd) + Local $tRECT = DllStructCreate($tagRECT) + Local $aCall = DllCall($hUser32, "bool", "GetClientRect", "hwnd", $hWnd, "struct*", $tRECT) + If @error Or Not $aCall[0] Then Return SetError(@error + 10, @extended, 0) + + Return $tRECT +EndFunc ;==>_WinAPI_GetClientRect_mod + +Func _WinAPI_GetWindowLong_mod($hWnd, $iIndex) + Local $sFuncName = "GetWindowLongW" + If @AutoItX64 Then $sFuncName = "GetWindowLongPtrW" + Local $aCall = DllCall($hUser32, "long_ptr", $sFuncName, "hwnd", $hWnd, "int", $iIndex) + If @error Or Not $aCall[0] Then Return SetError(@error + 10, @extended, 0) + + Return $aCall[0] +EndFunc ;==>_WinAPI_GetWindowLong_mod + +Func _WinAPI_DefWindowProc_mod($hWnd, $iMsg, $wParam, $lParam) + Local $aCall = DllCall($hUser32, "lresult", "DefWindowProc", "hwnd", $hWnd, "uint", $iMsg, "wparam", $wParam, _ + "lparam", $lParam) + If @error Then Return SetError(@error, @extended, 0) + + Return $aCall[0] +EndFunc ;==>_WinAPI_DefWindowProc_mod + +Func _WinAPI_SetLastError_mod($iErrorCode, Const $_iCallerError = @error, Const $_iCallerExtended = @extended) + DllCall($hKernel32, "none", "SetLastError", "dword", $iErrorCode) + Return SetError($_iCallerError, $_iCallerExtended, Null) +EndFunc ;==>_WinAPI_SetLastError_mod + +Func _WinAPI_SetWindowLong_mod($hWnd, $iIndex, $iValue) + _WinAPI_SetLastError_mod(0) ; as suggested in MSDN + Local $sFuncName = "SetWindowLongW" + If @AutoItX64 Then $sFuncName = "SetWindowLongPtrW" + Local $aCall = DllCall($hUser32, "long_ptr", $sFuncName, "hwnd", $hWnd, "int", $iIndex, "long_ptr", $iValue) + If @error Then Return SetError(@error, @extended, 0) + + Return $aCall[0] +EndFunc ;==>_WinAPI_SetWindowLong_mod + +Func _WinAPI_SetWindowPos_mod($hWnd, $hAfter, $iX, $iY, $iCX, $iCY, $iFlags) + Local $aCall = DllCall($hUser32, "bool", "SetWindowPos", "hwnd", $hWnd, "hwnd", $hAfter, "int", $iX, "int", $iY, _ + "int", $iCX, "int", $iCY, "uint", $iFlags) + If @error Then Return SetError(@error, @extended, False) + + Return $aCall[0] +EndFunc ;==>_WinAPI_SetWindowPos_mod + +Func _WinAPI_DrawText_mod($hDC, $sText, ByRef $tRECT, $iFlags) + Local $aCall = DllCall($hUser32, "int", "DrawTextW", "handle", $hDC, "wstr", $sText, "int", -1, "struct*", $tRECT, _ + "uint", $iFlags) + If @error Then Return SetError(@error, @extended, 0) + + Return $aCall[0] +EndFunc ;==>_WinAPI_DrawText_mod + +Func _WinAPI_SetBkColor_mod($hDC, $iColor) + Local $aCall = DllCall($hGdi32, "INT", "SetBkColor", "handle", $hDC, "INT", $iColor) + If @error Then Return SetError(@error, @extended, -1) + + Return $aCall[0] +EndFunc ;==>_WinAPI_SetBkColor_mod + +Func _WinAPI_DeleteObject_mod($hObject) + Local $aCall = DllCall($hGdi32, "bool", "DeleteObject", "handle", $hObject) + If @error Then Return SetError(@error, @extended, False) + + Return $aCall[0] +EndFunc ;==>_WinAPI_DeleteObject_mod + +Func _WinAPI_InflateRect_mod(ByRef $tRECT, $iDX, $iDY) + Local $aCall = DllCall($hUser32, 'bool', 'InflateRect', 'struct*', $tRECT, 'int', $iDX, 'int', $iDY) + If @error Then Return SetError(@error, @extended, False) + + Return $aCall[0] +EndFunc ;==>_WinAPI_InflateRect_mod + +Func _WinAPI_FillRect_mod($hDC, $tRECT, $hBrush) + Local $aCall + If IsPtr($hBrush) Then + $aCall = DllCall($hUser32, "int", "FillRect", "handle", $hDC, "struct*", $tRECT, "handle", $hBrush) + Else + $aCall = DllCall($hUser32, "int", "FillRect", "handle", $hDC, "struct*", $tRECT, "dword_ptr", $hBrush) + EndIf + If @error Then Return SetError(@error, @extended, False) + + Return $aCall[0] +EndFunc ;==>_WinAPI_FillRect_mod + +Func _WinAPI_CreateSolidBrush_mod($iColor) + Local $aCall = DllCall($hGdi32, "handle", "CreateSolidBrush", "INT", $iColor) + If @error Then Return SetError(@error, @extended, 0) + + Return $aCall[0] +EndFunc ;==>_WinAPI_CreateSolidBrush_mod + +Func _WinAPI_GetClassName_mod($hWnd) + If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd) + Local $aCall = DllCall($hUser32, "int", "GetClassNameW", "hwnd", $hWnd, "wstr", "", "int", 4096) + If @error Or Not $aCall[0] Then Return SetError(@error, @extended, '') + + Return SetExtended($aCall[0], $aCall[2]) +EndFunc ;==>_WinAPI_GetClassName_mod + +Func _WinAPI_SetTextColor_mod($hDC, $iColor) + Local $aCall = DllCall($hGdi32, "INT", "SetTextColor", "handle", $hDC, "INT", $iColor) + If @error Then Return SetError(@error, @extended, -1) + + Return $aCall[0] +EndFunc ;==>_WinAPI_SetTextColor_mod + +Func _WinAPI_PathIsRoot_mod($sFilePath) + Local $aCall = DllCall($hShlwapi, 'bool', 'PathIsRootW', 'wstr', $sFilePath & "\") + If @error Then Return SetError(@error, @extended, False) + + Return $aCall[0] +EndFunc ;==>_WinAPI_PathIsRoot_mod + +Func _WinAPI_ScreenToClient_mod($hWnd, ByRef $tPoint) + Local $aCall = DllCall($hUser32, "bool", "ScreenToClient", "hwnd", $hWnd, "struct*", $tPoint) + If @error Then Return SetError(@error, @extended, False) + + Return $aCall[0] +EndFunc ;==>_WinAPI_ScreenToClient_mod + +Func TreeItemToPath($hTree, $hItem, $bArray = False) + Local $sPath = StringReplace(_GUICtrlTreeView_GetTree($hTree, $hItem), "|", "\") + $sPath = StringTrimLeft($sPath, StringInStr($sPath, "\")) ; remove this pc at the beginning + If StringInStr(FileGetAttrib($sPath), "D") Then $sPath &= "\" ; let folders end with \ + If $bArray Then + Local $aPath = _ArrayFromString($sPath) + _ArrayInsert($aPath, 0, 1) + Return $aPath + EndIf + Return $sPath +EndFunc ;==>TreeItemToPath + +Func _PathSplit_mod($sFilePath) + Local $sDrive = "", $sDir = "", $sFileName = "", $sExtension = "" + Local $aArray = StringRegExp($sFilePath, "^\h*((?:\\\\\?\\)*(\\\\[^\?\/\\]+|[A-Za-z]:)?(.*[\/\\]\h*)?((?:[^\.\/\\]|(?(?=\.[^\/\\]*\.)\.))*)?([^\/\\]*))$", $STR_REGEXPARRAYMATCH) + If @error Then ; This error should never happen. + ReDim $aArray[5] + $aArray[$PATH_ORIGINAL] = $sFilePath + EndIf + $sDrive = $aArray[$PATH_DRIVE] + If StringLeft($aArray[$PATH_DIRECTORY], 1) == "/" Then + $sDir = StringRegExpReplace($aArray[$PATH_DIRECTORY], "\h*[\/\\]+\h*", "\/") + Else + $sDir = StringRegExpReplace($aArray[$PATH_DIRECTORY], "\h*[\/\\]+\h*", "\\") + EndIf + $aArray[$PATH_DIRECTORY] = $sDir + $sFileName = $aArray[$PATH_FILENAME] + $sExtension = $aArray[$PATH_EXTENSION] + + Return $aArray +EndFunc ;==>_PathSplit_mod diff --git a/src/main.au3 b/src/main.au3 index 87ee745..db0dc96 100644 --- a/src/main.au3 +++ b/src/main.au3 @@ -11,12 +11,20 @@ #include #include +Global $hKernel32 = DllOpen('kernel32.dll') +Global $hGdi32 = DllOpen('gdi32.dll') +Global $hUser32 = DllOpen('user32.dll') +Global $hShlwapi = DllOpen('shlwapi.dll') +Global $hShell32 = DllOpen('shell32.dll') + +#include "../lib/SharedFunctions.au3" #include "../lib/GUIFrame_WBD_Mod.au3" #include "../lib/History.au3" #include "../lib/TreeListExplorer.au3" #include "../lib/ProjectConstants.au3" #include "../lib/DropSourceObject.au3" #include "../lib/DropTargetObject.au3" +;#include "../lib/IFileOperation.au3" ; CREDITS: ; Kanashius TreeListExplorer UDF @@ -32,6 +40,7 @@ ; DonChunior Code review, bug fixes and refactoring ; MattyD Drag and drop code ; jugador ListView multiple item drag and drop +; Danyfirex IFileOperation code Global $sVersion = "0.4.0 - 2026-01-22" @@ -67,12 +76,6 @@ Global $aPosTip, $iOldaPos0, $iOldaPos1 ; force light mode ;$isDarkMode = False -Global $hKernel32 = DllOpen('kernel32.dll') -Global $hGdi32 = DllOpen('gdi32.dll') -Global $hUser32 = DllOpen('user32.dll') -Global $hShlwapi = DllOpen('shlwapi.dll') -Global $hShell32 = DllOpen('shell32.dll') - ; get Windows build Global $iOSBuild = @OSBuild Global $iRevision = RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "UBR") @@ -803,11 +806,16 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) Next Local $pDataObj, $pDropSource - $pDataObj = GetDataObjectOfFiles($hWnd, $aItems) + ;$pDataObj = GetDataObjectOfFiles($hWnd, $aItems) ; MattyD function + + _ArrayDelete($aItems, 0) ; only needed for GetDataObjectOfFile_B + $pDataObj = GetDataObjectOfFile_B($aItems) ; jugador function + ;Create an IDropSource to handle our end of the drag/drop operation. $pDropSource = CreateDropSource() - _SHDoDragDrop($pDataObj, $pDropSource, BitOR($DROPEFFECT_COPY, $DROPEFFECT_LINK)) + _SHDoDragDrop($pDataObj, $pDropSource, BitOR($DROPEFFECT_MOVE, $DROPEFFECT_COPY, $DROPEFFECT_LINK)) + ;__TreeListExplorer_Reload($hTLESystem) DestroyDropSource($pDropSource) _Release($pDataObj) @@ -870,7 +878,7 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) EndSwitch Case $g_hTreeView Switch $iCode - Case $TVN_BEGINDRAGA, $TVN_BEGINDRAGW + Case $TVN_BEGINDRAGW, $TVN_BEGINRDRAGW Local $tTree = DllStructCreate($tagNMTREEVIEW, $lParam) Local $hDragItem = DllStructGetData($tTree, "NewhItem") $hTreeItemOrig = _GUICtrlTreeView_GetSelection($g_hTreeView) @@ -889,7 +897,8 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) If Not @error Then ;We allow DROPEFFECT_COPY and DROPEFFECT_LINK. We don't want to DROPEFFECT_MOVE the file!! ;DoDragDrop($pDataObj, $pDropSource, BitOR($DROPEFFECT_COPY, $DROPEFFECT_LINK)) - _SHDoDragDrop($pDataObj, $pDropSource, BitOR($DROPEFFECT_COPY, $DROPEFFECT_LINK)) + _SHDoDragDrop($pDataObj, $pDropSource, BitOR($DROPEFFECT_MOVE, $DROPEFFECT_COPY, $DROPEFFECT_LINK)) + ;__TreeListExplorer_Reload($hTLESystem) ;Operation done, destroy our drop source. (Can't just IUnknown_Release() this one!) DestroyDropSource($pDropSource) @@ -1135,182 +1144,6 @@ Func _InitDarkSizebox() $g_hDots = CreateDots($g_iHeight, $g_iHeight, 0x00000000 + $iBackColorDef, 0xFF000000 + 0xBFBFBF) EndFunc ;==>_InitDarkSizebox -Func __Timer_QueryPerformanceFrequency_mod() - Local $aCall = DllCall($hKernel32, "bool", "QueryPerformanceFrequency", "int64*", 0) - If @error Then Return SetError(@error, @extended, 0) - Return SetExtended($aCall[0], $aCall[1]) -EndFunc ;==>__Timer_QueryPerformanceFrequency_mod - -Func __Timer_QueryPerformanceCounter_mod() - Local $aCall = DllCall($hKernel32, "bool", "QueryPerformanceCounter", "int64*", 0) - If @error Then Return SetError(@error, @extended, -1) - Return SetExtended($aCall[0], $aCall[1]) -EndFunc ;==>__Timer_QueryPerformanceCounter_mod - -Func _Timer_Diff_mod($iTimeStamp) - Return 1000 * (__Timer_QueryPerformanceCounter_mod() - $iTimeStamp) / __Timer_QueryPerformanceFrequency_mod() -EndFunc ;==>_Timer_Diff_mod - -Func _Timer_Init_mod() - Return __Timer_QueryPerformanceCounter_mod() -EndFunc ;==>_Timer_Init_mod - -Func _WinAPI_ReleaseDC_mod($hWnd, $hDC) - Local $aCall = DllCall($hUser32, "int", "ReleaseDC", "hwnd", $hWnd, "handle", $hDC) - If @error Then Return SetError(@error, @extended, False) - - Return $aCall[0] -EndFunc ;==>_WinAPI_ReleaseDC_mod - -Func _WinAPI_GetDCEx_mod($hWnd, $hRgn, $iFlags) - Local $aCall = DllCall($hUser32, 'handle', 'GetDCEx', 'hwnd', $hWnd, 'handle', $hRgn, 'dword', $iFlags) - If @error Then Return SetError(@error, @extended, 0) - - Return $aCall[0] -EndFunc ;==>_WinAPI_GetDCEx_mod - -Func _WinAPI_CreateRectRgn_mod($iLeftRect, $iTopRect, $iRightRect, $iBottomRect) - Local $aCall = DllCall($hGdi32, "handle", "CreateRectRgn", "int", $iLeftRect, "int", $iTopRect, "int", $iRightRect, _ - "int", $iBottomRect) - If @error Then Return SetError(@error, @extended, 0) - - Return $aCall[0] -EndFunc ;==>_WinAPI_CreateRectRgn_mod - -Func _WinAPI_OffsetRect_mod(ByRef $tRECT, $iDX, $iDY) - Local $aCall = DllCall($hUser32, 'bool', 'OffsetRect', 'struct*', $tRECT, 'int', $iDX, 'int', $iDY) - If @error Then Return SetError(@error, @extended, 0) - - Return $aCall[0] -EndFunc ;==>_WinAPI_OffsetRect_mod - -Func _WinAPI_GetWindowRect_mod($hWnd) - Local $tRECT = DllStructCreate($tagRECT) - Local $aCall = DllCall($hUser32, "bool", "GetWindowRect", "hwnd", $hWnd, "struct*", $tRECT) - If @error Or Not $aCall[0] Then Return SetError(@error + 10, @extended, 0) - - Return $tRECT -EndFunc ;==>_WinAPI_GetWindowRect_mod - -Func _WinAPI_ShellGetFileInfo_mod($sFilePath, $iFlags, $iAttributes, ByRef $tSHFILEINFO) - Local $aCall = DllCall($hShell32, 'dword_ptr', 'SHGetFileInfoW', 'wstr', $sFilePath, 'dword', $iAttributes, _ - 'struct*', $tSHFILEINFO, 'uint', DllStructGetSize($tSHFILEINFO), 'uint', $iFlags) - If @error Then Return SetError(@error, @extended, 0) - - Return $aCall[0] -EndFunc ;==>_WinAPI_ShellGetFileInfo_mod - -Func _WinAPI_GetClientRect_mod($hWnd) - Local $tRECT = DllStructCreate($tagRECT) - Local $aCall = DllCall($hUser32, "bool", "GetClientRect", "hwnd", $hWnd, "struct*", $tRECT) - If @error Or Not $aCall[0] Then Return SetError(@error + 10, @extended, 0) - - Return $tRECT -EndFunc ;==>_WinAPI_GetClientRect_mod - -Func _WinAPI_GetWindowLong_mod($hWnd, $iIndex) - Local $sFuncName = "GetWindowLongW" - If @AutoItX64 Then $sFuncName = "GetWindowLongPtrW" - Local $aCall = DllCall($hUser32, "long_ptr", $sFuncName, "hwnd", $hWnd, "int", $iIndex) - If @error Or Not $aCall[0] Then Return SetError(@error + 10, @extended, 0) - - Return $aCall[0] -EndFunc ;==>_WinAPI_GetWindowLong_mod - -Func _WinAPI_DefWindowProc_mod($hWnd, $iMsg, $wParam, $lParam) - Local $aCall = DllCall($hUser32, "lresult", "DefWindowProc", "hwnd", $hWnd, "uint", $iMsg, "wparam", $wParam, _ - "lparam", $lParam) - If @error Then Return SetError(@error, @extended, 0) - - Return $aCall[0] -EndFunc ;==>_WinAPI_DefWindowProc_mod - -Func _WinAPI_SetLastError_mod($iErrorCode, Const $_iCallerError = @error, Const $_iCallerExtended = @extended) - DllCall($hKernel32, "none", "SetLastError", "dword", $iErrorCode) - Return SetError($_iCallerError, $_iCallerExtended, Null) -EndFunc ;==>_WinAPI_SetLastError_mod - -Func _WinAPI_SetWindowLong_mod($hWnd, $iIndex, $iValue) - _WinAPI_SetLastError_mod(0) ; as suggested in MSDN - Local $sFuncName = "SetWindowLongW" - If @AutoItX64 Then $sFuncName = "SetWindowLongPtrW" - Local $aCall = DllCall($hUser32, "long_ptr", $sFuncName, "hwnd", $hWnd, "int", $iIndex, "long_ptr", $iValue) - If @error Then Return SetError(@error, @extended, 0) - - Return $aCall[0] -EndFunc ;==>_WinAPI_SetWindowLong_mod - -Func _WinAPI_SetWindowPos_mod($hWnd, $hAfter, $iX, $iY, $iCX, $iCY, $iFlags) - Local $aCall = DllCall($hUser32, "bool", "SetWindowPos", "hwnd", $hWnd, "hwnd", $hAfter, "int", $iX, "int", $iY, _ - "int", $iCX, "int", $iCY, "uint", $iFlags) - If @error Then Return SetError(@error, @extended, False) - - Return $aCall[0] -EndFunc ;==>_WinAPI_SetWindowPos_mod - -Func _WinAPI_DrawText_mod($hDC, $sText, ByRef $tRECT, $iFlags) - Local $aCall = DllCall($hUser32, "int", "DrawTextW", "handle", $hDC, "wstr", $sText, "int", -1, "struct*", $tRECT, _ - "uint", $iFlags) - If @error Then Return SetError(@error, @extended, 0) - - Return $aCall[0] -EndFunc ;==>_WinAPI_DrawText_mod - -Func _WinAPI_SetBkColor_mod($hDC, $iColor) - Local $aCall = DllCall($hGdi32, "INT", "SetBkColor", "handle", $hDC, "INT", $iColor) - If @error Then Return SetError(@error, @extended, -1) - - Return $aCall[0] -EndFunc ;==>_WinAPI_SetBkColor_mod - -Func _WinAPI_DeleteObject_mod($hObject) - Local $aCall = DllCall($hGdi32, "bool", "DeleteObject", "handle", $hObject) - If @error Then Return SetError(@error, @extended, False) - - Return $aCall[0] -EndFunc ;==>_WinAPI_DeleteObject_mod - -Func _WinAPI_InflateRect_mod(ByRef $tRECT, $iDX, $iDY) - Local $aCall = DllCall($hUser32, 'bool', 'InflateRect', 'struct*', $tRECT, 'int', $iDX, 'int', $iDY) - If @error Then Return SetError(@error, @extended, False) - - Return $aCall[0] -EndFunc ;==>_WinAPI_InflateRect_mod - -Func _WinAPI_FillRect_mod($hDC, $tRECT, $hBrush) - Local $aCall - If IsPtr($hBrush) Then - $aCall = DllCall($hUser32, "int", "FillRect", "handle", $hDC, "struct*", $tRECT, "handle", $hBrush) - Else - $aCall = DllCall($hUser32, "int", "FillRect", "handle", $hDC, "struct*", $tRECT, "dword_ptr", $hBrush) - EndIf - If @error Then Return SetError(@error, @extended, False) - - Return $aCall[0] -EndFunc ;==>_WinAPI_FillRect_mod - -Func _WinAPI_CreateSolidBrush_mod($iColor) - Local $aCall = DllCall($hGdi32, "handle", "CreateSolidBrush", "INT", $iColor) - If @error Then Return SetError(@error, @extended, 0) - - Return $aCall[0] -EndFunc ;==>_WinAPI_CreateSolidBrush_mod - -Func _WinAPI_GetClassName_mod($hWnd) - If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd) - Local $aCall = DllCall($hUser32, "int", "GetClassNameW", "hwnd", $hWnd, "wstr", "", "int", 4096) - If @error Or Not $aCall[0] Then Return SetError(@error, @extended, '') - - Return SetExtended($aCall[0], $aCall[2]) -EndFunc ;==>_WinAPI_GetClassName_mod - -Func _WinAPI_SetTextColor_mod($hDC, $iColor) - Local $aCall = DllCall($hGdi32, "INT", "SetTextColor", "handle", $hDC, "INT", $iColor) - If @error Then Return SetError(@error, @extended, -1) - - Return $aCall[0] -EndFunc ;==>_WinAPI_SetTextColor_mod - ; Resize the status bar when GUI size changes Func WM_SIZE($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg, $wParam, $lParam @@ -1512,13 +1345,6 @@ Func WM_DRAWITEM2($hWnd, $Msg, $wParam, $lParam) Return $GUI_RUNDEFMSG EndFunc ;==>WM_DRAWITEM2 -Func _WinAPI_PathIsRoot_mod($sFilePath) - Local $aCall = DllCall($hShlwapi, 'bool', 'PathIsRootW', 'wstr', $sFilePath & "\") - If @error Then Return SetError(@error, @extended, False) - - Return $aCall[0] -EndFunc ;==>_WinAPI_PathIsRoot_mod - ;============================================== Func ScrollbarProc($hWnd, $iMsg, $wParam, $lParam) ; Andreik @@ -1969,18 +1795,6 @@ Func WM_WINDOWPOSCHANGED_Handler($hWnd, $iMsg, $wParam, $lParam) Return $GUI_RUNDEFMSG EndFunc ;==>WM_WINDOWPOSCHANGED_Handler -Func TreeItemToPath($hTree, $hItem, $bArray = False) - Local $sPath = StringReplace(_GUICtrlTreeView_GetTree($hTree, $hItem), "|", "\") - $sPath = StringTrimLeft($sPath, StringInStr($sPath, "\")) ; remove this pc at the beginning - If StringInStr(FileGetAttrib($sPath), "D") Then $sPath &= "\" ; let folders end with \ - If $bArray Then - Local $aPath = _ArrayFromString($sPath) - _ArrayInsert($aPath, 0, 1) - Return $aPath - EndIf - Return $sPath -EndFunc ;==>TreeItemToPath - ;Convert @error codes from DllCall into win32 codes. Func TranslateDllError($iError = @error) Switch $iError @@ -2005,8 +1819,6 @@ Func _SHDoDragDrop($pDataObj, $pDropSource, $iOKEffects) ;Local $aCall = DllCall($hShell32, "long", "SHDoDragDrop", "hwnd", $g_hGUI, "ptr", $pDataObj, "ptr", $pDropSource, "dword", $iOKEffects, "ptr*", 0) Local $aCall = DllCall($hShell32, "long", "SHDoDragDrop", "hwnd", Null, "ptr", $pDataObj, "ptr", Null, "dword", $iOKEffects, "ptr*", 0) - If Hex($aCall[5], 1) = $DROPEFFECT_COPY Then ConsoleWrite("copy success" & @CRLF) - If @error Then Return SetError(@error, @extended, $aCall) Return SetError($aCall[0], 0, $aCall[4]) EndFunc ;==>_SHDoDragDrop @@ -2084,3 +1896,125 @@ Func RevokeDragDrop($hWnd) If @error Then Return SetError(TranslateDllError(), 0, False) Return SetError($aCall[0], 0, $aCall[0] = $S_OK) EndFunc ;==>RevokeDragDrop + + +; jugador code + +Func GetDataObjectOfFile_B(ByRef $sPath) + Local $iCount = UBound($sPath) + If $iCount = 0 Then Return 0 + + Local $sParentPath = StringLeft($sPath[0], StringInStr($sPath[0], "\", 0, -1) - 1) + Local $pParentPidl = _WinAPI_ShellILCreateFromPath($sParentPath) + + Local $tPidls = DllStructCreate("ptr[" & $iCount & "]") + + Local $pFullPidl, $pRelativePidl, $last_SHITEMID + For $i = 0 To $iCount - 1 + $pFullPidl = _WinAPI_ShellILCreateFromPath($sPath[$i]) + $last_SHITEMID = DllCall($hShell32, "ptr", "ILFindLastID", "ptr", $pFullPidl)[0] + $pRelativePidl = DllCall($hShell32, "ptr", "ILClone", "ptr", $last_SHITEMID)[0] + DllStructSetData($tPidls, 1, $pRelativePidl, $i + 1) + DllCall($hShell32, "none", "ILFree", "ptr", $pFullPidl) + Next + + Local $tIID_IDataObject = _WinAPI_GUIDFromString($sIID_IDataObject) + Local $pIDataObject = __SHCreateDataObject($tIID_IDataObject, $pParentPidl, $iCount, DllStructGetPtr($tPidls), 0) + + DllCall($hShell32, "none", "ILFree", "ptr", $pParentPidl) + For $i = 1 To $iCount + DllCall($hShell32, "none", "ILFree", "ptr", DllStructGetData($tPidls, 1, $i)) + Next + + If Not $pIDataObject Then Return 0 + Return $pIDataObject +EndFunc + +Func GetDataObjectOfFile_C(ByRef $sPath) + If UBound($sPath) = 0 Then Return 0 + + Local $tIID_IDataObject = _WinAPI_GUIDFromString($sIID_IDataObject) + Local $pIDataObject = __SHCreateDataObject($tIID_IDataObject, 0, 0, 0, 0) + If Not $pIDataObject Then Return 0 + + Local Const $tag_IDataObject = _ + "GetData hresult(ptr;ptr*);" & _ + "GetDataHere hresult(ptr;ptr*);" & _ + "QueryGetData hresult(ptr);" & _ + "GetCanonicalFormatEtc hresult(ptr;ptr*);" & _ + "SetData hresult(ptr;ptr;bool);" & _ + "EnumFormatEtc hresult(dword;ptr*);" & _ + "DAdvise hresult(ptr;dword;ptr;dword*);" & _ + "DUnadvise hresult(dword);" & _ + "EnumDAdvise hresult(ptr*);" + Local $oIDataObject = ObjCreateInterface($pIDataObject, $sIID_IDataObject, $tag_IDataObject) + If Not IsObj($oIDataObject) Then + _Release($pIDataObject) + Return 0 + Endif + + Local $tFORMATETC, $tSTGMEDIUM + __Fill_tag_FORMATETC($tFORMATETC) + __Fill_tag_STGMEDIUM($tSTGMEDIUM, $sPath) + + $oIDataObject.SetData(DllStructGetPtr($tFORMATETC), DllStructGetPtr($tSTGMEDIUM), 1) + _AddRef($pIDataObject) + + Return $pIDataObject +EndFunc + +Func __Fill_tag_FORMATETC(Byref $tFORMATETC) + Local Const $CF_HDROP = 15 + Local Const $TYMED_HGLOBAL = 1 + + $tFORMATETC = DllStructCreate("ushort cfFormat; ptr ptd; uint dwAspect; int lindex; uint tymed") + DllStructSetData($tFORMATETC, "cfFormat", $CF_HDROP) + DllStructSetData($tFORMATETC, "dwAspect", 1) + DllStructSetData($tFORMATETC, "lindex", -1) + DllStructSetData($tFORMATETC, "tymed", $TYMED_HGLOBAL) +EndFunc + +Func __Fill_tag_STGMEDIUM(Byref $tSTGMEDIUM, Byref $aFiles) + Local Const $CF_HDROP = 15 + Local Const $TYMED_HGLOBAL = 1 + + Local $sFileList = "" + For $i = 0 To UBound($aFiles) - 1 + $sFileList &= $aFiles[$i] & Chr(0) + Next + $sFileList &= Chr(0) + + Local $iSize = 20 + (StringLen($sFileList) * 2) + + Local $hGlobal = DllCall($hKernel32, "ptr", "GlobalAlloc", "uint", 0x2042, "ulong_ptr", $iSize)[0] + Local $pLock = DllCall($hKernel32, "ptr", "GlobalLock", "ptr", $hGlobal)[0] + + Local $tDROPFILES = DllStructCreate("dword pFiles; int x; int y; bool fNC; bool fWide", $pLock) + DllStructSetData($tDROPFILES, "pFiles", 20) + DllStructSetData($tDROPFILES, "fWide", True) + + Local $tPaths = DllStructCreate("wchar[" & StringLen($sFileList) & "]", $pLock + 20) + DllStructSetData($tPaths, 1, $sFileList) + + DllCall($hKernel32, "bool", "GlobalUnlock", "ptr", $hGlobal) + + $tSTGMEDIUM = DllStructCreate("uint tymed; ptr hGlobal; ptr pUnkForRelease") + DllStructSetData($tSTGMEDIUM, "tymed", $TYMED_HGLOBAL) + DllStructSetData($tSTGMEDIUM, "hGlobal", $hGlobal) + DllStructSetData($tSTGMEDIUM, "pUnkForRelease", 0) +EndFunc + +Func __SHCreateDataObject($tIID_IDataObject, $ppidlFolder = 0, $cidl = 0, $papidl = 0, $pdtInner = 0) + Local $aRes = DllCall($hShell32, "long", "SHCreateDataObject", _ + "ptr", $ppidlFolder, _ + "uint", $cidl, _ + "ptr", $papidl, _ + "ptr", $pdtInner, _ + "struct*", $tIID_IDataObject, _ + "ptr*", 0) + If @error Then Return SetError(1, 0, $aRes[0]) + Return $aRes[6] +EndFunc + +; jugador code above + From 939df87413941ebb729de05b833680192bdd7156 Mon Sep 17 00:00:00 2001 From: WildByDesign Date: Sat, 7 Feb 2026 19:21:59 -0500 Subject: [PATCH 08/14] Add notice about testing drag and drop --- lib/DropTargetObject.au3 | 4 ---- src/main.au3 | 7 +++++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/DropTargetObject.au3 b/lib/DropTargetObject.au3 index 6bccb75..5df39f3 100644 --- a/lib/DropTargetObject.au3 +++ b/lib/DropTargetObject.au3 @@ -366,13 +366,11 @@ Func __Mthd_Drop($pThis, $pDataObject, $iKeyState, $iPoint, $piEffect) Case $DROPEFFECT_COPY $iFlags = BitOR($FOFX_ADDUNDORECORD, $FOFX_RECYCLEONDELETE, $FOFX_NOCOPYHOOKS) $sAction = "CopyItems" - ConsoleWrite("copy took place on listview" & @CRLF) _IFileOperationFile($pDataObject, $sFullPath, $sAction, $iFlags) __TreeListExplorer_Reload(1) Case $DROPEFFECT_MOVE $iFlags = BitOR($FOFX_ADDUNDORECORD, $FOFX_RECYCLEONDELETE, $FOFX_NOCOPYHOOKS) $sAction = "MoveItems" - ConsoleWrite("move took place on listview" & @CRLF) _IFileOperationFile($pDataObject, $sFullPath, $sAction, $iFlags) ; send response back to source to indicate that file move has been handled $tEffect.iEffect = $DROPEFFECT_NONE @@ -392,13 +390,11 @@ Func __Mthd_Drop($pThis, $pDataObject, $iKeyState, $iPoint, $piEffect) Case $DROPEFFECT_COPY $iFlags = BitOR($FOFX_ADDUNDORECORD, $FOFX_RECYCLEONDELETE, $FOFX_NOCOPYHOOKS) $sAction = "CopyItems" - ConsoleWrite("copy took place on treeview" & @CRLF) _IFileOperationFile($pDataObject, $sFullPath, $sAction, $iFlags) __TreeListExplorer_Reload(1) Case $DROPEFFECT_MOVE $iFlags = BitOR($FOFX_ADDUNDORECORD, $FOFX_RECYCLEONDELETE, $FOFX_NOCOPYHOOKS) $sAction = "MoveItems" - ConsoleWrite("move took place on treeview" & @CRLF) _IFileOperationFile($pDataObject, $sFullPath, $sAction, $iFlags) ; send response back to source to indicate that file move has been handled $tEffect.iEffect = $DROPEFFECT_NONE diff --git a/src/main.au3 b/src/main.au3 index db0dc96..1719b4d 100644 --- a/src/main.au3 +++ b/src/main.au3 @@ -417,6 +417,11 @@ Func _FilesAu3() $i_ExStyle_Old = _WinAPI_GetWindowLong_mod(_GUIFrame_GetHandle($iFrame_A, 2), $GWL_EXSTYLE) _WinAPI_SetWindowLong_mod(_GUIFrame_GetHandle($iFrame_A, 2), $GWL_EXSTYLE, BitOR($i_ExStyle_Old, $WS_EX_ACCEPTFILES)) + Local $sMsg = "Attention: The drag and drop code is new and caution is advised." & @CRLF & @CRLF + $sMsg &= "Please consider testing drag and drop in less important areas of your file system." & @CRLF & @CRLF + $sMsg &= "To Undo the last drag and drop operation, open File Explorer and press Ctrl+Z." + MsgBox($MB_ICONWARNING, "Files Au3", $sMsg) + While True If $bTooltipActive Then ; check if cursor is still over listview @@ -1677,8 +1682,6 @@ Func _EventsGUI() _resizeLVCols2() Case $GUI_EVENT_RESIZED _resizeLVCols2() - Case $GUI_EVENT_DROPPED - ConsoleWrite("drop detected" & @CRLF) EndSwitch EndFunc ;==>_EventsGUI From 4064815434a8deb07096d100339fba612ec44161 Mon Sep 17 00:00:00 2001 From: WildByDesign Date: Mon, 9 Feb 2026 08:33:14 -0500 Subject: [PATCH 09/14] Add Rename and Delete functionality - add Rename and Delete functionality to TreeView and ListView - TreeView can delete single item at a time while ListView can delete single or multiple selections - Context menu for Rename, Delete, etc. can be done later --- lib/IFileOperation.au3 | 17 +++++ src/main.au3 | 168 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 179 insertions(+), 6 deletions(-) diff --git a/lib/IFileOperation.au3 b/lib/IFileOperation.au3 index b907603..fea2170 100644 --- a/lib/IFileOperation.au3 +++ b/lib/IFileOperation.au3 @@ -73,6 +73,23 @@ Global Const $dtagIFileOperation = "Advise hresult(ptr;dword*);" & _ ;_IFileOperationFile($pDataObj, $sPathTo, $sAction, $iFlags) +Func _IFileOperationDelete($pDataObj, $iFlags = 0) + + Local $tIIDIShellItem = CLSIDFromString($IID_IShellItem) + Local $tIIDIShellItemArray = CLSIDFromString($IID_IShellItemArray) + + + Local $oIFileOperation = ObjCreateInterface($CLSID_IFileOperation, $IID_IFileOperation, $dtagIFileOperation) + If Not IsObj($oIFileOperation) Then Return SetError(2, 0, False) + + $oIFileOperation.SetOperationFlags($iFlags) + + $oIFileOperation.DeleteItems($pDataObj) + + Return $oIFileOperation.PerformOperations() = 0 + +EndFunc ;==>_IFileOperationDelete + Func _IFileOperationFile($pDataObj, $sPathTo, $sAction, $iFlags = 0) If Not FileExists($sPathTo) Then diff --git a/src/main.au3 b/src/main.au3 index 1719b4d..eca57be 100644 --- a/src/main.au3 +++ b/src/main.au3 @@ -5,9 +5,11 @@ #include #include #include +#include #include #include #include +;#include #include #include @@ -73,6 +75,7 @@ Global $hFolderHistory = __History_Create("_doUnReDo", 100, "_historyChange"), $ Global $hSolidBrush = _WinAPI_CreateBrushIndirect($BS_SOLID, 0x000000) Global $iTopSpacer = Round(12 * $iDPI) Global $aPosTip, $iOldaPos0, $iOldaPos1 +Global $sRenameFrom ; force light mode ;$isDarkMode = False @@ -253,7 +256,7 @@ Func _FilesAu3() $aWinSize1 = WinGetClientSize(_GUIFrame_GetHandle($iFrame_A, 1)) ; create treeview - Local $iStyle = BitOR($TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_SHOWSELALWAYS, $TVS_TRACKSELECT) + Local $iStyle = BitOR($TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_SHOWSELALWAYS, $TVS_TRACKSELECT, $TVS_EDITLABELS) $idTreeView = GUICtrlCreateTreeView(0, 0, $aWinSize1[0], $iFrameHeight, $iStyle) GUICtrlSetState(-1, $GUI_DROPACCEPTED) GUICtrlSetResizing(-1, $GUI_DOCKLEFT + $GUI_DOCKRIGHT + $GUI_DOCKTOP + $GUI_DOCKBOTTOM) @@ -292,7 +295,7 @@ Func _FilesAu3() ; create listview control Local $iExStyles = BitOR($LVS_EX_FULLROWSELECT, $LVS_EX_DOUBLEBUFFER, $LVS_EX_TRACKSELECT) - $idListview = GUICtrlCreateListView("Name|Size|Date Modified|Type", 0, $iHeaderHeight, $aWinSize2[0], $iFrameHeight - $iHeaderHeight, BitOR($LVS_SHOWSELALWAYS, $LVS_NOCOLUMNHEADER), $iExStyles) + $idListview = GUICtrlCreateListView("Name|Size|Date Modified|Type", 0, $iHeaderHeight, $aWinSize2[0], $iFrameHeight - $iHeaderHeight, BitOR($LVS_SHOWSELALWAYS, $LVS_NOCOLUMNHEADER, $LVS_EDITLABELS), $iExStyles) GUICtrlSetState(-1, $GUI_DROPACCEPTED) GUICtrlSetResizing(-1, $GUI_DOCKLEFT + $GUI_DOCKRIGHT + $GUI_DOCKTOP + $GUI_DOCKBOTTOM) @@ -420,7 +423,7 @@ Func _FilesAu3() Local $sMsg = "Attention: The drag and drop code is new and caution is advised." & @CRLF & @CRLF $sMsg &= "Please consider testing drag and drop in less important areas of your file system." & @CRLF & @CRLF $sMsg &= "To Undo the last drag and drop operation, open File Explorer and press Ctrl+Z." - MsgBox($MB_ICONWARNING, "Files Au3", $sMsg) + ;MsgBox($MB_ICONWARNING, "Files Au3", $sMsg) While True If $bTooltipActive Then @@ -709,6 +712,8 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) Local Static $iItemPrev Local $iItemRow + Local $tText + ; header and listview combined functionality Local $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom")) Local $iCode = DllStructGetData($tNMHDR, "Code") @@ -798,6 +803,7 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) _GUIToolTip_UpdateTipText($hToolTip1, $g_hGUI, $g_hListview, $gText) EndIf Case $LVN_ITEMCHANGED + ;ConsoleWrite("lv item changed" & @CRLF) ; item selection(s) have changed _selectionChangedLV() Case $LVN_BEGINDRAG, $LVN_BEGINRDRAG @@ -880,6 +886,81 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) $bTooltipActive = True EndIf Return 1 ; prevent the hover from being processed + Case $LVN_KEYDOWN + Local $tLVKeyDown = DllStructCreate($tagNMLVKEYDOWN, $lParam) + Local $iVKey = DllStructGetData($tLVKeyDown, "VKey") + If $iVKey = 46 Then + ; create array with list of selected listview items + Local $aItems = _GUICtrlListView_GetSelectedIndices($tNMHDR.hwndFrom, True) + For $i = 1 To $aItems[0] + $aItems[$i] = __TreeListExplorer_GetPath($hTLESystem) & _GUICtrlListView_GetItemText($tNMHDR.hwndFrom, $aItems[$i]) + Next + + ;$pDataObj = GetDataObjectOfFiles($hWnd, $aItems) ; MattyD function + + _ArrayDelete($aItems, 0) ; only needed for GetDataObjectOfFile_B + Local $pDataObj = GetDataObjectOfFile_B($aItems) ; jugador function + + Local $iFlags = BitOR($FOFX_ADDUNDORECORD, $FOFX_RECYCLEONDELETE, $FOFX_NOCOPYHOOKS) + _IFileOperationDelete($pDataObj, $iFlags) + + __TreeListExplorer_Reload($hTLESystem) + + _Release($pDataObj) + EndIf + Case $LVN_BEGINLABELEDITA, $LVN_BEGINLABELEDITW + Local $aSelectedLV = _GUICtrlListView_GetSelectedIndices($idListview, True) + ; there should only be one selected item during a rename + Local $iItemLV = $aSelectedLV[1] + Local $sRenameItem = _GUICtrlListView_GetItemText($idListview, $iItemLV, 0) + $sRenameFrom = __TreeListExplorer_GetPath($hTLESystem) & $sRenameItem + Return False + Case $LVN_ENDLABELEDITA, $LVN_ENDLABELEDITW + Local $sRenameTo + $tText = DllStructCreate($tagNMLVDISPINFO, $lParam) + Local $tBuffer = DllStructCreate("wchar Text[" & DllStructGetData($tText, "TextMax") & "]", DllStructGetData($tText, "Text")) + Local $sTextRet = DllStructGetData($tBuffer, "Text") + Local $sIllegal = "A file name can't contain any of the following characters:" & @CRLF & @CRLF + $sIllegal &= '\ / : * ? " < > |' + ; A file name can't contain any of the following characters: + ; \/:*?"<>| + Select + Case StringInStr($sTextRet, '\', 2) + ;MsgBox($MB_ICONERROR, "Error", $sIllegal) ; MsgBox causing GUI lockup + Return False + Case StringInStr($sTextRet, '/', 2) + ;MsgBox($MB_ICONERROR, "Error", $sIllegal) + Return False + Case StringInStr($sTextRet, ':', 2) + ;MsgBox($MB_ICONERROR, "Error", $sIllegal) + Return False + Case StringInStr($sTextRet, '*', 2) + ;MsgBox($MB_ICONERROR, "Error", $sIllegal) + Return False + Case StringInStr($sTextRet, '?', 2) + ;MsgBox($MB_ICONERROR, "Error", $sIllegal) + Return False + Case StringInStr($sTextRet, '"', 2) + ;MsgBox($MB_ICONERROR, "Error", $sIllegal) + Return False + Case StringInStr($sTextRet, '<', 2) + ;MsgBox($MB_ICONERROR, "Error", $sIllegal) + Return False + Case StringInStr($sTextRet, '>', 2) + ;MsgBox($MB_ICONERROR, "Error", $sIllegal) + Return False + Case StringInStr($sTextRet, '|', 2) + ;MsgBox($MB_ICONERROR, "Error", $sIllegal) + Return False + Case Not $sTextRet + Return False + Case Else + $sRenameTo = __TreeListExplorer_GetPath($hTLESystem) & $sTextRet + _WinAPI_ShellFileOperation($sRenameFrom, $sRenameTo, $FO_RENAME, BitOR($FOF_ALLOWUNDO, $FOF_NO_UI)) + ; refresh TLE system to pick up any folder changes, file type changes, etc. + __TreeListExplorer_Reload($hTLESystem) + Return True ; allow rename to occur + EndSelect EndSwitch Case $g_hTreeView Switch $iCode @@ -900,10 +981,7 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) $pDropSource = CreateDropSource() If Not @error Then - ;We allow DROPEFFECT_COPY and DROPEFFECT_LINK. We don't want to DROPEFFECT_MOVE the file!! - ;DoDragDrop($pDataObj, $pDropSource, BitOR($DROPEFFECT_COPY, $DROPEFFECT_LINK)) _SHDoDragDrop($pDataObj, $pDropSource, BitOR($DROPEFFECT_MOVE, $DROPEFFECT_COPY, $DROPEFFECT_LINK)) - ;__TreeListExplorer_Reload($hTLESystem) ;Operation done, destroy our drop source. (Can't just IUnknown_Release() this one!) DestroyDropSource($pDropSource) @@ -912,7 +990,81 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) ;Relase the data object so the system can destroy it (prevent memory leaks) _Release($pDataObj) EndIf + Case $TVN_KEYDOWN + Local $tTVKeyDown = DllStructCreate($tagNMTVKEYDOWN, $lParam) + Local $iVKey = DllStructGetData($tTVKeyDown, "VKey") + If $iVKey = 46 Then + Local $hTreeItemSel = _GUICtrlTreeView_GetSelection($g_hTreeView) + Local $sItemText = TreeItemToPath($g_hTreeView, $hTreeItemSel) + Local $pDataObj, $pDropSource + + ;Get an IDataObject representing the file to copy + $pDataObj = GetDataObjectOfFile($hWnd, $sItemText) + $iFlags = BitOR($FOFX_ADDUNDORECORD, $FOFX_RECYCLEONDELETE, $FOFX_NOCOPYHOOKS) + _IFileOperationDelete($pDataObj, $iFlags) + + __TreeListExplorer_Reload($hTLESystem) + + ;Relase the data object so the system can destroy it (prevent memory leaks) + _Release($pDataObj) + EndIf + Case $TVN_BEGINLABELEDITA, $TVN_BEGINLABELEDITW + HotKeySet("{Enter}", "_EndEditTV") + HotKeySet("{Esc}", "_EndEditTV") + $hTreeItemOrig = _GUICtrlTreeView_GetSelection($g_hTreeView) + $sRenameFrom = TreeItemToPath($g_hTreeView, $hTreeItemOrig) + Return False + Case $TVN_ENDLABELEDITA, $TVN_ENDLABELEDITW + Local $sRenameTo + HotKeySet("{Enter}") + HotKeySet("{Esc}") + $tText = DllStructCreate($tagNMTVDISPINFO, $lParam) + Local $tBuffer = DllStructCreate("wchar Text[" & DllStructGetData($tText, "TextMax") & "]", DllStructGetData($tText, "Text")) + Local $sTextRet = DllStructGetData($tBuffer, "Text") + Local $sIllegal = "A file name can't contain any of the following characters:" & @CRLF & @CRLF + $sIllegal &= '\ / : * ? " < > |' + ; A file name can't contain any of the following characters: + ; \/:*?"<>| + Select + Case StringInStr($sTextRet, '\', 2) + ;MsgBox($MB_ICONERROR, "Error", $sIllegal) ; MsgBox causing GUI lockup + ; TODO: maybe consider tooltip for these + Return False + Case StringInStr($sTextRet, '/', 2) + ;MsgBox($MB_ICONERROR, "Error", $sIllegal) + Return False + Case StringInStr($sTextRet, ':', 2) + ;MsgBox($MB_ICONERROR, "Error", $sIllegal) + Return False + Case StringInStr($sTextRet, '*', 2) + ;MsgBox($MB_ICONERROR, "Error", $sIllegal) + Return False + Case StringInStr($sTextRet, '?', 2) + ;MsgBox($MB_ICONERROR, "Error", $sIllegal) + Return False + Case StringInStr($sTextRet, '"', 2) + ;MsgBox($MB_ICONERROR, "Error", $sIllegal) + Return False + Case StringInStr($sTextRet, '<', 2) + ;MsgBox($MB_ICONERROR, "Error", $sIllegal) + Return False + Case StringInStr($sTextRet, '>', 2) + ;MsgBox($MB_ICONERROR, "Error", $sIllegal) + Return False + Case StringInStr($sTextRet, '|', 2) + ;MsgBox($MB_ICONERROR, "Error", $sIllegal) + Return False + Case Not $sTextRet + Return False + Case Else + Local $aPath = _StringBetween($sRenameFrom, "\", "\") + Local $sRenameItem = $aPath[UBound($aPath) - 1] + $sRenameTo = StringReplace($sRenameFrom, $sRenameItem, $sTextRet) + _WinAPI_ShellFileOperation($sRenameFrom, $sRenameTo, $FO_RENAME, BitOR($FOF_ALLOWUNDO, $FOF_NO_UI)) + ;__TreeListExplorer_Reload($hTLESystem) + Return True ; allow rename to occur + EndSelect EndSwitch EndSwitch @@ -974,6 +1126,10 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) Return $GUI_RUNDEFMSG EndFunc ;==>WM_NOTIFY2 +Func _EndEditTV() + _GUICtrlTreeView_EndEdit($g_hTreeView) +EndFunc + Func _removeExStyles() ; remove WS_EX_COMPOSITED from GUI Local $i_ExStyle_Old = _WinAPI_GetWindowLong_mod($hParentFrame, $GWL_EXSTYLE) From e80ab78b6490da9ee2a752829d3b903ef4caec2d Mon Sep 17 00:00:00 2001 From: WildByDesign Date: Tue, 10 Feb 2026 07:01:55 -0500 Subject: [PATCH 10/14] Block illegal path characters - Block illegal path characters from Rename of file names or folders. - Show balloon tip regarding illegal characters if illegal character pressed --- src/main.au3 | 294 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 219 insertions(+), 75 deletions(-) diff --git a/src/main.au3 b/src/main.au3 index eca57be..3a5f37d 100644 --- a/src/main.au3 +++ b/src/main.au3 @@ -9,7 +9,6 @@ #include #include #include -;#include #include #include @@ -26,7 +25,6 @@ Global $hShell32 = DllOpen('shell32.dll') #include "../lib/ProjectConstants.au3" #include "../lib/DropSourceObject.au3" #include "../lib/DropTargetObject.au3" -;#include "../lib/IFileOperation.au3" ; CREDITS: ; Kanashius TreeListExplorer UDF @@ -66,7 +64,7 @@ Global $sBack, $sForward, $sUpLevel, $sRefresh Global $sTreeDragItem, $sListDragItems, $bDragToolActive = False Global $pLVDropTarget, $pTVDropTarget Global $bPathInputChanged = False, $bLoadStatus = False, $bCursorOverride = False -Global $idExitItem, $idAboutItem +Global $idExitItem, $idAboutItem, $idDeleteItem, $idRenameItem, $idCopyItem, $idPasteItem Global $hCursor, $hProc Global $sSelectedItems, $g_aText, $gText Global $idSeparator, $idThemeItem, $hToolTip1, $hToolTip2, $bTooltipActive @@ -75,7 +73,7 @@ Global $hFolderHistory = __History_Create("_doUnReDo", 100, "_historyChange"), $ Global $hSolidBrush = _WinAPI_CreateBrushIndirect($BS_SOLID, 0x000000) Global $iTopSpacer = Round(12 * $iDPI) Global $aPosTip, $iOldaPos0, $iOldaPos1 -Global $sRenameFrom +Global $sRenameFrom, $sControlFocus, $bFocusChanged = False, $bSaveEdit = False ; force light mode ;$isDarkMode = False @@ -207,25 +205,32 @@ Func _FilesAu3() ; reset GUI font GUISetFont(10, $FW_NORMAL, $GUI_FONTNORMAL, "Segoe UI") - ; Menu - If $isDarkMode Then - Local $idFileMenu = _GUICtrlCreateODTopMenu("& File", $g_hGUI) - Local $idViewMenu = _GUICtrlCreateODTopMenu("& View", $g_hGUI) - Local $idHelpMenu = _GUICtrlCreateODTopMenu("& Help", $g_hGUI) - Else - Local $idFileMenu = _GUICtrlCreateODTopMenu("& File", $g_hGUI) - Local $idViewMenu = _GUICtrlCreateODTopMenu("& View", $g_hGUI) - Local $idHelpMenu = _GUICtrlCreateODTopMenu("& Help", $g_hGUI) - EndIf - + ; Menubar + Local $idFileMenu = _GUICtrlCreateODTopMenu("& File", $g_hGUI) + Local $idEditMenu = _GUICtrlCreateODTopMenu("& Edit", $g_hGUI) + Local $idViewMenu = _GUICtrlCreateODTopMenu("& View", $g_hGUI) + Local $idHelpMenu = _GUICtrlCreateODTopMenu("& Help", $g_hGUI) + + ; File menu + $idDeleteItem = GUICtrlCreateMenuItem("&Delete", $idFileMenu) + GUICtrlSetState($idDeleteItem, $GUI_DISABLE) + $idRenameItem = GUICtrlCreateMenuItem("&Rename", $idFileMenu) + GUICtrlSetState($idRenameItem, $GUI_DISABLE) $idPropertiesItem = GUICtrlCreateMenuItem("&Properties", $idFileMenu) GUICtrlSetOnEvent(-1, "_MenuFunctions") GUICtrlSetState($idPropertiesItem, $GUI_DISABLE) GUICtrlCreateMenuItem("", $idFileMenu) $idExitItem = GUICtrlCreateMenuItem("&Exit", $idFileMenu) GUICtrlSetOnEvent(-1, "_MenuFunctions") + ; Edit menu + $idCopyItem = GUICtrlCreateMenuItem("&Copy", $idEditMenu) + GUICtrlSetState($idCopyItem, $GUI_DISABLE) + $idPasteItem = GUICtrlCreateMenuItem("&Paste", $idEditMenu) + GUICtrlSetState($idPasteItem, $GUI_DISABLE) + ; View menu $idThemeItem = GUICtrlCreateMenuItem("&Dark Mode", $idViewMenu) GUICtrlSetOnEvent(-1, "_MenuFunctions") + ; Help menu $idAboutItem = GUICtrlCreateMenuItem("&About", $idHelpMenu) GUICtrlSetOnEvent(-1, "_MenuFunctions") @@ -425,6 +430,9 @@ Func _FilesAu3() $sMsg &= "To Undo the last drag and drop operation, open File Explorer and press Ctrl+Z." ;MsgBox($MB_ICONWARNING, "Files Au3", $sMsg) + $sControlFocus = 'Tree' + $bFocusChanged = True + While True If $bTooltipActive Then ; check if cursor is still over listview @@ -439,6 +447,22 @@ Func _FilesAu3() EndIf EndIf + If $bFocusChanged Then + $bFocusChanged = False + Select + Case $sControlFocus = 'List' + ConsoleWrite("ListView currently has focus." & @CRLF) + ; need to ensure it has a selection + ; figure out which menu options to enable/disable + Case $sControlFocus = 'Tree' + ConsoleWrite("TreeView currently has focus." & @CRLF) + ; treeview always has a selection + Case Not $sControlFocus + ConsoleWrite("Neither the ListView or TreeView has focus right now." & @CRLF) + ; in this case likely disable menu options + EndSelect + EndIf + Sleep(200) WEnd EndFunc ;==>_FilesAu3 @@ -803,7 +827,6 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) _GUIToolTip_UpdateTipText($hToolTip1, $g_hGUI, $g_hListview, $gText) EndIf Case $LVN_ITEMCHANGED - ;ConsoleWrite("lv item changed" & @CRLF) ; item selection(s) have changed _selectionChangedLV() Case $LVN_BEGINDRAG, $LVN_BEGINRDRAG @@ -914,8 +937,29 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) Local $iItemLV = $aSelectedLV[1] Local $sRenameItem = _GUICtrlListView_GetItemText($idListview, $iItemLV, 0) $sRenameFrom = __TreeListExplorer_GetPath($hTLESystem) & $sRenameItem + ; set hotkeys to ensure that file name cannot contain illegal characters + ; \ / : * ? " < > | + HotKeySet ('{\}', "_RenameCheckLV") + HotKeySet ('{/}', "_RenameCheckLV") + HotKeySet ('{:}', "_RenameCheckLV") + HotKeySet ('{*}', "_RenameCheckLV") + HotKeySet ('{?}', "_RenameCheckLV") + HotKeySet ('{"}', "_RenameCheckLV") + HotKeySet ('{<}', "_RenameCheckLV") + HotKeySet ('{>}', "_RenameCheckLV") + HotKeySet ('{|}', "_RenameCheckLV") Return False Case $LVN_ENDLABELEDITA, $LVN_ENDLABELEDITW + ; unset hotkeys that block illegal characters from being set + HotKeySet ('{\}') + HotKeySet ('{/}') + HotKeySet ('{:}') + HotKeySet ('{*}') + HotKeySet ('{?}') + HotKeySet ('{"}') + HotKeySet ('{<}') + HotKeySet ('{>}') + HotKeySet ('{|}') Local $sRenameTo $tText = DllStructCreate($tagNMLVDISPINFO, $lParam) Local $tBuffer = DllStructCreate("wchar Text[" & DllStructGetData($tText, "TextMax") & "]", DllStructGetData($tText, "Text")) @@ -926,31 +970,22 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) ; \/:*?"<>| Select Case StringInStr($sTextRet, '\', 2) - ;MsgBox($MB_ICONERROR, "Error", $sIllegal) ; MsgBox causing GUI lockup Return False Case StringInStr($sTextRet, '/', 2) - ;MsgBox($MB_ICONERROR, "Error", $sIllegal) Return False Case StringInStr($sTextRet, ':', 2) - ;MsgBox($MB_ICONERROR, "Error", $sIllegal) Return False Case StringInStr($sTextRet, '*', 2) - ;MsgBox($MB_ICONERROR, "Error", $sIllegal) Return False Case StringInStr($sTextRet, '?', 2) - ;MsgBox($MB_ICONERROR, "Error", $sIllegal) Return False Case StringInStr($sTextRet, '"', 2) - ;MsgBox($MB_ICONERROR, "Error", $sIllegal) Return False Case StringInStr($sTextRet, '<', 2) - ;MsgBox($MB_ICONERROR, "Error", $sIllegal) Return False Case StringInStr($sTextRet, '>', 2) - ;MsgBox($MB_ICONERROR, "Error", $sIllegal) Return False Case StringInStr($sTextRet, '|', 2) - ;MsgBox($MB_ICONERROR, "Error", $sIllegal) Return False Case Not $sTextRet Return False @@ -961,6 +996,12 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) __TreeListExplorer_Reload($hTLESystem) Return True ; allow rename to occur EndSelect + Case $NM_SETFOCUS + $sControlFocus = 'List' + $bFocusChanged = True + Case $NM_KILLFOCUS + $sControlFocus = '' + $bFocusChanged = True EndSwitch Case $g_hTreeView Switch $iCode @@ -1010,61 +1051,82 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) _Release($pDataObj) EndIf Case $TVN_BEGINLABELEDITA, $TVN_BEGINLABELEDITW - HotKeySet("{Enter}", "_EndEditTV") - HotKeySet("{Esc}", "_EndEditTV") + HotKeySet("{Enter}", "_SaveEditTV") + HotKeySet("{Esc}", "_CancelEditTV") $hTreeItemOrig = _GUICtrlTreeView_GetSelection($g_hTreeView) $sRenameFrom = TreeItemToPath($g_hTreeView, $hTreeItemOrig) + ; set hotkeys to ensure that file name cannot contain illegal characters + ; \ / : * ? " < > | + HotKeySet ('{\}', "_RenameCheckTV") + HotKeySet ('{/}', "_RenameCheckTV") + HotKeySet ('{:}', "_RenameCheckTV") + HotKeySet ('{*}', "_RenameCheckTV") + HotKeySet ('{?}', "_RenameCheckTV") + HotKeySet ('{"}', "_RenameCheckTV") + HotKeySet ('{<}', "_RenameCheckTV") + HotKeySet ('{>}', "_RenameCheckTV") + HotKeySet ('{|}', "_RenameCheckTV") Return False Case $TVN_ENDLABELEDITA, $TVN_ENDLABELEDITW Local $sRenameTo HotKeySet("{Enter}") HotKeySet("{Esc}") - $tText = DllStructCreate($tagNMTVDISPINFO, $lParam) - Local $tBuffer = DllStructCreate("wchar Text[" & DllStructGetData($tText, "TextMax") & "]", DllStructGetData($tText, "Text")) - Local $sTextRet = DllStructGetData($tBuffer, "Text") - Local $sIllegal = "A file name can't contain any of the following characters:" & @CRLF & @CRLF - $sIllegal &= '\ / : * ? " < > |' - ; A file name can't contain any of the following characters: - ; \/:*?"<>| - Select - Case StringInStr($sTextRet, '\', 2) - ;MsgBox($MB_ICONERROR, "Error", $sIllegal) ; MsgBox causing GUI lockup - ; TODO: maybe consider tooltip for these - Return False - Case StringInStr($sTextRet, '/', 2) - ;MsgBox($MB_ICONERROR, "Error", $sIllegal) - Return False - Case StringInStr($sTextRet, ':', 2) - ;MsgBox($MB_ICONERROR, "Error", $sIllegal) - Return False - Case StringInStr($sTextRet, '*', 2) - ;MsgBox($MB_ICONERROR, "Error", $sIllegal) - Return False - Case StringInStr($sTextRet, '?', 2) - ;MsgBox($MB_ICONERROR, "Error", $sIllegal) - Return False - Case StringInStr($sTextRet, '"', 2) - ;MsgBox($MB_ICONERROR, "Error", $sIllegal) - Return False - Case StringInStr($sTextRet, '<', 2) - ;MsgBox($MB_ICONERROR, "Error", $sIllegal) - Return False - Case StringInStr($sTextRet, '>', 2) - ;MsgBox($MB_ICONERROR, "Error", $sIllegal) - Return False - Case StringInStr($sTextRet, '|', 2) - ;MsgBox($MB_ICONERROR, "Error", $sIllegal) - Return False - Case Not $sTextRet - Return False - Case Else - Local $aPath = _StringBetween($sRenameFrom, "\", "\") - Local $sRenameItem = $aPath[UBound($aPath) - 1] - $sRenameTo = StringReplace($sRenameFrom, $sRenameItem, $sTextRet) - _WinAPI_ShellFileOperation($sRenameFrom, $sRenameTo, $FO_RENAME, BitOR($FOF_ALLOWUNDO, $FOF_NO_UI)) - ;__TreeListExplorer_Reload($hTLESystem) - Return True ; allow rename to occur - EndSelect + ; unset hotkeys that block illegal characters from being set + HotKeySet ('{\}') + HotKeySet ('{/}') + HotKeySet ('{:}') + HotKeySet ('{*}') + HotKeySet ('{?}') + HotKeySet ('{"}') + HotKeySet ('{<}') + HotKeySet ('{>}') + HotKeySet ('{|}') + If $bSaveEdit Then + $bSaveEdit = False + $tText = DllStructCreate($tagNMTVDISPINFO, $lParam) + Local $tBuffer = DllStructCreate("wchar Text[" & DllStructGetData($tText, "TextMax") & "]", DllStructGetData($tText, "Text")) + Local $sTextRet = DllStructGetData($tBuffer, "Text") + ; A file name can't contain any of the following characters: + ; \/:*?"<>| + Select + Case StringInStr($sTextRet, '\', 2) + Return False + Case StringInStr($sTextRet, '/', 2) + Return False + Case StringInStr($sTextRet, ':', 2) + Return False + Case StringInStr($sTextRet, '*', 2) + Return False + Case StringInStr($sTextRet, '?', 2) + Return False + Case StringInStr($sTextRet, '"', 2) + Return False + Case StringInStr($sTextRet, '<', 2) + Return False + Case StringInStr($sTextRet, '>', 2) + Return False + Case StringInStr($sTextRet, '|', 2) + Return False + Case Not $sTextRet + Return False + Case Else + Local $aPath = _StringBetween($sRenameFrom, "\", "\") + Local $sRenameItem = $aPath[UBound($aPath) - 1] + $sRenameTo = StringReplace($sRenameFrom, $sRenameItem, $sTextRet) + _WinAPI_ShellFileOperation($sRenameFrom, $sRenameTo, $FO_RENAME, BitOR($FOF_ALLOWUNDO, $FOF_NO_UI)) + ;__TreeListExplorer_Reload($hTLESystem) + Return True ; allow rename to occur + EndSelect + EndIf + Case $NM_SETFOCUS + $sControlFocus = 'Tree' + $bFocusChanged = True + Case $NM_KILLFOCUS + $sControlFocus = '' + $bFocusChanged = True + Case $TVN_SELCHANGINGA, $TVN_SELCHANGINGW + ;ConsoleWrite("treeview selection changing" & @CRLF) + ; TODO: maybe follow up in While loop EndSwitch EndSwitch @@ -1126,7 +1188,27 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) Return $GUI_RUNDEFMSG EndFunc ;==>WM_NOTIFY2 -Func _EndEditTV() +Func _RenameCheckLV() + Local $sIllegal = "A file name can't contain any of the following characters:" & @CRLF & @CRLF + $sIllegal &= '\ / : * ? " < > |' + Local $hEdit = _GUICtrlListView_GetEditControl($g_hListview) + _GUICtrlEdit_ShowBalloonTip($hEdit, '', $sIllegal, $TTI_INFO) +EndFunc + +Func _RenameCheckTV() + Local $sIllegal = "A file name can't contain any of the following characters:" & @CRLF & @CRLF + $sIllegal &= '\ / : * ? " < > |' + Local $hEdit = _GUICtrlTreeView_GetEditControl($g_hTreeView) + _GUICtrlEdit_ShowBalloonTip($hEdit, '', $sIllegal, $TTI_INFO) +EndFunc + +Func _SaveEditTV() + $bSaveEdit = True + _GUICtrlTreeView_EndEdit($g_hTreeView) +EndFunc + +Func _CancelEditTV() + $bSaveEdit = False _GUICtrlTreeView_EndEdit($g_hTreeView) EndFunc @@ -1256,7 +1338,8 @@ EndFunc ;==>WM_COMMAND2 Func _About() Local $sMsg - $sMsg = "Version: " & @TAB & @TAB & $sVersion & @CRLF & @CRLF + $sMsg = "Program Version: " & @TAB & $sVersion & @CRLF & @CRLF + $sMsg &= "TreeListExplorer: " & @TAB & _VersionToString(_UDFGetVersion("../lib/TreeListExplorer.au3")) & @CRLF & @CRLF $sMsg &= "Made by: " & @TAB & "AutoIt Community" MsgBox(0, "Files Au3", $sMsg) EndFunc ;==>_About @@ -2177,3 +2260,64 @@ EndFunc ; jugador code above +Func _VersionToString($arVersion, $sSep = " ") + If Not IsArray($arVersion) Or UBound($arVersion, 0)<2 Or UBound($arVersion, 1)<2 Then Return SetError(1, 1, "Version not parsed.") + Local $sVersion = "" + If $arVersion[1][0]>0 Then + $sVersion &= $arVersion[1][1] + EndIf + If $sVersion = "" Then Return "Version unknown" + Return $sVersion +EndFunc + +Func _UDFGetVersion($sFile) + Local $sCode = FileRead($sFile) + If @error Then Return SetError(@error, @extended, 0) + Local $arVersion = _GetVersion($sCode) + If @error Then Return SetError(@error, @extended, -1) + Return $arVersion +EndFunc + +; #FUNCTION# ==================================================================================================================== +; Name ..........: _GetVersion +; Description ...: Get the AutoIt Version as well as the UDF Version. +; Syntax ........: _GetVersion($sUdfCode) +; Parameters ....: $sUdfCode - the sourcecode of the udf +; Return values .: Array with version information. +; Author ........: Kanashius +; Modified ......: +; Remarks .......: @extended (1 - Only AutoIt Version found, 2 - Only UDF Version found, 3 - Both found) +; Resurns a 2D-Array with: +; [0][0] being the amount of version parts found for the AutoIt Version + 1 +; [0][1] If [0][0]>0 then this is the full autoit version as string +; [0][2] The first part of the autoit version (index 2-5 is a number) +; ... +; [0][6] The last part of the autoit version (last part is a/b/rc) +; [1][0] being the amount of version parts found for the UDF Version + 1 +; [1][1] If [1][0]>0 then this is the full udf version as string +; [1][2] The first part of the udf version (index 2-5 is a number) +; ... +; [1][6] The last part of the udf version (last part is a/b/rc) +; Related .......: +; Link ..........: +; Example .......: No +; =============================================================================================================================== +Func _GetVersion($sUdfCode) + Local $iExtended = 0 + Local $arAutoItVersion = StringRegExp($sUdfCode, "(?m)(?s)^;\s*#INDEX#\s*=*.*?;\s*AutoIt\s*Version\s*\.*:\s((\d+)(?:\.(\d+)(?:\.(\d+)(?:\.(\d+))?)?)?(a|b|rc)?)\s*$", 1) + If Not @error Then $iExtended = 1 + Local $arUDFVersion = StringRegExp($sUdfCode, "(?m)(?s)^;\s*#INDEX#\s*=*.*?;\s*Version\s*\.*:\s((\d+)(?:\.(\d+)(?:\.(\d+))?)?(a|b|rc)?)\s*$", 1) + If Not @error Then $iExtended += 2 + Local $iVerNumbers = UBound($arAutoItVersion) + If UBound($arUDFVersion)>$iVerNumbers Then $iVerNumbers = UBound($arUDFVersion) + Local $arResult[2][$iVerNumbers+1] + $arResult[0][0] = UBound($arAutoItVersion) + For $i=0 to UBound($arAutoItVersion)-1 Step 1 + $arResult[0][$i+1] = $arAutoItVersion[$i] + Next + $arResult[1][0] = UBound($arUDFVersion) + For $i=0 to UBound($arUDFVersion)-1 Step 1 + $arResult[1][$i+1] = $arUDFVersion[$i] + Next + Return SetExtended($iExtended, $arResult) +EndFunc From 5d4434fa7b0c3f838aa69df5894ab56241f4af6a Mon Sep 17 00:00:00 2001 From: WildByDesign Date: Wed, 11 Feb 2026 13:48:40 -0500 Subject: [PATCH 11/14] Add menu entries and hotkeys - Adds menu entries for Delete, Rename, Copy, Paste, and Undo. - Also adds the related hotkeys for those same functions. - Allows Undo for the most recent drag and drop, delete, rename, copy, move, etc. --- lib/SharedFunctions.au3 | 6 + src/main.au3 | 343 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 321 insertions(+), 28 deletions(-) diff --git a/lib/SharedFunctions.au3 b/lib/SharedFunctions.au3 index 4e09bff..0752669 100644 --- a/lib/SharedFunctions.au3 +++ b/lib/SharedFunctions.au3 @@ -227,3 +227,9 @@ Func _PathSplit_mod($sFilePath) Return $aArray EndFunc ;==>_PathSplit_mod + +Func _WinAPI_FindWindowEx($hParent, $hAfter, $sClass, $sTitle = "") + Local $ret = DllCall($hUser32, "hwnd", "FindWindowExW", "hwnd", $hParent, "hwnd", $hAfter, "wstr", $sClass, "wstr", $sTitle) + If @error Or Not IsArray($ret) Then Return 0 + Return $ret[0] +EndFunc diff --git a/src/main.au3 b/src/main.au3 index 3a5f37d..81ddf5f 100644 --- a/src/main.au3 +++ b/src/main.au3 @@ -64,7 +64,7 @@ Global $sBack, $sForward, $sUpLevel, $sRefresh Global $sTreeDragItem, $sListDragItems, $bDragToolActive = False Global $pLVDropTarget, $pTVDropTarget Global $bPathInputChanged = False, $bLoadStatus = False, $bCursorOverride = False -Global $idExitItem, $idAboutItem, $idDeleteItem, $idRenameItem, $idCopyItem, $idPasteItem +Global $idExitItem, $idAboutItem, $idDeleteItem, $idRenameItem, $idCopyItem, $idPasteItem, $idUndoItem Global $hCursor, $hProc Global $sSelectedItems, $g_aText, $gText Global $idSeparator, $idThemeItem, $hToolTip1, $hToolTip2, $bTooltipActive @@ -73,7 +73,8 @@ Global $hFolderHistory = __History_Create("_doUnReDo", 100, "_historyChange"), $ Global $hSolidBrush = _WinAPI_CreateBrushIndirect($BS_SOLID, 0x000000) Global $iTopSpacer = Round(12 * $iDPI) Global $aPosTip, $iOldaPos0, $iOldaPos1 -Global $sRenameFrom, $sControlFocus, $bFocusChanged = False, $bSaveEdit = False +Global $sRenameFrom, $sControlFocus, $bFocusChanged = False, $bSelectChanged = False, $bSaveEdit = False +Global $bCopy = False, $pCopyObj, $bUndo = False ; force light mode ;$isDarkMode = False @@ -212,20 +213,28 @@ Func _FilesAu3() Local $idHelpMenu = _GUICtrlCreateODTopMenu("& Help", $g_hGUI) ; File menu - $idDeleteItem = GUICtrlCreateMenuItem("&Delete", $idFileMenu) + $idDeleteItem = GUICtrlCreateMenuItem("&Delete" & @TAB & "Delete", $idFileMenu) + GUICtrlSetOnEvent(-1, "_MenuFunctions") GUICtrlSetState($idDeleteItem, $GUI_DISABLE) $idRenameItem = GUICtrlCreateMenuItem("&Rename", $idFileMenu) + GUICtrlSetOnEvent(-1, "_MenuFunctions") GUICtrlSetState($idRenameItem, $GUI_DISABLE) - $idPropertiesItem = GUICtrlCreateMenuItem("&Properties", $idFileMenu) + $idPropertiesItem = GUICtrlCreateMenuItem("&Properties" & @TAB & "Shift+P", $idFileMenu) GUICtrlSetOnEvent(-1, "_MenuFunctions") GUICtrlSetState($idPropertiesItem, $GUI_DISABLE) GUICtrlCreateMenuItem("", $idFileMenu) $idExitItem = GUICtrlCreateMenuItem("&Exit", $idFileMenu) GUICtrlSetOnEvent(-1, "_MenuFunctions") ; Edit menu - $idCopyItem = GUICtrlCreateMenuItem("&Copy", $idEditMenu) + $idUndoItem = GUICtrlCreateMenuItem("&Undo" & @TAB & "Ctrl+Z", $idEditMenu) + GUICtrlSetOnEvent(-1, "_MenuFunctions") + GUICtrlSetState($idUndoItem, $GUI_DISABLE) + GUICtrlCreateMenuItem("", $idEditMenu) + $idCopyItem = GUICtrlCreateMenuItem("&Copy" & @TAB & "Ctrl+C", $idEditMenu) + GUICtrlSetOnEvent(-1, "_MenuFunctions") GUICtrlSetState($idCopyItem, $GUI_DISABLE) - $idPasteItem = GUICtrlCreateMenuItem("&Paste", $idEditMenu) + $idPasteItem = GUICtrlCreateMenuItem("&Paste" & @TAB & "Ctrl+V", $idEditMenu) + GUICtrlSetOnEvent(-1, "_MenuFunctions") GUICtrlSetState($idPasteItem, $GUI_DISABLE) ; View menu $idThemeItem = GUICtrlCreateMenuItem("&Dark Mode", $idViewMenu) @@ -425,10 +434,13 @@ Func _FilesAu3() $i_ExStyle_Old = _WinAPI_GetWindowLong_mod(_GUIFrame_GetHandle($iFrame_A, 2), $GWL_EXSTYLE) _WinAPI_SetWindowLong_mod(_GUIFrame_GetHandle($iFrame_A, 2), $GWL_EXSTYLE, BitOR($i_ExStyle_Old, $WS_EX_ACCEPTFILES)) - Local $sMsg = "Attention: The drag and drop code is new and caution is advised." & @CRLF & @CRLF - $sMsg &= "Please consider testing drag and drop in less important areas of your file system." & @CRLF & @CRLF - $sMsg &= "To Undo the last drag and drop operation, open File Explorer and press Ctrl+Z." - ;MsgBox($MB_ICONWARNING, "Files Au3", $sMsg) + Local $sMsg = "Attention: The file operation code is new and caution is advised." & @CRLF & @CRLF + $sMsg &= "Please consider testing any file operations in less important areas of your file system. Creating an area " + $sMsg &= "on your file system with test folders and test files would be a good idea for testing purposes." & @CRLF & @CRLF + $sMsg &= "At the moment, Files Au3 allows you to Undo the most recent drag and drop, copy, move, delete, rename, etc. " + $sMsg &= "by pressing Ctrl+Z or Undo from the Edit menu. Future versions will expand to allow more than just the most " + $sMsg &= "recent Undo operation." + MsgBox($MB_ICONWARNING, "Files Au3", $sMsg) $sControlFocus = 'Tree' $bFocusChanged = True @@ -447,22 +459,98 @@ Func _FilesAu3() EndIf EndIf - If $bFocusChanged Then + If $bFocusChanged Or $bSelectChanged Then + ; keep track of which control currently has focus to determine which menu items to enable/disable $bFocusChanged = False + $bSelectChanged = False Select Case $sControlFocus = 'List' - ConsoleWrite("ListView currently has focus." & @CRLF) + ; ListView currently has focus ; need to ensure it has a selection ; figure out which menu options to enable/disable + ; get selected indices + ; if 1 selected, show Rename and Delete + ; if more than 1 don't show Rename, but show Delete, Copy + ; TODO: need to destroy Copy object after Paste; or maybe not + ; TODO: Paste can only be enabled if valid target dir and copy object exists + ; TODO: Move Properties enable/disable here as well + ; TODO: set/unset related hotkeys here too + ; TODO: for most file management functions, need to check if path is only root of drive (caution) + Local $aSelectedLV = _GUICtrlListView_GetSelectedIndices($idListview, True) + If $aSelectedLV[0] = 0 Then + ; no selections in ListView currently + GUICtrlSetState($idRenameItem, $GUI_DISABLE) + GUICtrlSetState($idCopyItem, $GUI_DISABLE) + HotKeySet("^c") + GUICtrlSetState($idDeleteItem, $GUI_DISABLE) + HotKeySet("{DELETE}") + GUICtrlSetState($idPasteItem, $bCopy ? $GUI_ENABLE : $GUI_DISABLE) + HotKeySet("^v", $bCopy ? "_PasteItems" : "") + GUICtrlSetState($idPropertiesItem, $GUI_ENABLE) + HotKeySet("+p", "_Properties") + ElseIf $aSelectedLV[0] = 1 Then + ; 1 item selection in ListView + GUICtrlSetState($idRenameItem, $GUI_ENABLE) + GUICtrlSetState($idCopyItem, $GUI_ENABLE) + HotKeySet("^c", "_CopyItems") + GUICtrlSetState($idDeleteItem, $GUI_ENABLE) + HotKeySet("{DELETE}", "_DeleteItems") + Local $sSelectedItem = _GUICtrlListView_GetItemText($idListview, $aSelectedLV[1], 0) + Local $sSelectedLV = __TreeListExplorer_GetPath($hTLESystem) & $sSelectedItem + ; is selected path a folder + If StringInStr(FileGetAttrib($sSelectedLV), "D") Then + GUICtrlSetState($idPasteItem, $bCopy ? $GUI_ENABLE : $GUI_DISABLE) + HotKeySet("^v", $bCopy ? "_PasteItems" : "") + Else + GUICtrlSetState($idPasteItem, $GUI_DISABLE) + HotKeySet("^v") + EndIf + GUICtrlSetState($idPropertiesItem, $GUI_ENABLE) + HotKeySet("+p", "_Properties") + Else + ; multiple items selected in ListView + GUICtrlSetState($idRenameItem, $GUI_DISABLE) ; not supporting multiple file Rename right now + GUICtrlSetState($idCopyItem, $GUI_ENABLE) + HotKeySet("^c", "_CopyItems") + GUICtrlSetState($idDeleteItem, $GUI_ENABLE) + HotKeySet("{DELETE}", "_DeleteItems") + GUICtrlSetState($idPasteItem, $GUI_DISABLE) + HotKeySet("^v") + GUICtrlSetState($idPropertiesItem, $GUI_ENABLE) + HotKeySet("+p", "_Properties") + EndIf Case $sControlFocus = 'Tree' - ConsoleWrite("TreeView currently has focus." & @CRLF) + ; TreeView currently has focus ; treeview always has a selection + GUICtrlSetState($idRenameItem, $GUI_ENABLE) + GUICtrlSetState($idCopyItem, $GUI_ENABLE) + HotKeySet("^c", "_CopyItems") + GUICtrlSetState($idDeleteItem, $GUI_ENABLE) + HotKeySet("{DELETE}", "_DeleteItems") + GUICtrlSetState($idPasteItem, $bCopy ? $GUI_ENABLE : $GUI_DISABLE) + HotKeySet("^v", $bCopy ? "_PasteItems" : "") + GUICtrlSetState($idPropertiesItem, $GUI_ENABLE) + HotKeySet("+p", "_Properties") Case Not $sControlFocus - ConsoleWrite("Neither the ListView or TreeView has focus right now." & @CRLF) + ; Neither the ListView or TreeView has focus right now ; in this case likely disable menu options + GUICtrlSetState($idRenameItem, $GUI_DISABLE) + GUICtrlSetState($idCopyItem, $GUI_DISABLE) + HotKeySet("^c") + GUICtrlSetState($idDeleteItem, $GUI_DISABLE) + HotKeySet("{DELETE}") + GUICtrlSetState($idPasteItem, $GUI_DISABLE) + HotKeySet("^v") + GUICtrlSetState($idPropertiesItem, $GUI_DISABLE) + HotKeySet("+p") EndSelect EndIf + ;If $bUndo Then + ; GUICtrlSetState($idUndoItem, $GUI_ENABLE) + ; HotKeySet("^z", "_UndoOp") + ;EndIf + Sleep(200) WEnd EndFunc ;==>_FilesAu3 @@ -827,6 +915,8 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) _GUIToolTip_UpdateTipText($hToolTip1, $g_hGUI, $g_hListview, $gText) EndIf Case $LVN_ITEMCHANGED + ; follow up in main While loop + $bSelectChanged = True ; item selection(s) have changed _selectionChangedLV() Case $LVN_BEGINDRAG, $LVN_BEGINRDRAG @@ -854,6 +944,11 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) DestroyDropSource($pDropSource) _Release($pDataObj) + ; track Undo availability + $bUndo = True + ; TODO: need to confirm if drop was successful or cancelled + _AllowUndo() + ; there is not supposed to be a Return value on LVN_BEGINDRAG ; however it fixes an issue with built-in drag-drop mechanism (now that we use DoDragDrop) Return 0 @@ -930,6 +1025,7 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) __TreeListExplorer_Reload($hTLESystem) _Release($pDataObj) + _AllowUndo() EndIf Case $LVN_BEGINLABELEDITA, $LVN_BEGINLABELEDITW Local $aSelectedLV = _GUICtrlListView_GetSelectedIndices($idListview, True) @@ -994,6 +1090,7 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) _WinAPI_ShellFileOperation($sRenameFrom, $sRenameTo, $FO_RENAME, BitOR($FOF_ALLOWUNDO, $FOF_NO_UI)) ; refresh TLE system to pick up any folder changes, file type changes, etc. __TreeListExplorer_Reload($hTLESystem) + _AllowUndo() Return True ; allow rename to occur EndSelect Case $NM_SETFOCUS @@ -1030,6 +1127,11 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) ;Relase the data object so the system can destroy it (prevent memory leaks) _Release($pDataObj) + + ; track Undo availability + $bUndo = True + ; TODO: need to confirm if drop was successful or cancelled + _AllowUndo() EndIf Case $TVN_KEYDOWN Local $tTVKeyDown = DllStructCreate($tagNMTVKEYDOWN, $lParam) @@ -1049,6 +1151,7 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) ;Relase the data object so the system can destroy it (prevent memory leaks) _Release($pDataObj) + _AllowUndo() EndIf Case $TVN_BEGINLABELEDITA, $TVN_BEGINLABELEDITW HotKeySet("{Enter}", "_SaveEditTV") @@ -1115,6 +1218,7 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) $sRenameTo = StringReplace($sRenameFrom, $sRenameItem, $sTextRet) _WinAPI_ShellFileOperation($sRenameFrom, $sRenameTo, $FO_RENAME, BitOR($FOF_ALLOWUNDO, $FOF_NO_UI)) ;__TreeListExplorer_Reload($hTLESystem) + _AllowUndo() Return True ; allow rename to occur EndSelect EndIf @@ -1125,8 +1229,8 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) $sControlFocus = '' $bFocusChanged = True Case $TVN_SELCHANGINGA, $TVN_SELCHANGINGW - ;ConsoleWrite("treeview selection changing" & @CRLF) - ; TODO: maybe follow up in While loop + ; follow up in main While loop + $bSelectChanged = True EndSwitch EndSwitch @@ -1416,18 +1520,25 @@ Func WM_SIZE($hWnd, $iMsg, $wParam, $lParam) EndFunc ;==>WM_SIZE Func _Properties() - Local $aSelectedLV = _GUICtrlListView_GetSelectedIndices($idListview, True) - If $aSelectedLV[0] = 1 Then - _WinAPI_ShellObjectProperties($sCurrentPath) - ElseIf $aSelectedLV[0] = 0 Then - _WinAPI_ShellObjectProperties(__TreeListExplorer_GetPath($hTLESystem)) - Else - ;$sSelectedItems - Local $aFiles = StringSplit($sSelectedItems, "|") - _ArrayDelete($aFiles, $aFiles[0]) - _ArrayDelete($aFiles, 0) - _WinAPI_SHMultiFileProperties(__TreeListExplorer_GetPath($hTLESystem), $aFiles) - EndIf + Select + Case $sControlFocus = 'List' + Local $aSelectedLV = _GUICtrlListView_GetSelectedIndices($idListview, True) + If $aSelectedLV[0] = 1 Then + _WinAPI_ShellObjectProperties($sCurrentPath) + ElseIf $aSelectedLV[0] = 0 Then + _WinAPI_ShellObjectProperties(__TreeListExplorer_GetPath($hTLESystem)) + Else + ;$sSelectedItems + Local $aFiles = StringSplit($sSelectedItems, "|") + _ArrayDelete($aFiles, $aFiles[0]) + _ArrayDelete($aFiles, 0) + _WinAPI_SHMultiFileProperties(__TreeListExplorer_GetPath($hTLESystem), $aFiles) + EndIf + Case $sControlFocus = 'Tree' + Local $hTreeItem = _GUICtrlTreeView_GetSelection($g_hTreeView) + Local $sItemText = TreeItemToPath($g_hTreeView, $hTreeItem) + _WinAPI_ShellObjectProperties($sItemText) + EndSelect EndFunc ;==>_Properties ; #FUNCTION# ==================================================================================================================== @@ -1959,9 +2070,185 @@ Func _MenuFunctions() _Properties() Case $idAboutItem _About() + Case $idDeleteItem + _DeleteItems() + ; track Undo availability + $bUndo = True + _AllowUndo() + Case $idRenameItem + _RenameItem() + ; track Undo availability + $bUndo = True + _AllowUndo() + Case $idCopyItem + _CopyItems() + ; track Undo availability + $bUndo = True + Case $idPasteItem + _PasteItems() + ; track Undo availability + $bUndo = True + _AllowUndo() + Case $idUndoItem + _UndoOp() EndSwitch EndFunc ;==>_MenuFunctions +Func _UndoOp() + ConsoleWrite("Undo from menu not available yet." & @CRLF) + ; TODO: need to keep track of how many times Undo, may limit to 1 right now to be safe + ; reset Undo availability + Local Const $hProgman = WinGetHandle("[CLASS:Progman]") + Local Const $hCurrent = WinGetHandle("[ACTIVE]") + + Local Const $hSHELLDLL_DefView = _WinAPI_FindWindowEx($hProgman, 0, "SHELLDLL_DefView", "") + Local Const $hSysListView32 = _WinAPI_FindWindowEx($hSHELLDLL_DefView, 0, "SysListView32", "FolderView") + + _WinAPI_SetForegroundWindow($hSysListView32) + _WinAPI_SetFocus($hSysListView32) + + ControlSend($hSysListView32, "", "", "^z") + WinActivate($hCurrent) + + __TreeListExplorer_Reload($hTLESystem) + + $bUndo = False + GUICtrlSetState($idUndoItem, $GUI_DISABLE) + HotKeySet("^z") +EndFunc + +Func _AllowUndo() + GUICtrlSetState($idUndoItem, $GUI_ENABLE) + HotKeySet("^z", "_UndoOp") +EndFunc + +Func _PasteItems() + Local $sFullPath + Select + Case $sControlFocus = 'List' + Local $aSelectedLV = _GUICtrlListView_GetSelectedIndices($idListview, True) + If $aSelectedLV[0] = 0 Then + ; no selections in ListView currently, current path is Paste directory + Local $sSelectedLV = __TreeListExplorer_GetPath($hTLESystem) + $sFullPath = $sSelectedLV + ElseIf $aSelectedLV[0] = 1 Then + ; 1 item selection in ListView + Local $sSelectedItem = _GUICtrlListView_GetItemText($idListview, $aSelectedLV[1], 0) + Local $sSelectedLV = __TreeListExplorer_GetPath($hTLESystem) & $sSelectedItem + ; is selected path a folder + If StringInStr(FileGetAttrib($sSelectedLV), "D") Then + $sSelectedLV = $sSelectedLV + Else + Return + EndIf + EndIf + $iFlags = BitOR($FOFX_ADDUNDORECORD, $FOFX_RECYCLEONDELETE, $FOFX_NOCOPYHOOKS) + $sAction = "CopyItems" + _IFileOperationFile($pCopyObj, $sFullPath, $sAction, $iFlags) + __TreeListExplorer_Reload($hTLESystem) + Case $sControlFocus = 'Tree' + Local $hTreeItem = _GUICtrlTreeView_GetSelection($g_hTreeView) + Local $sItemText = TreeItemToPath($g_hTreeView, $hTreeItem) + $sFullPath = $sItemText + $iFlags = BitOR($FOFX_ADDUNDORECORD, $FOFX_RECYCLEONDELETE, $FOFX_NOCOPYHOOKS) + $sAction = "CopyItems" + _IFileOperationFile($pCopyObj, $sFullPath, $sAction, $iFlags) + __TreeListExplorer_Reload($hTLESystem) + EndSelect +EndFunc + +Func _CopyItems() + Select + Case $sControlFocus = 'List' + ; if previous copy object exists and user initiates new copy, release previous object + If $bCopy Then _Release($pCopyObj) + + ; create array with list of selected listview items + Local $aItems = _GUICtrlListView_GetSelectedIndices($g_hListView, True) + For $i = 1 To $aItems[0] + $aItems[$i] = __TreeListExplorer_GetPath($hTLESystem) & _GUICtrlListView_GetItemText($g_hListView, $aItems[$i]) + Next + + ; TODO: $pCopyObj will probably need to be Global + ;Local $pDataObj = GetDataObjectOfFiles($hWnd, $aItems) ; MattyD function + + _ArrayDelete($aItems, 0) ; only needed for GetDataObjectOfFile_B + $pCopyObj = GetDataObjectOfFile_B($aItems) ; jugador function + + ; we don't want to release this until after Paste + ;_Release($pCopyObj) + + ; keep track of copy status for menu + $bCopy = True + Case $sControlFocus = 'Tree' + ; if previous copy object exists and user initiates new copy, release previous object + If $bCopy Then _Release($pCopyObj) + + Local $hTreeItem = _GUICtrlTreeView_GetSelection($g_hTreeView) + Local $sItemText = TreeItemToPath($g_hTreeView, $hTreeItem) + + ;Get an IDataObject representing the file to copy + $pCopyObj = GetDataObjectOfFile(_GUIFrame_GetHandle($iFrame_A, 1), $sItemText) + + ; we don't want to release this until after Paste + ;_Release($pCopyObj) + + ; keep track of copy status for menu + $bCopy = True + EndSelect +EndFunc + +Func _RenameItem() + Select + Case $sControlFocus = 'List' + Local $aSelectedLV = _GUICtrlListView_GetSelectedIndices($idListview, True) + ; there should only be one selected item during a rename + Local $iItemLV = $aSelectedLV[1] + Local $hEditLabel = _GUICtrlListView_EditLabel($g_hListView, $iItemLV) + Case $sControlFocus = 'Tree' + Local $hTreeItem = _GUICtrlTreeView_GetSelection($g_hTreeView) + _GUICtrlTreeView_EditText($g_hTreeView, $hTreeItem) + EndSelect +EndFunc + +Func _DeleteItems() + Select + Case $sControlFocus = 'List' + ; create array with list of selected listview items + Local $aItems = _GUICtrlListView_GetSelectedIndices($g_hListview, True) + For $i = 1 To $aItems[0] + $aItems[$i] = __TreeListExplorer_GetPath($hTLESystem) & _GUICtrlListView_GetItemText($g_hListview, $aItems[$i]) + Next + + ;$pDataObj = GetDataObjectOfFiles($hWnd, $aItems) ; MattyD function + + _ArrayDelete($aItems, 0) ; only needed for GetDataObjectOfFile_B + Local $pDataObj = GetDataObjectOfFile_B($aItems) ; jugador function + + Local $iFlags = BitOR($FOFX_ADDUNDORECORD, $FOFX_RECYCLEONDELETE, $FOFX_NOCOPYHOOKS) + _IFileOperationDelete($pDataObj, $iFlags) + + __TreeListExplorer_Reload($hTLESystem) + + _Release($pDataObj) + Case $sControlFocus = 'Tree' + Local $hTreeItemSel = _GUICtrlTreeView_GetSelection($g_hTreeView) + Local $sItemText = TreeItemToPath($g_hTreeView, $hTreeItemSel) + + Local $pDataObj, $pDropSource + + ;Get an IDataObject representing the file to copy + $pDataObj = GetDataObjectOfFile(_GUIFrame_GetHandle($iFrame_A, 1), $sItemText) + $iFlags = BitOR($FOFX_ADDUNDORECORD, $FOFX_RECYCLEONDELETE, $FOFX_NOCOPYHOOKS) + _IFileOperationDelete($pDataObj, $iFlags) + + __TreeListExplorer_Reload($hTLESystem) + + ;Relase the data object so the system can destroy it (prevent memory leaks) + _Release($pDataObj) + EndSelect +EndFunc + Func _EndDrag() ; reorder columns after header drag and drop _reorderLVCols() From a6b939d9589f4464d6384e7662c2bbeeca04ac74 Mon Sep 17 00:00:00 2001 From: WildByDesign Date: Thu, 12 Feb 2026 07:17:08 -0500 Subject: [PATCH 12/14] Return drop result from SHDoDragDrop - Return drop result from SHDoDragDrop to determine whether drop was successful or not. - Allow Undo on successful drag and drop - Clean up unneeded drag and drop code --- lib/DropTargetObject.au3 | 1 - src/main.au3 | 72 +++++++++------------------------------- 2 files changed, 16 insertions(+), 57 deletions(-) diff --git a/lib/DropTargetObject.au3 b/lib/DropTargetObject.au3 index 5df39f3..1b5b672 100644 --- a/lib/DropTargetObject.au3 +++ b/lib/DropTargetObject.au3 @@ -189,7 +189,6 @@ Func __Mthd_DragOver($pThis, $iKeyState, $iPoint, $piEffect) Local $aListItem = _GUICtrlListView_HitTest($tData.hTarget, $tPoint.X, $tPoint.Y) Local $sItemText = _GUICtrlListView_GetItemText($tData.hTarget, $aListItem[0]) Local $sFullPath = __TreeListExplorer_GetPath(1) & $sItemText - ;ConsoleWrite("$sFullPath: " & $sFullPath & @CRLF) If Not $sItemText Then ; get the currently selected path $sDirPath = __TreeListExplorer_GetPath(1) diff --git a/src/main.au3 b/src/main.au3 index 81ddf5f..7fe9a4d 100644 --- a/src/main.au3 +++ b/src/main.au3 @@ -74,7 +74,7 @@ Global $hSolidBrush = _WinAPI_CreateBrushIndirect($BS_SOLID, 0x000000) Global $iTopSpacer = Round(12 * $iDPI) Global $aPosTip, $iOldaPos0, $iOldaPos1 Global $sRenameFrom, $sControlFocus, $bFocusChanged = False, $bSelectChanged = False, $bSaveEdit = False -Global $bCopy = False, $pCopyObj, $bUndo = False +Global $bCopy = False, $pCopyObj ; force light mode ;$isDarkMode = False @@ -442,6 +442,7 @@ Func _FilesAu3() $sMsg &= "recent Undo operation." MsgBox($MB_ICONWARNING, "Files Au3", $sMsg) + ; TreeView has initial focus $sControlFocus = 'Tree' $bFocusChanged = True @@ -466,16 +467,6 @@ Func _FilesAu3() Select Case $sControlFocus = 'List' ; ListView currently has focus - ; need to ensure it has a selection - ; figure out which menu options to enable/disable - ; get selected indices - ; if 1 selected, show Rename and Delete - ; if more than 1 don't show Rename, but show Delete, Copy - ; TODO: need to destroy Copy object after Paste; or maybe not - ; TODO: Paste can only be enabled if valid target dir and copy object exists - ; TODO: Move Properties enable/disable here as well - ; TODO: set/unset related hotkeys here too - ; TODO: for most file management functions, need to check if path is only root of drive (caution) Local $aSelectedLV = _GUICtrlListView_GetSelectedIndices($idListview, True) If $aSelectedLV[0] = 0 Then ; no selections in ListView currently @@ -488,6 +479,7 @@ Func _FilesAu3() HotKeySet("^v", $bCopy ? "_PasteItems" : "") GUICtrlSetState($idPropertiesItem, $GUI_ENABLE) HotKeySet("+p", "_Properties") + GUICtrlSetState($idPropertiesLV, $GUI_ENABLE) ElseIf $aSelectedLV[0] = 1 Then ; 1 item selection in ListView GUICtrlSetState($idRenameItem, $GUI_ENABLE) @@ -507,6 +499,7 @@ Func _FilesAu3() EndIf GUICtrlSetState($idPropertiesItem, $GUI_ENABLE) HotKeySet("+p", "_Properties") + GUICtrlSetState($idPropertiesLV, $GUI_ENABLE) Else ; multiple items selected in ListView GUICtrlSetState($idRenameItem, $GUI_DISABLE) ; not supporting multiple file Rename right now @@ -518,6 +511,7 @@ Func _FilesAu3() HotKeySet("^v") GUICtrlSetState($idPropertiesItem, $GUI_ENABLE) HotKeySet("+p", "_Properties") + GUICtrlSetState($idPropertiesLV, $GUI_ENABLE) EndIf Case $sControlFocus = 'Tree' ; TreeView currently has focus @@ -531,6 +525,7 @@ Func _FilesAu3() HotKeySet("^v", $bCopy ? "_PasteItems" : "") GUICtrlSetState($idPropertiesItem, $GUI_ENABLE) HotKeySet("+p", "_Properties") + GUICtrlSetState($idPropertiesLV, $GUI_DISABLE) Case Not $sControlFocus ; Neither the ListView or TreeView has focus right now ; in this case likely disable menu options @@ -543,14 +538,10 @@ Func _FilesAu3() HotKeySet("^v") GUICtrlSetState($idPropertiesItem, $GUI_DISABLE) HotKeySet("+p") + GUICtrlSetState($idPropertiesLV, $GUI_DISABLE) EndSelect EndIf - ;If $bUndo Then - ; GUICtrlSetState($idUndoItem, $GUI_ENABLE) - ; HotKeySet("^z", "_UndoOp") - ;EndIf - Sleep(200) WEnd EndFunc ;==>_FilesAu3 @@ -682,21 +673,6 @@ Func _selectionChangedLV() Local $iItemCount = $iFileCount + $iDirCount - ; Properties dialog - If $iItemCount = 1 Then - $sCurrentPath = $sSelectedLV - GUICtrlSetState($idPropertiesItem, $GUI_ENABLE) - GUICtrlSetState($idPropertiesLV, $GUI_ENABLE) - ElseIf $iItemCount <> 1 And $iItemCount <> 0 Then - ; multi-properties - ; need number of selected items to declare array - GUICtrlSetState($idPropertiesItem, $GUI_ENABLE) - GUICtrlSetState($idPropertiesLV, $GUI_ENABLE) - Else - GUICtrlSetState($idPropertiesItem, $GUI_DISABLE) - GUICtrlSetState($idPropertiesLV, $GUI_DISABLE) - EndIf - If $iItemCount > 1 Then $g_aText[1] = " " & $iItemCount & " items selected" ElseIf $iItemCount = 1 Then @@ -938,19 +914,17 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) ;Create an IDropSource to handle our end of the drag/drop operation. $pDropSource = CreateDropSource() - _SHDoDragDrop($pDataObj, $pDropSource, BitOR($DROPEFFECT_MOVE, $DROPEFFECT_COPY, $DROPEFFECT_LINK)) + Local $iResult = _SHDoDragDrop($pDataObj, $pDropSource, BitOR($DROPEFFECT_MOVE, $DROPEFFECT_COPY, $DROPEFFECT_LINK)) ;__TreeListExplorer_Reload($hTLESystem) DestroyDropSource($pDropSource) _Release($pDataObj) - ; track Undo availability - $bUndo = True - ; TODO: need to confirm if drop was successful or cancelled - _AllowUndo() + ; allow Undo if drop returns successful + If $iResult = $DRAGDROP_S_DROP Then _AllowUndo() ; there is not supposed to be a Return value on LVN_BEGINDRAG - ; however it fixes an issue with built-in drag-drop mechanism (now that we use DoDragDrop) + ; however it fixes an issue with built-in drag-drop mechanism Return 0 Case $LVN_HOTTRACK ; Sent by a list-view control When the user moves the mouse over an item Local $tInfo2 = DllStructCreate($tagNMLISTVIEW, $lParam) @@ -1119,7 +1093,7 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) $pDropSource = CreateDropSource() If Not @error Then - _SHDoDragDrop($pDataObj, $pDropSource, BitOR($DROPEFFECT_MOVE, $DROPEFFECT_COPY, $DROPEFFECT_LINK)) + Local $iResult = _SHDoDragDrop($pDataObj, $pDropSource, BitOR($DROPEFFECT_MOVE, $DROPEFFECT_COPY, $DROPEFFECT_LINK)) ;Operation done, destroy our drop source. (Can't just IUnknown_Release() this one!) DestroyDropSource($pDropSource) @@ -1128,10 +1102,8 @@ Func WM_NOTIFY2($hWnd, $iMsg, $wParam, $lParam) ;Relase the data object so the system can destroy it (prevent memory leaks) _Release($pDataObj) - ; track Undo availability - $bUndo = True - ; TODO: need to confirm if drop was successful or cancelled - _AllowUndo() + ; allow Undo if drop returns successful + If $iResult = $DRAGDROP_S_DROP Then _AllowUndo() EndIf Case $TVN_KEYDOWN Local $tTVKeyDown = DllStructCreate($tagNMTVKEYDOWN, $lParam) @@ -2072,22 +2044,14 @@ Func _MenuFunctions() _About() Case $idDeleteItem _DeleteItems() - ; track Undo availability - $bUndo = True _AllowUndo() Case $idRenameItem _RenameItem() - ; track Undo availability - $bUndo = True _AllowUndo() Case $idCopyItem _CopyItems() - ; track Undo availability - $bUndo = True Case $idPasteItem _PasteItems() - ; track Undo availability - $bUndo = True _AllowUndo() Case $idUndoItem _UndoOp() @@ -2095,9 +2059,7 @@ Func _MenuFunctions() EndFunc ;==>_MenuFunctions Func _UndoOp() - ConsoleWrite("Undo from menu not available yet." & @CRLF) - ; TODO: need to keep track of how many times Undo, may limit to 1 right now to be safe - ; reset Undo availability + ; perform Undo by sending Ctrl+Z to the Desktop (Progman class, SysListView32 class) Local Const $hProgman = WinGetHandle("[CLASS:Progman]") Local Const $hCurrent = WinGetHandle("[ACTIVE]") @@ -2112,7 +2074,6 @@ Func _UndoOp() __TreeListExplorer_Reload($hTLESystem) - $bUndo = False GUICtrlSetState($idUndoItem, $GUI_DISABLE) HotKeySet("^z") EndFunc @@ -2169,7 +2130,6 @@ Func _CopyItems() $aItems[$i] = __TreeListExplorer_GetPath($hTLESystem) & _GUICtrlListView_GetItemText($g_hListView, $aItems[$i]) Next - ; TODO: $pCopyObj will probably need to be Global ;Local $pDataObj = GetDataObjectOfFiles($hWnd, $aItems) ; MattyD function _ArrayDelete($aItems, 0) ; only needed for GetDataObjectOfFile_B @@ -2349,7 +2309,7 @@ Func _SHDoDragDrop($pDataObj, $pDropSource, $iOKEffects) Local $aCall = DllCall($hShell32, "long", "SHDoDragDrop", "hwnd", Null, "ptr", $pDataObj, "ptr", Null, "dword", $iOKEffects, "ptr*", 0) If @error Then Return SetError(@error, @extended, $aCall) - Return SetError($aCall[0], 0, $aCall[4]) + Return '0x' & Hex($aCall[0]) EndFunc ;==>_SHDoDragDrop Func GetDataObjectOfFile($hWnd, $sPath) From 90c72145711198a805f2a14c84c7ed8b28433bfc Mon Sep 17 00:00:00 2001 From: WildByDesign Date: Thu, 12 Feb 2026 09:01:27 -0500 Subject: [PATCH 13/14] Single item Properties was failing Single item Properties was failing to show correctly for ListView. --- src/main.au3 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main.au3 b/src/main.au3 index 7fe9a4d..e43e8f7 100644 --- a/src/main.au3 +++ b/src/main.au3 @@ -1496,7 +1496,9 @@ Func _Properties() Case $sControlFocus = 'List' Local $aSelectedLV = _GUICtrlListView_GetSelectedIndices($idListview, True) If $aSelectedLV[0] = 1 Then - _WinAPI_ShellObjectProperties($sCurrentPath) + Local $sSelectedItem = _GUICtrlListView_GetItemText($idListview, $aSelectedLV[1], 0) + Local $sSelectedLV = __TreeListExplorer_GetPath($hTLESystem) & $sSelectedItem + _WinAPI_ShellObjectProperties($sSelectedLV) ElseIf $aSelectedLV[0] = 0 Then _WinAPI_ShellObjectProperties(__TreeListExplorer_GetPath($hTLESystem)) Else From 9360c98cf36a02bdfe4afc3fc459da70c4c0253f Mon Sep 17 00:00:00 2001 From: WildByDesign Date: Sun, 15 Feb 2026 19:24:39 -0500 Subject: [PATCH 14/14] Add Callback Filter for hidden files - add Show Hidden Files to menu - add Hide Protected System Files to menu - add related callback filter for those options to function --- src/main.au3 | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/src/main.au3 b/src/main.au3 index e43e8f7..3976c72 100644 --- a/src/main.au3 +++ b/src/main.au3 @@ -64,7 +64,8 @@ Global $sBack, $sForward, $sUpLevel, $sRefresh Global $sTreeDragItem, $sListDragItems, $bDragToolActive = False Global $pLVDropTarget, $pTVDropTarget Global $bPathInputChanged = False, $bLoadStatus = False, $bCursorOverride = False -Global $idExitItem, $idAboutItem, $idDeleteItem, $idRenameItem, $idCopyItem, $idPasteItem, $idUndoItem +Global $idExitItem, $idAboutItem, $idDeleteItem, $idRenameItem, $idCopyItem, $idPasteItem, $idUndoItem, $idHiddenItem, $idSystemItem +Global $bHideHidden = False, $bHideSystem = False Global $hCursor, $hProc Global $sSelectedItems, $g_aText, $gText Global $idSeparator, $idThemeItem, $hToolTip1, $hToolTip2, $bTooltipActive @@ -239,6 +240,15 @@ Func _FilesAu3() ; View menu $idThemeItem = GUICtrlCreateMenuItem("&Dark Mode", $idViewMenu) GUICtrlSetOnEvent(-1, "_MenuFunctions") + GUICtrlCreateMenuItem("", $idViewMenu) + $idHiddenItem = GUICtrlCreateMenuItem("&Show Hidden Files", $idViewMenu) + GUICtrlSetOnEvent(-1, "_MenuFunctions") + GUICtrlSetState($idHiddenItem, $GUI_CHECKED) + $bHideHidden = False + $idSystemItem = GUICtrlCreateMenuItem("&Hide Protected System Files", $idViewMenu) + GUICtrlSetOnEvent(-1, "_MenuFunctions") + GUICtrlSetState($idSystemItem, $GUI_CHECKED) + $bHideSystem = True ; Help menu $idAboutItem = GUICtrlCreateMenuItem("&About", $idHelpMenu) GUICtrlSetOnEvent(-1, "_MenuFunctions") @@ -284,6 +294,9 @@ Func _FilesAu3() __TreeListExplorer_AddView($hTLESystem, $idTreeView) __TreeListExplorer_SetViewIconSize($idTreeView, $iTreeListIconSize) + ; set callback to allow filtering of hidden and/or protected system files + __TreeListExplorer_SetCallback($idTreeView, $__TreeListExplorer_Callback_Filter, "_filterCallback") + ; Create listview frame _GUIFrame_Switch($iFrame_A, 2) @@ -340,6 +353,9 @@ Func _FilesAu3() __TreeListExplorer_SetCallback($idListview, $__TreeListExplorer_Callback_ListViewPaths, "_handleListViewData") __TreeListExplorer_SetCallback($idListview, $__TreeListExplorer_Callback_ListViewItemCreated, "_handleListViewItemCreated") + ; set callback to allow filtering of hidden and/or protected system files + __TreeListExplorer_SetCallback($idListview, $__TreeListExplorer_Callback_Filter, "_filterCallback") + ; Set resizing flag for all created frames _GUIFrame_ResizeSet(0) @@ -2057,6 +2073,28 @@ Func _MenuFunctions() _AllowUndo() Case $idUndoItem _UndoOp() + Case $idHiddenItem + If BitAND(GUICtrlRead($idHiddenItem), $GUI_CHECKED) = $GUI_CHECKED Then + GUICtrlSetState($idHiddenItem, $GUI_UNCHECKED) + $bHideHidden = True + Else + GUICtrlSetState($idHiddenItem, $GUI_CHECKED) + $bHideHidden = False + EndIf + + __TreeListExplorer_ReloadView($idListView, True) + __TreeListExplorer_ReloadView($idTreeView, True) + Case $idSystemItem + If BitAND(GUICtrlRead($idSystemItem), $GUI_CHECKED) = $GUI_CHECKED Then + GUICtrlSetState($idSystemItem, $GUI_UNCHECKED) + $bHideSystem = False + Else + GUICtrlSetState($idSystemItem, $GUI_CHECKED) + $bHideSystem = True + EndIf + + __TreeListExplorer_ReloadView($idListView, True) + __TreeListExplorer_ReloadView($idTreeView, True) EndSwitch EndFunc ;==>_MenuFunctions @@ -2570,3 +2608,28 @@ Func _GetVersion($sUdfCode) Next Return SetExtended($iExtended, $arResult) EndFunc + +Func _filterCallback($hSystem, $hView, $bIsFolder, $sPath, $sName, $sExt) + If $bHideHidden Or $bHideSystem Then + ; ensure that root drive letters do not get hidden + If _WinAPI_PathIsRoot_mod($sPath&$sName&$sExt) Then Return True + + Switch $sName + Case "$RECYCLE.BIN" + Return False + Case "System Volume Information" + Return False + EndSwitch + EndIf + + Select + Case $bHideSystem + ; filter out files and folders with System attribute + If StringInStr(FileGetAttrib($sPath&$sName&$sExt), "S", 2)>0 Then Return False + Case $bHideHidden + ; filter out files and folders with Hidden attribute + If StringInStr(FileGetAttrib($sPath&$sName&$sExt), "H", 2)>0 Then Return False + EndSelect + + Return True +EndFunc