3

I'm working on an installer that needs to create a backup of a directory prior to installing. The method I implement is purely to copy all files from the current directory to a new directory and then I am free to overwrite files (my installer) in the old directory.

However, I receive a prompt indicating file copy failed, but I just cannot understand why it doesn't work. My error message prints the correct directory\filename and I can verify that they exist and aren't open in any external programs.

Below is the code, taken (and modified slightly) from: http://blogs.candoerz.com/question/139833/inno-setup-copy-folder-subfolders-and-files-recursively-in-code-section.aspx

function DirectoryCopy(SourcePath, DestPath: string): boolean;
var
  FindRec: TFindRec;
  SourceFilePath: string;
  DestFilePath: string;
begin
  if FindFirst(SourcePath + '\*', FindRec) then begin
    try
      repeat
        if (FindRec.Name <> '.') and (FindRec.Name <> '..') then begin
          SourceFilePath := SourcePath + '\' + FindRec.Name;
          DestFilePath := DestPath + '\' + FindRec.Name;
          if FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY = 0 then begin
            if FileCopy(SourceFilePath, DestFilePath, False) then begin
              Result := True;
              MsgBox('Copy Worked!', mbInformation, MB_OK);
            end else begin
              Result := False;
              MsgBox('Copy Failed!'+SourceFilePath, mbInformation, MB_OK);
            end;
          end else begin
            if CreateDir(DestFilePath) then begin
              Result := True;
              MsgBox('Created Dir!', mbInformation, MB_OK);
              DirectoryCopy(SourceFilePath, DestFilePath);
            end else begin
              Result := False;
              MsgBox('Failed to create Dir!', mbInformation, MB_OK);
            end;
          end;
        end;
      until not FindNext(FindRec);
    finally
      FindClose(FindRec);
    end;
  end else begin
    Result := False;
    MsgBox('Failed to List!', mbInformation, MB_OK);
  end;
end;
Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
amitchone
  • 1,630
  • 3
  • 21
  • 45

2 Answers2

4

I suspect that the directory you are trying to copy to doesn't exist. You need to create the directory first using CreateDir or ForceDirectories. The file functions (including Martin's DirectoryCopy function, which uses these internal functions) require the directory to exist or they will fail. They will not automatically create the path for you. It is a pity this isn't documented anywhere (that I could find, although someone may be able to correct me on that) as it caught me out for a while too.

The original link to Martin's DirectoryCopy function is available here.

Community
  • 1
  • 1
Robert Wigley
  • 1,917
  • 22
  • 42
  • It's only natural that the `FileCopy` does not create the target folder. There's nothing that would indicate that it does. It's a trivial function with a single purpose. You cannot expect it to do anything more. No need to document that. +1 anyway. – Martin Prikryl Sep 17 '16 at 07:44
  • The CreateDir function was failing due to the use of illegal characters within the directory name. One of the drawbacks of being a native Mac user when developing for Windows! – amitchone Sep 22 '16 at 06:25
3

As we didn't receive any information that can be used for debugging your actual problem, I'm posting generic instructions for debugging problems with files.

To find out why any (file) system function fails, use the GetLastError WinAPI function. You can also use the SysErrorMessage support function to convert an error code to a message. The function is a wrapper for the FormatMessage WinAPI function.

function GetLastError: Cardinal;
  external 'GetLastError@kernel32.dll stdcall';

function FileCopyLogged(
  ExistingFile, NewFile: String; FailIfExists: Boolean): Boolean;
var
  Error: Cardinal;
begin
  Result := FileCopy(ExistingFile, NewFile, FailIfExists);

  if not Result then
  begin
    Error := GetLastError;
    Log(
      Format(
        'Copying "%s" to "%s" failed with code %d (0x%x) - %s', [
        ExistingFile, NewFile, Error, Error, SysErrorMessage(Error)]));
  end
    else
  begin
    Log(Format('Copying "%s" to "%s" succeeded', [ExistingFile, NewFile]));
  end;
end;

A correct call to the FileCopy (or the FileCopyLogged) is like:

FileCopyLogged(
  ExpandConstant('{app}\MyProg.exe'), 
  ExpandConstant('{app}\archive\MyProg.exe'),
  False);

As @RobertWigley already posted in his answer, make sure the target folder exists. If it does not, you will get error code 3 (The system cannot find the path specified).

Also make sure you use a full path to a target file in the NewFile argument (C:\folder\file). Not just a path to a target folder (C:\folder or C:\folder\). If you use just a path to the target folder, you will get error code 5 (Access is denied).

Of course both these codes can indicate other problems too.

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992