WildByDesign Posted Saturday at 10:58 AM Posted Saturday at 10:58 AM Speaking of IFileOperation, I should probably share what I have at the moment which works really well. I may need to add more to the Actions parts at some point: Switch $sAction Case "CopyItems" $oIFileOperation.CopyItems($pDataObj, $pIShellItemTo) Case "MoveItems" $oIFileOperation.MoveItems($pDataObj, $pIShellItemTo) EndSwitch MoveItems and CopyItems are good because they work well with the object created from either Matty or jagudor's functions, whether it's only one file or folders containing many files. Anyway, I call it with the following: Local $iFlags = BitOR($FOFX_ADDUNDORECORD, $FOFX_RECYCLEONDELETE, $FOFX_NOCOPYHOOKS) Local $sAction = "CopyItems" ; CopyItems or MoveItems would get determined earlier, but this is for example _IFileOperationFile($pDataObject, $sFullPath, $sAction, $iFlags) And here is the IFileOperation code, originally from @Danyfirex but I've modified it to work with this drag/drop object. expandcollapse popup#include-once #include <WinAPIShellEx.au3> ; 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 Danyfirex 1
WildByDesign Posted Saturday at 03:46 PM Posted Saturday at 03:46 PM 14 hours ago, MattyD said: If this is a DROPEFFECT_MOVE, then obviously do that. If you "remove" the the original, we don't want to signal the source to erase it too. So, in that case we should set the dropeffect flag to something else again before returning out of IDropTarget::Drop(). I am having some difficulty on the Move stuff. I added more than a dozen ConsoleWrites to strategic areas to figure it out. While still dragging, the effect stays on DROPEFFECT_MOVE as it should. However, there is a brief moment on Drop when the system seems to switch it to DROPEFFECT_NONE automatically. It turns out that @ProgAndy was ahead of the game back in 2009 with his DoDragDrop script. I can’t do proper forum link on my phone since the option is not there, so link will be messy: Link: From his DoDragDropGUI.au3 script While loop: Quote Case $DROPEFFECT_NONE ; on Win 9x nothing, but NT/2000 and above have MOVE-operaion here, too ; on NT/200 and above, a move-action will also return DROPEFFECT_NONE. So you have to check that manually: Sorry for inconsistencies, copy and paste from my phone is almost useless.
MattyD Posted yesterday at 12:08 AM Posted yesterday at 12:08 AM (edited) 13 hours ago, WildByDesign said: $tEffect.iEffect = $iRetEffect Is the effect contained in that line the one which gets reported back to the app which started the drag? Yep its an in/out param. Its why the object receives the drop effect as a pointer instead of a dword - its literally passed ByRef On input it tells us what we're allowed to do (combination of values). On output we report what the result of a drop would be. The source then reads this via IDropSource::GiveFeedback(), and its also returned by DoDragDrop as an output param. 13 hours ago, WildByDesign said: Can I (or do I even need to) get a Return value (drop effect) from the __DoDropResponse() function? Its an internal helper function - it doesn't interact with the outside world, so you can do whatever you want. We set the drop effect anyway, so its probably not necessary to return the value as well - just check the value where it lives. I have __DoDropResponse returning info on where I should drop items in a ListView/TreeView. 13 hours ago, WildByDesign said: Does that order make sense? Yeah makes sense. DoDropResponse first. ;Within IDropTarget::Drop __DoDropResponse($tData, $iKeyState, $tPoint, $piEffect) Local $tEffect = DllStructCreate("dword iEffect", $piEffect) Switch $tEffect.iEffect Case $DROPEFFECT_MOVE ;FileMove() $tEffect.iEffect = $DROPEFFECT_NONE ;Leaving $tEffect.iEffect = $DROPEFFECT_MOVE tells the source to delete the original. ;if we've successfully moved the file here (not just copied it), we should change the flag. Case $DROPEFFECT_COPY ;FileCopy() Case $DROPEFFECT_LINK ;FileCreateShortcut() EndSwitch __SetPerformedDropEffect($pDataObject, $tEffect.iEffect) Edited yesterday at 12:21 AM by MattyD WildByDesign 1
WildByDesign Posted yesterday at 12:34 AM Posted yesterday at 12:34 AM 21 minutes ago, MattyD said: Yep its an in/out param. Its why the object receives the drop effect as a pointer instead of a dword - its literally passed ByRef On input it tells us what we're allowed to do (combination of values). On output we report what the result of a drop would be. The source then reads this via IDropSource::GiveFeedback(), and its also returned by DoDragDrop as an output param. Thanks for clarifying. That helps me understand the general flow of everything. 22 minutes ago, MattyD said: Yeah makes sense. DoDropResponse first. Speaking of DoDropResponse, is there any way for me to access $pDataObject from that function? Currently, I am obtaining file information from $pDataObject in the Drop method function. But if I can do it within DoDropResponse it might be better organized that way.
MattyD Posted yesterday at 12:34 AM Posted yesterday at 12:34 AM 8 hours ago, WildByDesign said: From his DoDragDropGUI.au3 script While loop: Quote Case $DROPEFFECT_NONE ; on Win 9x nothing, but NT/2000 and above have MOVE-operaion here, too ; on NT/200 and above, a move-action will also return DROPEFFECT_NONE. So you have to check that manually: Yeah that tracks. He's checking the result of DoDragDrop here (which is called from the source side). If the target successfully moved the file, we don't need to do anything more for the move. Andy needs to update his listview however, so he needs to know if the move actually happened, or if the operation was a "no-op". Might be worth checking the "performed operation" on the dataobject after the fact to see if that tells you the real operation... I'm pretty sure it should mirror the dropeffect, but maybe I missed something.
MattyD Posted yesterday at 12:43 AM Posted yesterday at 12:43 AM 1 minute ago, WildByDesign said: is there any way for me to access $pDataObject from that function? yep I'm stashing it internally in the dropTarget object on IDropTarget::DragEnter $tData.pDataObject WildByDesign 1
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now