views:

589

answers:

3

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;

+8  A: 

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.

lkessler
Thanks for the information, I added it to my application.
Brad
Or you could simply use `ForceDirectories()` (in the `FileCtrl` unit) instead of `CreateDir()` to create the structure in one call.
mghie
@mghie: Thanks. I didn't know myself about the ForceDirectories function. I've updated my answer.
lkessler
+4  A: 

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.

Tim Jarvis
+3  A: 

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');

TechnoCowboy
+1. It's worth pointing out that the first part in `COMMON_APPDATA` should be considered read-only by the application. The installer can write everything necessary, it will have proper permissions. Later changes can only be made by users with sufficient privileges, which needs to be checked for, or elevation be requested.
mghie
You are right. I usually save SystemSettings and DefaultUserSettings in COMMON_APPDATA. At startup i Load the SystemSsettings - and check if current user has UserSettings in his APPDATA. If not i will load the default settings from COMMON_APPDATA and save them to the users APPDATA - now ready for use.
TechnoCowboy
You can use the defaul user appdata to automatically create a user app_data initial settings when a new user is create (it does not work for already existing users).
ldsandon