Search code examples
windowsdelphidelphi-7portability

Achieving application portability within Windows and Delphi?


We have this application that does not write to the Windows registry or store its configuration files (such as an INI file) in the user's profile; instead, it stores its configuration files in the program's directory. Wikipedia has this statement

A portable application (portable app) is a computer software program designed to run independently from an operating system. This type of application is stored on a removable storage device such as a CD, USB flash drive, flash card - storing its program files, configuration information and data on the storage medium alone.

so our question is, does this make our application a true portable application (portable app)?

I should point out that if the application is on a write protected medium we use the function below, so it doesn't try to write to that medium.

function GetTempFile(): string;
var
  Buffer: array[0..MAX_PATH] of Char;
begin
  Windows.ZeroMemory(@Buffer, System.SizeOf(Buffer));
  SysUtils.StrPCopy(Buffer, SysUtils.ExcludeTrailingBackslash(SysUtils.ExtractFilePath(System.ParamStr(0))));
  Windows.GetTempFileName(Buffer, '~', 0, Buffer);
  Result := string(Buffer);
end;

function IsMediumWriteProtected(): Boolean;
var
  ErrorMode: Word;
  hHandle: THandle;
begin
  ErrorMode := Windows.SetErrorMode(SEM_FAILCRITICALERRORS);
  try
    hHandle := Windows.CreateFile(PChar(GetTempFile()), GENERIC_WRITE, 0, nil, 
      CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY or FILE_FLAG_DELETE_ON_CLOSE, 0);
    try
      Result := (hHandle = INVALID_HANDLE_VALUE);
    finally
      Windows.CloseHandle(hHandle);
    end;
  finally
    Windows.SetErrorMode(ErrorMode);
  end;
end;

Solution

  • Do not use Windows.GetCurrentDirectory() to retrieve the executable file's directory. It returns the process's current working directory, which can change dynamically during the process's lifetime, so you are not guaranteed to get the correct directory every time. To get the app's directory reliably, use Sysutils.ExtractFilePath(Sysutils.ParamStr(0)) instead. Internally, this uses Windows.GetModuleFileName(nil) to get the full path of your app and then truncates off the executable name, leaving the desired directory path.