4
votes

Update: I've added the following code:


function TSettingsForm.AppDataPath: string;
 //CSIDL_APPDATA  Individual user Data
//CSIDL_COMMON_APPDATA  Common to Computer Data
  // works so long as people have at least IE 4.  (and Win95 or better)
var
   r: Bool;
   path: array[0..Max_Path] of Char;
begin
   r := ShGetSpecialFolderPath(0, path, CSIDL_APPDATA, False) ;
   if r then result := path
   else result := '';
end;

And I've changed the setinifilename function (See below). It will not create the folder structure.

--End update--

I'm behind the times, on what to and not to do. This is how I am currently saving the settings for my software. I just tested it on Vista not logged in as an administrator, and it gives me an error message cannot write ini file. So I'm guessing I'm supposed to write the data to a data folder? I've never used vista/win7 before, and want this software to be windows 2K+ compatible. What should I do to save the settings. I also really didn't want to mess with the registry, because every little bit you add to it, slows down the computer just that much more... (or so It seems)

Thanks for any input.



procedure TSettingsForm.setinifilename;
var filename:string;
    Path:string;
  begin
    filename:='key.ini';
    path:=AppDataPath+'\MyCompanyName\ProductName\';
    if NOT DirectoryExists(path) then
        CreateDir(path);
    inifilename:= path+filename;
  end;

procedure TSettingsForm.SaveSettings;
var
 appINI:  TIniFile;

begin
    appINI := TIniFile.Create(inifilename) ;
try
    low:= Trunc (edt_low.value);
    high:=Trunc (edt_high.value);
    appINI.WriteInteger('SPEED','LOW',low);
    appINI.WriteInteger('SPEED','HIGH',high);
    appINI.WriteString('PROXY','SERVER',edtProxyServer.Text);
    appINI.WriteString('PROXY','PORT',edtProxyPort.Text);
    appINI.WriteString('PROXY','USERNAME',edtProxyUserName.Text);
    appINI.WriteString('PROXY','PASSWORD',edtProxyPass.Text);

//    status.text:='Saved Data';
  finally
    appIni.Free;
  end;
end;
 procedure TSettingsForm.GetSettings;
Var
  appINI : TIniFile;
begin
  appINI := TIniFile.Create(inifilename) ;
  try
    //if no last user return an empty string
    edt_low.value:= appINI.ReadInteger('SPEED','LOW',0);
    edt_high.value:= appINI.ReadInteger('SPEED','HIGH',0);
    low:= Trunc (edt_low.Value);
    high := Trunc (edt_high.Value);

    edtProxyServer.Text:=appINI.ReadString('PROXY','SERVER','');
    edtProxyPort.Text:=appINI.ReadString('PROXY','PORT','0');
    edtProxyUserName.Text:=appINI.ReadString('PROXY','USERNAME','');
    edtProxyPass.Text:= appINI.ReadString('PROXY','PASSWORD','');
  finally
    appINI.Free;
  end;
 end;

3
See my update (in my answer). That should get it to work.lkessler
User accounts with read-only installation directories have been possible since the first Windows NT version more than 15 years ago, and were quite common in corporate environments. You just never tested on such an account before. Unless you use Vista-only API functions (the MSDN documentation states the minimum necessary OS version for each function) the techniques in the answers are certainly compatible with Windows 2000 and later.mghie

3 Answers

8
votes

In Vista, your program is NOT allowed to write to the program files directory where your program is located.

You now have to save your ini files in the AppData directory.

A description of how to do this in delphi is at: http://www.theabsolute.net/sware/delphivista.html#datafolder

And to be Vista/Windows 7 compatible, the rest of that web page will be a good guideline.


For your update, you cannot CreateDir more than 1 level deep at once. Use the ForceDirectories function instead:

    path:=AppDataPath+'\MyCompanyName\ProductName\'; 
    if NOT DirectoryExists(path) then
      ForceDirectories(path);

p.s. Don't be afraid to write program settings to the Registry. That's what the registry is for. In fact, it properly handles settings for different users for you when different users are logged in. The Registry works in the same way in 98/Vista/7. Whereas ini files have actually been depreciated, and are no longer used by Windows.

You say you don't want to mess with the registry because "every little bit you add to it, slows down the computer just that much more". Actually that is NOT true. The registry is simply a database. And if it is 10 MB or 100 MB, the difference in time it takes to access is imperceptable.

It's all those companies selling Registry Cleaner programs that are trying to keep this fairy tale going. Using their cleaners can do you more harm than good. All they need to do is wipe out one or two important entries and you can be in deep doo-doo. Please read this article about Registry Cleaners, and especially the "Marginal performance benefit" section which explains correctly that the problems Windows 98 and earlier had with the Registry have been mostly fixed.

If your program adds more than 2 or 3 KB to the Registry, that will be a lot, and it is an insignificant amount. Use the registry. Do it right.

4
votes

You should use the ApplicationData directory for your app data, In Delphi you can find this folder programatically using the shell api function SHGetSpecialFolderLocation

Embarcadero have a FAQ page on this, here.

2
votes

As already mentioned - dont save anything in the app folder.

You should split your configuration settings into two parts :

One part containing the settings that must work regardlees of the user - that part should be stored in COMMON_APPDATA.

A Second part containing the individual users settings (users personal choice of font etc) - that part should be stored in APPDATA

As for the CreateDir, it is true that you cannot create more than one level at a time - however, Delphi has the ForceDirectories function that can do exactly that.

e.g. ForceDirectories('C:\MyFolder\SubFolder\SubSubFolder');