Lazarus

Programming => General => Topic started by: Ericktux on November 20, 2022, 05:30:49 pm

Title: move folders to another drive
Post by: Ericktux on November 20, 2022, 05:30:49 pm
hello brothers, i am looking for the simplest way to move folders to another drive, the "renamefile" function is simple and cross-platform, but it only moves folders in the same drive, for other drives it cannot move. opening as admin doesn't work either  :(

Code: Pascal  [Select][+][-]
  1. var
  2.   Form1: TForm1;
  3.   origen_1, destino_1 : string;  
  4.  
  5. ....
  6.  
  7. procedure TForm1.Button1Click(Sender: TObject);
  8. begin
  9.   origen_1:='D:\test\casa\';
  10.   destino_1:='C:\test\trabajo\casa\';
  11.   //destino_1:='F:\test\trabajo\casa\'; // doesn't work either
  12.  
  13.  if RenameFile(origen_1,destino_1) then
  14.   begin
  15.   ShowMessage('yes');
  16.   end
  17.      else
  18.      begin
  19.      ShowMessage('not');
  20.      end;
  21. end;  

PD: I am using win10x64 + lazarusx86
Title: Re: move folders to another drive
Post by: Bart on November 20, 2022, 05:47:13 pm
I'm afraid you'll have to copy and then delete...

Bart
Title: Re: move folders to another drive
Post by: KodeZwerg on November 20, 2022, 07:01:21 pm
PD: I am using win10x64 + lazarusx86
https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-movefile (https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-movefile)
This works very well for me on Windows for files or folders.
If you need an example exclusive for Windows I can write you one.
Title: Re: move folders to another drive
Post by: PascalDragon on November 20, 2022, 10:49:18 pm
hello brothers, i am looking for the simplest way to move folders to another drive, the "renamefile" function is simple and cross-platform, but it only moves folders in the same drive, for other drives it cannot move. opening as admin doesn't work either  :(

You need to do a copy-and-delete. That's how it works on any operating system and that's what a function like WinAPI's MoveFile that was suggested by KodeZwerg does as well. So you can just as well develop it yourself (or there might already be cross platform functions for that) and then you'll be cross platform anyway.
Title: Re: move folders to another drive
Post by: Ericktux on November 21, 2022, 03:37:47 am
Hello friends, I just tried with movefile and it doesn't move to another unit either, not as admin either, could it be that Windows 10 works differently?

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. begin
  3.   origen_1:='D:\test\casa';
  4.   destino_1:='C:\test\trabajo\casa';
  5.  
  6.  //if RenameFile(origen_1,destino_1) then
  7.  if moveFile(pchar(origen_1),pchar(destino_1)) then
  8.   ShowMessage('yes')
  9.      else
  10.      ShowMessage('not');
  11. end;    
Title: Re: move folders to another drive
Post by: KodeZwerg on November 21, 2022, 04:30:33 am
Hello friends, I just tried with movefile and it doesn't move to another unit either, not as admin either, could it be that Windows 10 works differently?
1. You do not need to run such as admin, only when source or destination is protected.
2. I show you my own implementation that worked for me.
3. Copy and Delete is as suggested the better way for x-Platform etc.
Code: Pascal  [Select][+][-]
  1. //https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-movefile
  2. function MoveFileW(lpExistingFileName, lpNewFileName: PWideChar): BOOL; stdcall; external 'Kernel32.dll' name 'MoveFileW';
  3.  
  4. procedure TForm1.Button1Click(Sender: TObject);
  5. var
  6.   Src, Dst: WideString;
  7. begin
  8.   Src := 'C:\Test\FileOrg.txt';
  9.   Dst := 'D:\Test\FileNew.txt';
  10.   if ForceDirectories(ExtractFilePath(Dst)) then
  11.     begin
  12.       if (not MoveFileW(PWideChar(Src), PWideChar(Dst))) then
  13.         ShowMessage(Src + ' -> ' + Dst + ' failed to move.');
  14.     end
  15.     else
  16.       ShowMessage(ExtractFilePath(Dst) + ' folder creation error.');
  17.  
Happy testing.
Title: Re: move folders to another drive
Post by: Ericktux on November 21, 2022, 05:02:48 am
thank you very much friend for your help, i just tried and it works with files but not with folders, still the same error, can't move folders to another drive  :(
Title: Re: move folders to another drive
Post by: KodeZwerg on November 21, 2022, 06:24:20 am
thank you very much friend for your help, i just tried and it works with files but not with folders, still the same error, can't move folders to another drive  :(
I am sorry, it was my fault, I didnt fully read the Microsoft remarks!
Quote
The one caveat is that the MoveFile function will fail on directory moves when the destination is on a different volume.
So here is a working Folder move, including sub-folder etc...
Code: Pascal  [Select][+][-]
  1. type
  2.   TSHFileOpStruct = record
  3.     Wnd: HWND;
  4.     wFunc: UINT;
  5.     pFrom: LPCWSTR;
  6.     pTo: LPCWSTR;
  7.     fFlags: FILEOP_FLAGS;
  8.     fAnyOperationsAborted: BOOL;
  9.     hNameMappings: Pointer;
  10.     lpszProgressTitle: LPCWSTR;
  11.   end;
  12.  
  13. const
  14.   FO_MOVE = $0001;
  15.   FOF_NOCONFIRMMKDIR = $0200;
  16.  
  17. function SHFileOperationW(const lpFileOp: TSHFileOpStruct): Integer; stdcall; external 'shell32.dll' name 'SHFileOperationW';
  18.  
  19. function MoveDir(SrcDir, DstDir: WideString): Boolean;
  20. var
  21.   FOS: TSHFileOpStruct;
  22. begin
  23.   ZeroMemory(@FOS, SizeOf(FOS));
  24.   FOS.Wnd := Application.Handle;
  25.   FOS.wFunc := FO_MOVE;
  26.   FOS.fFlags := FOF_NOCONFIRMMKDIR;
  27.   FOS.pFrom := PWideChar(IncludeTrailingPathDelimiter(SrcDir) + '*.*'#0);
  28.   FOS.pTo := PWideChar(DstDir + #0);
  29.   Result := (SHFileOperationW(FOS) = 0);
  30. end;
  31.  
  32. procedure TForm1.Button1Click(Sender: TObject);
  33. var
  34.   Src, Dst: WideString;
  35. begin
  36.   Src := 'C:\Test';
  37.   Dst := 'D:\Test';
  38.   if (not MoveDir(Src, Dst)) then
  39.     ShowMessage(Src + ' -> ' + Dst + ' failed to move.')
  40.     else
  41.     if (not RemoveDir(Src)) then
  42.       ShowMessage('Unable to remove ' + Src);
  43. end;
Happy testing. (and please do not use my above stuff by checking for true as result, only work with false checking like i showed!)
Title: Re: move folders to another drive
Post by: ASerge on November 21, 2022, 04:05:04 pm
Happy testing.
By the way, the RenameFile function internally uses the MoveFileW function in Windows.
So the problem is most likely either in the permissions, or in the absence of a directory, or in the existence of the resulting file.
Title: Re: move folders to another drive
Post by: KodeZwerg on November 21, 2022, 04:59:59 pm
Happy testing.
By the way, the RenameFile function internally uses the MoveFileW function in Windows.
So the problem is most likely either in the permissions, or in the absence of a directory, or in the existence of the resulting file.
Or in the remark from Microsoft what I have quoted above that MoveFile does not work when moving folders to other volumes.  O:-)
Title: Re: move folders to another drive
Post by: Ericktux on November 21, 2022, 05:50:53 pm
hello friend now it works, but when i use it with files these files are created as folders...   %)
I see that there is no simple way  :(, no way I will continue trying, I think I have a similar code I will look for it
Title: Re: move folders to another drive
Post by: KodeZwerg on November 21, 2022, 06:08:18 pm
hello friend now it works, but when i use it with files these files are created as folders...   %)
I see that there is no simple way  :(, no way I will continue trying, I think I have a similar code I will look for it
You got a windows solution from me for files.
You got a windows solution from me for folders.

What you need more?
Title: Re: move folders to another drive
Post by: Bart on November 21, 2022, 06:23:13 pm
How difficult can it be to simply iterate the files in source, copy to dest, delete after succesfull copy (delete target if copy partially fails)?

And if that is too difficult, you can always use ShellExcute() to launch move.exe with appropriate paramters.
Title: Re: move folders to another drive
Post by: KodeZwerg on November 21, 2022, 07:46:09 pm
hello friend now it works, but when i use it with files these files are created as folders...   %)
I see that there is no simple way  :(, no way I will continue trying, I think I have a similar code I will look for it
If you have no idea how to solve, that works aslong you keep mechanism to my above examples.
Code: Pascal  [Select][+][-]
  1.   if FileExists(Src) then
  2.     begin
  3.       if ForceDirectories(ExtractFilePath(Dst)) then
  4.         begin
  5.           if (not MoveFileW(PWideChar(Src), PWideChar(Dst))) then
  6.             ShowMessage(Src + ' -> ' + Dst + ' failed to move.');
  7.         end
  8.         else
  9.           ShowMessage(ExtractFilePath(Dst) + ' folder creation error.');
  10.     end;
  11.   if DirectoryExists(Src) then
  12.     begin
  13.       if (not MoveDir(Src, Dst)) then
  14.           ShowMessage(Src + ' -> ' + Dst + ' failed to move.')
  15.           else
  16.           if (not RemoveDir(Src)) then
  17.             ShowMessage('Unable to remove ' + Src);
  18.     end;
Title: Re: move folders to another drive
Post by: Ericktux on November 22, 2022, 02:13:07 am
hello friend now it works, but when i use it with files these files are created as folders...   %)
I see that there is no simple way  :(, no way I will continue trying, I think I have a similar code I will look for it
If you have no idea how to solve, that works aslong you keep mechanism to my above examples.
Code: Pascal  [Select][+][-]
  1.   if FileExists(Src) then
  2.     begin
  3.       if ForceDirectories(ExtractFilePath(Dst)) then
  4.         begin
  5.           if (not MoveFileW(PWideChar(Src), PWideChar(Dst))) then
  6.             ShowMessage(Src + ' -> ' + Dst + ' failed to move.');
  7.         end
  8.         else
  9.           ShowMessage(ExtractFilePath(Dst) + ' folder creation error.');
  10.     end;
  11.   if DirectoryExists(Src) then
  12.     begin
  13.       if (not MoveDir(Src, Dst)) then
  14.           ShowMessage(Src + ' -> ' + Dst + ' failed to move.')
  15.           else
  16.           if (not RemoveDir(Src)) then
  17.             ShowMessage('Unable to remove ' + Src);
  18.     end;

Thank you very much friend, now it works for files and folders  :), just one last question:
where can i put showmessage('successful operation')  :-\
Title: Re: move folders to another drive
Post by: KodeZwerg on November 22, 2022, 04:16:17 am
where can i put showmessage('successful operation')  :-\
I simplified it for you so you can tell "success" or "failed".
When you want more of the "failed" messages, stick to old code and add some "else" wherever you need it.
Code: Pascal  [Select][+][-]
  1. function MoveFileW(lpExistingFileName, lpNewFileName: PWideChar): BOOL; stdcall; external 'Kernel32.dll' name 'MoveFileW';
  2.  
  3. type
  4.   TSHFileOpStructW = record
  5.     Wnd: HWND;
  6.     wFunc: UINT;
  7.     pFrom: LPCWSTR;
  8.     pTo: LPCWSTR;
  9.     fFlags: FILEOP_FLAGS;
  10.     fAnyOperationsAborted: BOOL;
  11.     hNameMappings: Pointer;
  12.     lpszProgressTitle: LPCWSTR;
  13.   end;
  14.  
  15. const
  16.   FO_MOVE = $0001;
  17.   FOF_NOCONFIRMMKDIR = $0200;
  18.  
  19. function SHFileOperationW(const lpFileOp: TSHFileOpStructW): Integer; stdcall; external 'shell32.dll' name 'SHFileOperationW';
  20.  
  21. function MoveDir(const Src, Dst: WideString): Boolean;
  22. var
  23.   FOS: TSHFileOpStructW;
  24. begin
  25.   ZeroMemory(@FOS, SizeOf(FOS));
  26.   FOS.Wnd := Application.Handle;
  27.   FOS.wFunc := FO_MOVE;
  28.   FOS.fFlags := FOF_NOCONFIRMMKDIR;
  29.   FOS.pFrom := PWideChar(IncludeTrailingPathDelimiter(Src) + '*.*'#0);
  30.   FOS.pTo := PWideChar(Dst + #0);
  31.   Result := (SHFileOperationW(FOS) = 0);
  32. end;
  33.  
  34. // this method wants either a full source and destination path
  35. // or a full source and destination path with "filename.ext"
  36. // it return true on success or false on failure
  37. function MoveData(const Src, Dst: WideString): Boolean;
  38. begin
  39.   Result := False;
  40.   if FileExists(Src) then
  41.     begin
  42.       Result := ForceDirectories(ExtractFilePath(Dst));
  43.       if Result then
  44.         Result := MoveFileW(PWideChar(Src), PWideChar(Dst));
  45.     end
  46.   else // file did not exists, try folder operation
  47.   if DirectoryExists(Src) then
  48.     begin
  49.       Result := MoveDir(Src, Dst);
  50.       if Result then
  51.         Result := RemoveDir(Src);
  52.     end;
  53. end;
  54.  
  55. procedure TForm1.Button1Click(Sender: TObject);
  56. var
  57.   Src, Dst: WideString;
  58. begin
  59.   Src := 'C:\Test';
  60.   Dst := 'D:\Test';
  61.   if MoveData(Src, Dst) then
  62.     ShowMessage('All Good.')
  63.     else
  64.     ShowMessage('Not successful.');
  65. end;
Thank you very much friend
You are welcome  O:-)
Title: Re: move folders to another drive
Post by: Ericktux on November 22, 2022, 05:55:12 am
Hello friend, thank you very much, very kind, I have copied the code as it is and I get this error:

Code: Pascal  [Select][+][-]
  1. function MoveDir(const Src, Dst: WideString): Boolean;
  2. var
  3.   FOS: TSHFileOpStructW;
  4. begin
  5.   ZeroMemory(@FOS, SizeOf(FOS));
  6.   FOS.Wnd := Application.Handle;
  7.   FOS.wFunc := FO_MOVE;
  8.   FOS.fFlags := FOF_NOCONFIRMMKDIR;
  9.   FOS.pFrom := PWideChar(IncludeTrailingPathDelimiter(Src) + '*.*'#0);
  10.   FOS.pTo := PWideChar(Dst + #0);
  11.   Result := (SHFileOperationW(FOS) = 0);  // here mark error in "FOS"
  12. end;  

in the message window it shows:
Code: Pascal  [Select][+][-]
  1. unit1.pas(66,34) Error: Incompatible type for arg no. 1: Got "TSHFileOpStructW", expected "_SHFILEOPSTRUCTA"

 :( :(
Title: Re: move folders to another drive
Post by: KodeZwerg on November 22, 2022, 06:03:24 am
I have copied the code as it is and I get this error
You need to copy and paste everything from my last again. The older is not compatible, I changed source.
Title: Re: move folders to another drive
Post by: KodeZwerg on November 22, 2022, 03:09:51 pm
If you still got errors, in attachment is a unit, just include it in your uses like:
Code: Pascal  [Select][+][-]
  1. uses ....FileHelper...
and call it like i showed on last post:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   Src, Dst: WideString;
  4. begin
  5.   Src := 'C:\Test';
  6.   Dst := 'D:\Test';
  7.   if FileHelper.MoveData(Src, Dst) then // i added unit name infront of method to ensure that my method is called.
  8.     ShowMessage('All Good.')
  9.     else
  10.     ShowMessage('Not successful.');
  11. end;
I hope now all works fluffy for you.
Title: Re: move folders to another drive
Post by: Ericktux on November 22, 2022, 03:55:24 pm
Thank you very much friend, now everything works perfect.  :D

Excuse me if I abuse your courtesy, I have a question, if one day I have files or folders with long names, will this code work ??
Thanks for your time.
Title: Re: move folders to another drive
Post by: KodeZwerg on November 22, 2022, 04:01:28 pm
My method is limited to a max name length of 32767 (wide)-chars. Is that long enough?
Title: Re: move folders to another drive
Post by: Ericktux on November 22, 2022, 04:03:50 pm
wow thank you very much friend.  :)
Title: Re: move folders to another drive
Post by: KodeZwerg on November 22, 2022, 04:15:39 pm
Sorry, you need to update the filehelper.pas file to enable to long path setting.
Change this
Code: Pascal  [Select][+][-]
  1.           Result := MoveFileW(PWideChar(Src), PWideChar(Dst));
into that
Code: Pascal  [Select][+][-]
  1.           Result := MoveFileW(PWideChar('\\?\' + Src), PWideChar('\\?\' + Dst));
and now you got 32k for files.


edit:
Sorry, for folders this does not apply, I never tested anything beyond MAX_PATH length.
As far as I understand the WinAPI it is not possible with my method to use folders longer than MAX_PATH.
Title: Re: move folders to another drive
Post by: Ericktux on November 22, 2022, 05:03:57 pm
I understand my friend, don't worry, it's not urgent, rather I have a question, the code you gave me works perfect for folders, in the case of files, if it already exists, it doesn't overwrite it, I've read that I should use copyfile and then deletefile to be able to overwrite it, I'll do some tests and tell you
Title: Re: move folders to another drive
Post by: KodeZwerg on November 22, 2022, 05:33:43 pm
I understand my friend, don't worry, it's not urgent, rather I have a question, the code you gave me works perfect for folders, in the case of files, if it already exists, it doesn't overwrite it, I've read that I should use copyfile and then deletefile to be able to overwrite it, I'll do some tests and tell you
Re-Uploaded, fixed small issue.
Now it will overwrite per default even hidden, readonly etc.. files.

Call it like this to overwrite files
Code: Pascal  [Select][+][-]
  1.   if FileHelper.MoveData(Src, Dst) then

Call it like this to skip moving existing files
Code: Pascal  [Select][+][-]
  1.   if FileHelper.MoveData(Src, Dst, False) then

I hope now all is okay.

Re-ReUploaded.... forgot to tweak the deletefile operation.
Title: Re: move folders to another drive
Post by: Ericktux on November 22, 2022, 05:43:11 pm
Thank you very much friend, one question, what would be better to overwrite?
first delete destination file (if it exists) and then move source file.
or
first copy file overwriting old file, and then delete source file
 :-\
Title: Re: move folders to another drive
Post by: KodeZwerg on November 22, 2022, 06:00:34 pm
Thank you very much friend, one question, what would be better to overwrite?
first delete destination file (if it exists) and then move source file.
or
first copy file overwriting old file, and then delete source file
 :-\
I do not really understand the question.
If you want to overwrite just call my method without using 3rd parameter and it does do all automagical for you.

When you plan to create your own way of doing with overwrite ability than this would be the correct order:
1. check if destination exists
2. if 1. is true than set the file attribute to be able to delete
3. if 1. and 2. is true than delete the file
4. if 2. and 3. is true or 1. was false than copy the file
5. if 4. is true than do the same 2. and 3. for the source file
Title: Re: move folders to another drive
Post by: Ericktux on November 22, 2022, 11:08:36 pm
ok friend, thank you very much for helping me  :)
Title: Re: move folders to another drive
Post by: Ericktux on December 01, 2022, 01:46:41 am
Hello brothers, I just made a modification to the code to be able to copy files and folders, that's how I'm using it at the moment and it works fine  :)

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, FileHelper;
  9.  
  10. type
  11.  
  12.   { TForm1 }
  13.  
  14.   TForm1 = class(TForm)
  15.     Button1: TButton;
  16.     Button2: TButton;
  17.     procedure Button1Click(Sender: TObject);
  18.     procedure Button2Click(Sender: TObject);
  19.     procedure FormCreate(Sender: TObject);
  20.   private
  21.  
  22.   public
  23.  
  24.   end;
  25.  
  26. var
  27.   Form1: TForm1;
  28.   Src, Dst: WideString;
  29.  
  30.   const
  31.     FO_MOVE   = $0001;
  32.     FO_COPY   = $0002;
  33.  
  34. implementation
  35.  
  36. {$R *.lfm}
  37.  
  38. { TForm1 }
  39.  
  40. procedure TForm1.Button1Click(Sender: TObject); // FOR MOVE
  41. begin
  42.   if FileHelper.MoveData(Src, Dst, FO_MOVE) then // i added unit name infront of method to ensure that my method is called.
  43.      ShowMessage('All Good.')
  44.      else
  45.      ShowMessage('Not successful.');
  46.  
  47. end;
  48.  
  49. procedure TForm1.Button2Click(Sender: TObject); // FOR COPY
  50. begin
  51.   if FileHelper.MoveData(Src, Dst, FO_COPY) then // i added unit name infront of method to ensure that my method is called.
  52.      ShowMessage('All Good.')
  53.      else
  54.      ShowMessage('Not successful.');
  55. end;
  56.  
  57. procedure TForm1.FormCreate(Sender: TObject);
  58. begin
  59.   Src := 'D:\test\casa\jaja.txt';
  60.   Dst := 'C:\test\trabajo\jaja.txt';
  61.   {
  62.   Src := 'D:\test\casa\';
  63.   Dst := 'C:\test\trabajo\casa\';
  64.   }
  65. end;
  66.  
  67. end.

also modify the "filehelper.pas" unit of the friend KodeZwerg

Code: Pascal  [Select][+][-]
  1. unit FileHelper;
  2.  
  3. {$mode ObjFPC}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Windows, SysUtils;
  9.  
  10. function MoveData(const Src, Dst: WideString; Func: Integer; FileOverwrite: Boolean = True): Boolean;
  11.  
  12. implementation
  13.  
  14.   const
  15.     {FO_MOVE   = $0001;
  16.     FO_COPY   = $0002;
  17.     FO_DELETE = $0003;
  18.     FO_RENAME = $0004;}
  19.     FOF_NOCONFIRMMKDIR = $0200;
  20.     FOF_NOCONFIRMATION = $0010;    { Don't prompt the user. }
  21.     FOF_SIMPLEPROGRESS = $0100;    { means don't show names of files }
  22.     FOF_SILENT         = $0004;    { don't create progress/report }
  23.  
  24.   type
  25.     TSHFileOpStructW = record
  26.       Wnd: HWND;
  27.       wFunc: UINT;
  28.       pFrom: LPCWSTR;
  29.       pTo: LPCWSTR;
  30.       fFlags: FILEOP_FLAGS;
  31.       fAnyOperationsAborted: BOOL;
  32.       hNameMappings: Pointer;
  33.       lpszProgressTitle: LPCWSTR;
  34.     end;
  35.  
  36.   function MoveFileW(lpExistingFileName, lpNewFileName: PWideChar): BOOL; stdcall; external 'Kernel32.dll' name 'MoveFileW';
  37.   function CopyFileW(lpExistingFileName, lpNewFileName: PWideChar; bFailIfExists: BOOL): BOOL; stdcall; external 'Kernel32.dll' name 'CopyFileW';
  38.  
  39.   {
  40.   function CopyFileW(lpExistingFileName:LPCWSTR; lpNewFileName:LPCWSTR; bFailIfExists:WINBOOL):WINBOOL; external 'kernel32' name 'CopyFileW';
  41.   function MoveFileW(lpExistingFileName:LPCWSTR; lpNewFileName:LPCWSTR):WINBOOL; external 'kernel32' name 'MoveFileW';
  42.   }
  43.  
  44.   function SHFileOperationW(const lpFileOp: TSHFileOpStructW): Integer; stdcall; external 'shell32.dll' name 'SHFileOperationW';
  45.  
  46.   function MoveDir(const Src, Dst: WideString; Func: Integer): Boolean;
  47.   var
  48.     FOS: TSHFileOpStructW;
  49.   begin
  50.     ZeroMemory(@FOS, SizeOf(FOS));
  51.     FOS.wFunc := Func; // FO_MOVE , FO_COPY;
  52.     FOS.fFlags := FOF_NOCONFIRMMKDIR or FOF_SIMPLEPROGRESS or FOF_NOCONFIRMATION or FOF_SILENT;
  53.     FOS.pFrom := PWideChar(IncludeTrailingPathDelimiter(Src) + '*.*'#0);
  54.     FOS.pTo := PWideChar(Dst + #0);
  55.     Result := (SHFileOperationW(FOS) = 0);
  56.   end;
  57.  
  58.   // this method wants either a full source and destination path
  59.   // or a full source and destination path with "filename.ext"
  60.   // it return true on success or false on failure
  61.   function MoveData(const Src, Dst: WideString; Func: Integer; FileOverwrite: Boolean = True): Boolean;
  62.   begin
  63.     Result := False;
  64.     if FileExists(Src) then
  65.       begin
  66.         Result := ForceDirectories(ExtractFilePath(Dst));
  67.         if Result then
  68.           begin
  69.             if (FileOverwrite and FileExists(Dst)) then
  70.               Result := ((SetFileAttributesW(PWideChar('\\?\' + Dst), faNormal)) and DeleteFileW(PWideChar('\\?\' + Dst)));
  71.             if Result then
  72.                begin
  73.                     if Func = $0001 then Result := MoveFileW(PWideChar('\\?\' + Src), PWideChar('\\?\' + Dst));  // move
  74.                     if Func = $0002 then Result := CopyFileW(PWideChar('\\?\' + Src), PWideChar('\\?\' + Dst), false);  // copy
  75.                end;
  76.  
  77.           end;
  78.       end
  79.     else
  80.     if DirectoryExists(Src) then
  81.       begin
  82.         Result := MoveDir(Src, Dst, Func);
  83.         if Result then
  84.           begin
  85.             if Func = $0001 then Result := RemoveDir(Src); // only remove empty folder when using FO_MOVE
  86.             //Result := RemoveDir(Src);
  87.           end;
  88.       end;
  89.   end;
  90.  
  91. end.

At the moment it works fine, but if I'm doing something wrong please correct me  :)

PD: I attached the project.
Title: Re: move folders to another drive
Post by: KodeZwerg on December 01, 2022, 09:29:12 am
At the moment it works fine, but if I'm doing something wrong please correct me  :)
Just a minor thing I would do different, when you having your "Func" like FO_COPY, use it also in code and not the binary part.

I would write this
Code: Pascal  [Select][+][-]
  1.             if Result then
  2.                begin
  3.                     if Func = $0001 then Result := MoveFileW(PWideChar('\\?\' + Src), PWideChar('\\?\' + Dst));  // move
  4.                     if Func = $0002 then Result := CopyFileW(PWideChar('\\?\' + Src), PWideChar('\\?\' + Dst), false);  // copy
  5.                end;
In a way like that
Code: Pascal  [Select][+][-]
  1.             if Result then
  2.                case Func of
  3.                  FO_MOVE: Result := MoveFileW(PWideChar('\\?\' + Src), PWideChar('\\?\' + Dst));  // move
  4.                  FO_COPY: Result := CopyFileW(PWideChar('\\?\' + Src), PWideChar('\\?\' + Dst), false);  // copy
  5.                  else
  6.                    Result := False;
  7.                end;
TinyPortal © 2005-2018