Mariner
Mariner

Reputation: 81

How to share an application and associated datafile

I have written a program (firemonkey) using delphi community edition. I would like to share the program, but the .exe file that my friends will be downloading has to access a text file from time to time to retrieve strings. When writing the program I used an event handler, to load the text file at startup:

tform3.formCreate (Sender:Tobject); ... assignfile(myfile,('C:**********.txt)); ...

Worked just fine during the design stage.

As a hobbyist, I now find myself stuck. If I use INNO setup compiler to create an installation program, which I plan to do, I can't have this same hardwired reference ('C:*****) to the data file's location. What I need is to change the above code such that the .exe file can locate the supporting datafile irrespective of where that .exe file (and datafile) ends up on someone else's PC.

How can I do this? i.e. What code do I need (in place of the above) to ensure that the installation program I hand out will install an .exe file that can locate the data file it references?

Any help, much appreciated. Still learning.

Upvotes: 0

Views: 361

Answers (3)

fpiette
fpiette

Reputation: 12322

You can let the user select the place where the file has to be saved. Proposing AppData folder if the file is for each individual user or CommonAppData if the file has to be shared between different users.

When the use selected the data file destination, you can save it to an INI file. The INI file can be stored, without asking the user, either to the registry or to an INI file saved in the AppData folder or ProgramData folder.

Here is a snipped of source code to get hand on those special folders:

const
    SectionWindow            = 'Window';
    SectionData              = 'Data';
    CompanyFolder            = 'YourCompanyName';


constructor TForm1.Create(AOwner: TComponent);
    var
        CommonPath   : array [0..MAX_PATH] of Char;
        LocalPath    : array [0..MAX_PATH] of Char;
        LangFileName : String;
    begin
        SHGetFolderPath(0, CSIDL_COMMON_APPDATA, 0, SHGFP_TYPE_CURRENT, @CommonPath[0]);
        SHGetFolderPath(0, CSIDL_LOCAL_APPDATA,  0, SHGFP_TYPE_CURRENT, @LocalPath[0]);
        FIniSection     := SectionWindow;
        FIniSectionData := SectionData;
        FAppName        := ChangeFileExt(ExtractFileName(Application.ExeName), '');
        FCommonAppData  := IncludeTrailingPathDelimiter(CommonPath) +
                           CompanyFolder + '\' + FAppName + '\';
        FLocalAppData   := IncludeTrailingPathDelimiter(LocalPath) +
                           CompanyFolder + '\' + FAppName + '\';
        FIniFileName    := FLocalAppData + FAppName + '.ini';
        ForceDirectories(FCommonAppData);
        ForceDirectories(FLocalAppData);
        inherited Create(AOwner);
    end;

Upvotes: 0

dummzeuch
dummzeuch

Reputation: 11252

If it is only accessed read only, you could also consider adding it as a resource to the executable. Which would then allow you to simply distribute this executable without the need for an installer.

Delphi Dabbler has an example, but I found it a bit confusing. I'll link to it (PDF) anyway.

Upvotes: 1

Andreas Rejbrand
Andreas Rejbrand

Reputation: 109003

Read-only access

If the data file should always be opened in read-only mode, the simplest solution is to place it next to the *.exe file. Then, at runtime, you dynamically find the path to the *.exe file and modify it to find the path to the data file. For instance,

uses
  IOUtils;

procedure TForm1.FormCreate(Sender: TObject);
var
  FileName: string;
begin
  FileName := TPath.Combine(ExtractFilePath(ParamStr(0)), 'data.txt');
  ShowMessage(TFile.ReadAllText(FileName, TEncoding.UTF8));
end;

ParamStr(0) contains the path to the *.exe file, such as

'C:\Users\Andreas Rejbrand\Documents\Embarcadero\Studio\Projects\test\Win32\Debug\Project1.exe'

Then ExtractFilePath(ParamStr(0)) is

'C:\Users\Andreas Rejbrand\Documents\Embarcadero\Studio\Projects\test\Win32\Debug\'

and, finally, TPath.Combine(ExtractFilePath(ParamStr(0)), 'data.txt') is

'C:\Users\Andreas Rejbrand\Documents\Embarcadero\Studio\Projects\test\Win32\Debug\data.txt'

Make sure the installer puts the data file next to the *.exe file.

Read and write access

If we are talking about a settings file or some other file that each user needs to change (via the software), you cannot place it next to the *.exe file, because the *.exe file typically resides in the Program Files folder, which is read only. Also, there is only one Program Files folder, but possibly many users on the PC, and each user should have his or her own copy.

The solution is to save the file in the user's own folders, specifically, the AppData folder:

FileName := TPath.GetHomePath + '\Mariner\My Word Processor App\Settings\settings.ini';

(using a different approach to path building).

On my system, this becomes

'C:\Users\Andreas Rejbrand\AppData\Roaming\Mariner\My Word Processor App\Settings\settings.ini'

Your installer (Inno Setup) has built-in support for placing files in this location.

Upvotes: 5

Related Questions