Using a local Users Application Data folder issue with access

Hi,

I have a little program that I want to store some application settings in the local users Application Data folder, i'm creating this program with Delphi 7, however whenever I try to use TiniFile to write some information to the inifile if it doesn't exist (defaults basically).

Here is the code i'm using to try and write to the inifile...

procedure TAddInModule.CreateBlankSettings(cType:char);
begin
  try
    case cType of
      'G': begin
          SettingsIni := TIniFile.Create(sLocalSettingsPath);
          if assigned(SettingsIni) then begin
            SettingsIni.WriteString('EM', 'AllowChanges', 'True');                              //THIS IS THE LINE IT DIES AT
            SettingsIni.WriteString('EM', 'StartupFolder', 'Outlook Today (HN Style)');
            SettingsIni.WriteString('EM', 'TabSite','HN Folder');
            Settingsini.WriteString('EM', 'CustomSite','http://');
          end;
      end;
      'U': begin
          Settingsini := TIniFile.Create(sLocalUserSettingsPath);
          SettingsIni.WriteString(sCurrentUserAddress, 'UserType', 'Local');
          SettingsIni.WriteString(sCurrentUserAddress, 'StartupFolder', 'Outlook Today (HN Style)');
          SettingsIni.WriteString(sCurrentUserAddress,'TabSite', 'HN Folder');
          Settingsini.WriteString(sCurrentUserAddress,'CustomSite', 'http://');
          Settingsini.WriteString(sCurrentUserAddress,'Version', sVersion);
      end;
    end;
  finally
    Settingsini.Free;
  end;
end;

for Reference the sLocalSettingsPath = the Windows API App Data folder + '\EM\HN.ini'
I've checked the path and its all fine.  I can create folders either manually or with Delphi, but cannot edit this ini file.  As a test I've also created a blank ini file in this location, and it still breaks down at the same spot.

If anyone has any ideas, it would be greatly appreciated.  If you require more info, please let me know, I'll be checking this regularly as I need to find a solution quite quickly.  While these settings I could store in the registry (and at some point I might even change that) this is a Outlook Addin that requires a seperate PST File to be stored locally, in a location that would be somewhat secure from Users accidently deleting their information.

Thanks
beezeeAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Imthiyaz_phCommented:
Is this is an executable file or some kind of dll?
Could you also please mention the exception message here.
0
sun4sundayCommented:
If the applicaiton is running under a user Limited account with windowsXP , will face problem to write into the files.
sun4sunday.
0
Eddie ShipmanAll-around developerCommented:
I would suppose that it is the particular user account that has problems with not being able to create or modify files in
that directory.
0
Cloud Class® Course: Certified Penetration Testing

This CPTE Certified Penetration Testing Engineer course covers everything you need to know about becoming a Certified Penetration Testing Engineer. Career Path: Professional roles include Ethical Hackers, Security Consultants, System Administrators, and Chief Security Officers.

TheRealLokiSenior DeveloperCommented:
I dont think you are using a filename, try this

SettingsIni := TIniFile.Create(InclideTrailingBackslash(sLocalSettingsPath) + 'MYINIFILENAME.ini');
0
TheRealLokiSenior DeveloperCommented:
oops, I should have read the entire question first :-D
Is this running as a service by any chance?
What is the actual error message you receive when you try to do this?
0
bernaniCommented:
Don't know if it's what you want (code below is a form with 2 buttons. A Click on the first buttons creates the file in the COMMON_APPDATA folder (for all users) with hn.ini file with settings declared for 'G' and the same for 'U' with the click on the second button but writing the file in the COMMON_DOCUMENTS folder (for all users) - Tested on XP with administrator's rights.

unit Unit1;

interface

uses
{add : IniFiles,ShellApi,ShlObj, FileCtrl}
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, IniFiles,ShellApi, StdCtrls, ShlObj, FileCtrl;


type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Déclarations privées }
  public
    { Déclarations publiques }
  end;

var
  Form1: TForm1;
  sLocalSettingsPath, sLocalUserSettingsPath, sCurrentUserAddress, sVersion: String;
  SettingsIni : TIniFile;

{Add those lines}
Const
  CSIDL_COMMON_APPDATA   = $0023;   // all users common application data
  CSIDL_COMMON_DOCUMENTS = $002E; // all users documents folder

implementation


{$R *.DFM}

Function SpecialFolder(Form:Tform; Folder: Integer): String;
var
  SFolder : pItemIDList;
  SpecialPath : Array[0..MAX_PATH] Of Char;
begin
  SHGetSpecialFolderLocation(Form.Handle, Folder, SFolder);
  SHGetPathFromIDList(SFolder, SpecialPath);
  Result := StrPas(SpecialPath);
end;


procedure CreateBlankSettings(cType:char);
begin
ForceDirectories(SpecialFolder(Form1, CSIDL_COMMON_APPDATA)+ '\EM\');
sLocalSettingsPath:= SpecialFolder(Form1, CSIDL_COMMON_APPDATA)+ '\EM\HN.ini';

ForceDirectories(SpecialFolder(Form1, CSIDL_COMMON_DOCUMENTS)+ '\EM\');
sLocalUserSettingsPath:= SpecialFolder(Form1, CSIDL_COMMON_DOCUMENTS)+ '\EM\HN.ini';

sCurrentUserAddress := 'Test Current user adress';
sVersion := 'Test Version';
  try
    case cType of

      'G': begin
          SettingsIni := TIniFile.Create(sLocalSettingsPath);
          if assigned(SettingsIni) then begin
            SettingsIni.WriteString('EM', 'AllowChanges', 'True');                              //THIS IS THE LINE IT DIES AT
            SettingsIni.WriteString('EM', 'StartupFolder', 'Outlook Today (HN Style)');
            SettingsIni.WriteString('EM', 'TabSite','HN Folder');
            Settingsini.WriteString('EM', 'CustomSite','http://');
          end;
      end;

      'U': begin
          Settingsini := TIniFile.Create(sLocalUserSettingsPath);
          SettingsIni.WriteString(sCurrentUserAddress, 'UserType', 'Local');
          SettingsIni.WriteString(sCurrentUserAddress, 'StartupFolder', 'Outlook Today (HN Style)');
          SettingsIni.WriteString(sCurrentUserAddress,'TabSite', 'HN Folder');
          Settingsini.WriteString(sCurrentUserAddress,'CustomSite', 'http://');
          Settingsini.WriteString(sCurrentUserAddress,'Version', sVersion);
      end;
    end;
  finally
    Settingsini.Free;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
CreateBlankSettings('G');
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
CreateBlankSettings('U');
end;

end.


0
beezeeAuthor Commented:
Thanks all for the quick response, this is a Outlook Add-in, so dll.

The exception on the other hand really doesn't help me much, no error number or address just that the Add-in fired an exception.

---------------------------
Error
---------------------------
EM error: the add-in has fired an exception.
Unable to write to "C:\Documents and Settings\<uname>\Application Data\<busname>\EM\EM.ini"
---------------------------
OK  
---------------------------
0
beezeeAuthor Commented:
After a quick test of bernani's code, works great on a normal App, but when put into my DLL Still fails, the user account has the full control in the security settings, so I don't think this is the issue.  I'm starting to think its something to do with it being a DLL...

For reference, when I moved bernani's code to my dll and made slight modifications (ie it has no form), the force directories still worked, creating directories, just not files.
0
bernaniCommented:
Strange, I test this in a dll and test application and it's working for me. The folders are correctly created with the ini files in them:

The dll code
____________________________________________________________________________
library DllTest; {DllTest.dpr}

{ Remarque importante concernant la gestion de mémoire des DLL : ShareMem doit être
  la première unité de la clause USES de votre bibliothèque ET de votre projet
  (sélectionnez Projet-Voir source) si votre DLL exporte des procédures ou des
  fonctions qui passent des chaînes comme paramètres ou résultats de fonctions.
  Ceci s'applique à toutes les chaînes passées de et vers votre DLL - même celles
  qui sont imbriquées dans des enregistrements et classes. ShareMem est l'unité d'interface pour
  le gestionnaire de mémoire partagée BORLNDMM.DLL, qui doit être déployé avec
  vos DLLs. Pour éviter d'utiliser BORLNDMM.DLL, passez les informations de chaînes
  avec des paramètres PChar ou ShortString.}

uses
  ShareMem,
  SysUtils,
  Classes,
  Forms,
  Windows,
  Messages,
  Graphics,
  Controls,
  Dialogs,
  inifiles,
  shellapi,
  StdCtrls,
  ShlObj,
  filectrl;

var
  sLocalSettingsPath, sLocalUserSettingsPath, sCurrentUserAddress, sVersion: String;
  SettingsIni : TIniFile;

const
  CSIDL_COMMON_APPDATA   = $0023;
  CSIDL_COMMON_DOCUMENTS = $002E;

{$R *.RES}

function SpecialFolder(Folder: Integer): PChar;stdcall;
var
  SFolder : pItemIDList;
  SpecialPath : Array[0..MAX_PATH] Of Char;
begin
  SHGetSpecialFolderLocation(0, Folder, SFolder);
  SHGetPathFromIDList(SFolder, SpecialPath);
  Result := Pchar(StrPas(SpecialPath));
end;

procedure CreateBlankSettings(cType:char);stdcall;
begin
{needs filectrl in use clause}
// be sure the folder exists and create it if not true
//you could check this elsewhere - put here for simplification
forcedirectories(SpecialFolder(CSIDL_COMMON_APPDATA)+ '\EM\');
sLocalSettingsPath:= SpecialFolder( CSIDL_COMMON_APPDATA)+ '\EM\HN.ini';
forcedirectories(SpecialFolder( CSIDL_COMMON_DOCUMENTS)+ '\EM\');
sLocalUserSettingsPath:= SpecialFolder(CSIDL_COMMON_DOCUMENTS)+ '\EM\HN.ini';
sCurrentUserAddress := 'Current user adress from the DllTest';
sVersion := 'Version from Dll';
  try
    case cType of
      'G': begin
          SettingsIni := TIniFile.Create(sLocalSettingsPath);
          if assigned(SettingsIni) then begin
            SettingsIni.WriteString('EM', 'AllowChanges', 'True');                              //THIS IS THE LINE IT DIES AT
            SettingsIni.WriteString('EM', 'StartupFolder', 'Outlook Today (HN Style)');
            SettingsIni.WriteString('EM', 'TabSite','HN Folder');
            Settingsini.WriteString('EM', 'CustomSite','http://');
          end;
      end;
      'U': begin
          Settingsini := TIniFile.Create(sLocalUserSettingsPath);
          SettingsIni.WriteString(sCurrentUserAddress, 'UserType', 'Local');
          SettingsIni.WriteString(sCurrentUserAddress, 'StartupFolder', 'Outlook Today (HN Style)');
          SettingsIni.WriteString(sCurrentUserAddress,'TabSite', 'HN Folder');
          Settingsini.WriteString(sCurrentUserAddress,'CustomSite', 'http://');
          Settingsini.WriteString(sCurrentUserAddress,'Version', sVersion);
      end;
    end;
  finally
    Settingsini.Free;
  end;
end;

exports
SpecialFolder,
CreateBlankSettings;

begin
{code to procede on open}
end.


The application test (1 form + 2 buttons)
__________________________________

unit Unit1; {unit1.pas}

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TForm1 = class(TForm)
    Button3: TButton;
    Button4: TButton;
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
  private
    { Déclarations privées }
  public
    { Déclarations publiques }
  end;

var
  Form1: TForm1;
  function SpecialFolder(Folder: Integer): PChar;stdcall;external 'DllTest.dll';
  procedure CreateBlankSettings(cType:char); stdcall;external 'DllTest.dll';

implementation

{$R *.DFM}

procedure TForm1.Button3Click(Sender: TObject);
begin
CreateBlankSettings('G');
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
CreateBlankSettings('U');
end;

end.

__________________________________________

{Unit1.dfm}

object Form1: TForm1
  Left = 189
  Top = 113
  Width = 128
  Height = 163
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object Button3: TButton
    Left = 16
    Top = 24
    Width = 75
    Height = 25
    Caption = 'G'
    TabOrder = 0
    OnClick = Button3Click
  end
  object Button4: TButton
    Left = 16
    Top = 56
    Width = 75
    Height = 25
    Caption = 'U'
    TabOrder = 1
    OnClick = Button4Click
  end
end
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
beezeeAuthor Commented:
I've accepted this as it works beautifully in a clean app calling a dll function scenario.  For some reason when running an Outlook Com Add-In, TiniFile is unable to write to the AppData path be it the Common path or not.  Unfortunately at this stage I don't have the time to figure out exaclty why this wont work...  I have found that I can create a PST File in the AppData folder of my choice, it just seems that TiniFile in that particular spot dies.

Thanks for all your help especially bernani for all the test source code :)

If I do stumble over a solution in the near future I'll be sure to come back and post it.

Thanks all.
0
jjozCommented:
 
how can I access the following folder:<!--[if gte mso 9]>   Normal  0          false  false  false    EN-AU  X-NONE  X-NONE                                 MicrosoftInternetExplorer4                                     <![endif]--><!--[if gte mso 9]>                                                                                                                                                                                                                                                                                    <![endif]--><!--[if gte mso 10]><![endif]-->C:\Users\username\Application Data


i got access denied when I'm an administrator ?

0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.