FileOps - Copy | Move | Delete | Rename (with Win32 progress bar) - 2022/11/12 - beta.15

Post your working scripts, libraries and tools.
User avatar
TheArkive
Posts: 1027
Joined: 05 Aug 2016, 08:06
Location: The Construct
Contact:

FileOps - Copy | Move | Delete | Rename (with Win32 progress bar) - 2022/11/12 - beta.15

18 May 2021, 08:32

File Copy, Delete, Rename, Move with default Win32 progress dialog.

Links: Usage:
  • obj := FileOps() to make an instance.
  • obj.Copy(src, dest [, no_confirm := false])
  • obj.Rename() & obj.Move() same as above
  • obj.Delete(src [, no_confirm := false])
Features:
  • Adjustments for Unicode/ANSI and x86/x64
  • no_confirm := true acts as "overwrite" on Copy action.
  • Flags can be set directly by one of the following:
    • obj.Flags := 0x1234
    • obj.FlagStr := "flag_name flag_name ..."
  • obj.error contains error codes on return. Non-zero = an error.
  • obj.abort contains abort codes in case of user/system aborting the action.
Limitations:
  • Long paths are only supported in theory. My tests indicate it doesn't work.
  • Setting ProgressTitle doesn't seem to work. The default title is more useful anyway.
  • I don't plan to implement any class solutions for WantMappingHandle for now.
  • Wildcards are not allowed in the directory name, an error will be thrown.
  • All relative paths are assumed to be relative to A_ScriptDir and are converted to fully qualified paths before execution.
  • All flags are reset after execution. This is done to prevent unexpected/dangerous results related to mismanagement of flag values.
  • If you set flags manually, then the no_confirm parameter is ignored.
=================================================================================
Updates
=================================================================================
Last edited by TheArkive on 12 Nov 2022, 05:19, edited 4 times in total.
LBJ
Posts: 19
Joined: 10 Aug 2020, 04:22

Re: FileOps - Copy | Move | Delete | Rename (with Win32 progress bar) - 2021/06/21 - beta.1

27 Feb 2022, 18:41

G'day TheArkive,

Firstly, thanks again for your brilliant AHK Portable Installer. It makes life very easy for multi-version testing.

Re your shfileoperation code, you have a small error at...

Line 125...

Code: Select all

FlagStr := "", Flags := "", error := 0, abort := 0, Title := ""

That initializes Flags to an empty string instead of a numa 0.

If FlagStr is then provided with a string flag rather than using the numa Flags, an "Expected a number but got an empty string" error is raised at..

Line 173...

Code: Select all

this.Flags := this.Flags | flags.%_flag%

You can create the error with the following.

Code: Select all

obj := FileOps()
obj.FlagStr := 'NoRecursion'
obj.copy('U:\*', 'V:\dump')

Best regards,

LBJ
User avatar
TheArkive
Posts: 1027
Joined: 05 Aug 2016, 08:06
Location: The Construct
Contact:

Re: FileOps - Copy | Move | Delete | Rename (with Win32 progress bar) - 2022/02/28 - beta.3

28 Feb 2022, 00:03

2022/02/28
  • fixed minor oversight when setting flags via text names - thanks to LBJ
@LBJ

Thanks for that. Fixed.

I kept it as being initialized with "" because a flags value of 0 is technically setting zero options, but "" indicates that the value is indeed unset.

As long as the user doesn't set both Flags and FlagStr properties, this should work fine. A warning has been added to the docs/comments.

EDIT: And I'm glad you're finding a good use for AHK Portable Installer. :thumbup: I use it all the time myself as well.
LBJ
Posts: 19
Joined: 10 Aug 2020, 04:22

Re: FileOps - Copy | Move | Delete | Rename (with Win32 progress bar) - 2022/02/28 - beta.3

01 Mar 2022, 21:52

G'day @TheArkive,

I needed to use SHFileOperationW in a project, which is how I came upon your solution, but because I also needed the renamed mappings, I found it cleaner to code my own solution afresh.

In doing that, I noticed you have another minor issue in your SHFileOperation structure at...

Code: Select all

    Static hwnd := 0
         , wFunc         := (A_PtrSize=4) ? 4  : 8
         , From          := (A_PtrSize=4) ? 8  : 16
         , To            := (A_PtrSize=4) ? 12 : 24
         , Flags         := (A_PtrSize=4) ? 16 : 32
         , AnyOpsAbort   := (A_PtrSize=4) ? 20 : 36
         , NameMappings  := (A_PtrSize=4) ? 24 : 40
         , ProgressTitle := (A_PtrSize=4) ? 28 : 48

In the x64 structure, a 32 bit Int is used for fFlags just as you've coded for, but in the x86 structure, it's a 16 bit Short. You're assuming the former for both cases.

For x64, you're fine, but for x86 you're currently 16 bits overstated. Consequently, you don't fetch the correct values from the structure for fAnyOperationAborted, hNameMappings or lpszProgressTitle

You're not currently dealing with the renamed mappings in your solution, so that's moot, but you do fetcch an incorrect result for fAnyOperationAborted under x86.

You can test it under x86 and x64 to see the issues with...

Code: Select all

obj := FileOps()
obj.FlagStr := 'NORECURSION RENAMEONCOLLISION WANTMAPPINGHANDLE'
obj.copy('u:\source\*', 'u:\target')
MsgBox(obj.Abort)

For an excellent solution "someone" developed for testing under different AHK versions, can I point you to...
viewtopic.php?f=6&t=73056
;)

For myself, I've coded the SHFileOpStructW, hNameMappings and SHNameMappingW structures as...

Code: Select all

  ; SHFileOpStructW
  Static Mhwnd                 := Map('Offset',              0,  'Type', 'Ptr'),                   ; HWND          8  4
         MwFunc                := Map('Offset', (x64 ?  8 :  4), 'Type', 'Ptr'),                   ; UINT          8  4
         MpFrom                := Map('Offset', (x64 ? 16 :  8), 'Type', 'Ptr'),                   ; PCZZSTR       8  4
         MpTo                  := Map('Offset', (x64 ? 24 : 12), 'Type', 'Ptr'),                   ; PCZZSTR       8  4
         MfFlags               := Map('Offset', (x64 ? 32 : 16), 'Type', (x64 ? 'Int' : 'Short')), ; FILEOP_FLAGS  4  2
         MfAnyOperationAborted := Map('Offset', (x64 ? 36 : 18), 'Type', 'Int'),                   ; BOOL          4  4
         MhNameMappings        := Map('Offset', (x64 ? 40 : 22), 'Type', 'Ptr'),                   ; LPVOID        8  4
         MlpszProgressTitle    := Map('Offset', (x64 ? 48 : 26), 'Type', 'Ptr'),                   ; PCSTR         8  4
         MTotalSHFileOpStructW :=               (x64 ? 56 : 30)

  ; hNameMappings
  Static MMappingsCount      := Map('Offset',             0,  'Type', 'Ptr'), ; UINT  8  4
         MSHNameMappingW     := Map('Offset', (x64 ?  8 : 4), 'Type', 'Ptr'), ; ptr   8  4
         MTotalhNameMappings :=               (x64 ? 16 : 8)

  ; SHNameMappingW
  Static MpszOldPath          := Map('Offset',              0,  'Type', 'Ptr'), ; LPSTR  8  4
         MpszNewPath          := Map('Offset', (x64 ?  8 :  4), 'Type', 'Ptr'), ; LPSTR  8  4
         McchOldPath          := Map('Offset', (x64 ? 16 :  8), 'Type', 'Int'), ; int    4  4
         McchNewPath          := Map('Offset', (x64 ? 20 : 12), 'Type', 'Int'), ; int    4  4
         MTotalSHNameMappingW :=               (x64 ? 24 : 16)

I hope that's of use to you.

Best regards,

LBJ
User avatar
TheArkive
Posts: 1027
Joined: 05 Aug 2016, 08:06
Location: The Construct
Contact:

Re: FileOps - Copy | Move | Delete | Rename (with Win32 progress bar) - 2022/02/28 - beta.3

02 Mar 2022, 05:42

@LBJ

Many thanks! I've confirmed the issues on my end. I figured there would be padding to align the MfAnyOperationAborted (BOOL) on a 4-byte boundary. (I guess not.) Thanks again!

I'll be adding support for NameMappings too on this update.
User avatar
TheArkive
Posts: 1027
Joined: 05 Aug 2016, 08:06
Location: The Construct
Contact:

Re: FileOps - Copy | Move | Delete | Rename (with Win32 progress bar) - 2022/03/02 - beta.3

02 Mar 2022, 08:23

2022/03/02
  • thanks to user @LBJ for pointing these out
  • added obj.NameMappings for "rename on collision"
  • fixed offsets for data members in SHFILEOPSTRUCT
  • optimized code

Return to “Scripts and Functions (v2)”

Who is online

Users browsing this forum: No registered users and 50 guests