• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 308
  • Last Modified:

Delphi Help

I am new to Delphi.  I have to make changes to a Delphi program which creates an ini and clm files when it is in use.  The problem now is that the application is to be placed on a Citrix server where it will be at one location (one exe at one location) and many users accessing the same app at the same location.  Because the app creates an ini and clm files when in use, concerns are raised about having mulitple users accessing the same exe at the same time.  In fact error messages like "Error writing to XXX.ini file" are popping up.  

I was told then to direct the output of these ini and clm files to a local directory specific to each user's machine.  Currently, the ini and clm files are created in the same directory in which the exe is stored.  However, I don't know how to do it or how to start it.  Any ideas?  I included the method below which creates the ini and clm files.

procedure TfrmEsnview.FormCreate(Sender: TObject);
var
   i: integer;
begin
   CalledFromTargys := False;
   Application.OnMessage := AppMessage;

   bDebug := False; // MM

   if not Assigned(EsnViewDataModule) then
      Application.CreateForm(TEsnViewDataModule, EsnViewDataModule);

   Top := ini.ReadInteger(cfgEVew, 'Top', 100);
   Left := ini.ReadInteger(cfgEVew, 'Left', 100);
   Width := ini.ReadInteger(cfgEVew, 'Width', 753);
   Height := ini.ReadInteger(cfgEVew, 'Height', 550);

   dbGrid6.Width := ini.ReadInteger(cfgEVew, 'dbGrid6Width', 600);

   clmFile1 := ExtractFilePath(Application.ExeName) + cfgEVew + '1.clm';
   clmFile2 := ExtractFilePath(Application.ExeName) + cfgEVew + '2.clm';
   clmFile3 := ExtractFilePath(Application.ExeName) + cfgEVew + '3.clm';
   clmFile4 := ExtractFilePath(Application.ExeName) + cfgEVew + '4.clm';
   clmFile5 := ExtractFilePath(Application.ExeName) + cfgEVew + '5.clm';
   clmFile6 := ExtractFilePath(Application.ExeName) + cfgEVew + '6.clm';
   if FileExists(clmFile1) then
      begin // Status
         dbGrid1.Columns.LoadFromFile(clmFile1);
      end;
   if FileExists(clmFile1) then
      begin // Channel Information
         dbGrid2.Columns.LoadFromFile(clmFile2);
      end;
   if FileExists(clmFile3) then
      begin // Attached Cards
         dbGrid3.Columns.LoadFromFile(clmFile3);
      end;
   if FileExists(clmFile4) then
      begin // Attached Cards (History)
         dbGrid4.Columns.LoadFromFile(clmFile4);
      end;
   if FileExists(clmFile5) then
      begin // PRL
         dbGrid5.Columns.LoadFromFile(clmFile5);
      end;
   if FileExists(clmFile6) then
      begin // Warranty
         dbGrid6.Columns.LoadFromFile(clmFile6);
      end;

   sgActivity.Cells[colActSerialNo, 0] := 'Serial Number';
   sgActivity.Cells[colActPwrOn, 0] := '1st Power On';
   sgActivity.Cells[colActPwrLast, 0] := 'Last Power On';
   sgActivity.Cells[colActPwrTotal, 0] := 'Total Power On';
   for i := 0 to sgActivity.ColCount - 1 do
      begin
         sgActivity.ColWidths[i] :=
            ini.ReadInteger(cfgEVew, 'sgActivityCol' + zIntToStr(i, 3),
            100);
      end;
end;
0
Magneto_Mystique
Asked:
Magneto_Mystique
1 Solution
 
shaneholmesCommented:
SO you are saying the application is now on a server on the network, and users are running it from there, and you want it to cteate the INI file and CLM file on there local machine when they run the app on the server?

I dont hink im reading this correctly!

sholmes
0
 
TheRealLokiSenior DeveloperCommented:
many users accessing the same exe is ok.
you haven't actually shown the ini file creation in your code
if you want to use a different ini or clm file for each user, then perhaps you could include the user's name in the file e.g.
clmFile1 := ExtractFilePath(Application.ExeName) + cfgEVew + fUsername + '_1.clm';
clmFile2 := ExtractFilePath(Application.ExeName) + cfgEVew + fUsername + '_2.clm';
etc.
so it actually looks like
bob_1.clm
bob_2.clm
sam_1.clm
sam_2.clm

you mention the error says xxx.ini  but i see no .ini in your example code. is the problem elsewhere?
you should access ini files like this

with TIniFile.Create('myname.ini') do
try
     i := readinteger(section, ident, default);
finally
    free;
end;
that way you can be sure you are not leaving too many files open when not in use
0
 
pcsentinelCommented:
I get the impression that you probably need 2 sets of data.

The first is the location of your datafiles which are persistent settings.

Leave these as being read from the central ini file

The 2nd set of data is local to the user
i.e. the size and layout of the form and sort order etc

if this is the case then you could add these to the registry

using something like

-----------------put this in the form create to load settings-------------------

procedure TfrmMain.FormCreate(Sender: TObject);
var
      lReg:    TRegistry;
begin
      lReg:=tRegistry.Create;
      try
            lReg.RootKey := HKEY_CURRENT_USER;
            if lReg.OpenKeyReadOnly('\Software\ESNView') then
            begin
                  if lReg.ValueExists('Top') then
                        Top:=lReg.ReadInteger('Top');
                  if lReg.ValueExists('Left') then
                        Left:=lReg.ReadInteger('Left');
                  if lReg.ValueExists('Height') then
                        Height:=lReg.ReadInteger('Height');
                  if lReg.ValueExists('SortColumn') then
                        FColumnSort:=lReg.ReadInteger('SortColumn');
                  if lReg.ValueExists('SortAscending') then
                        FSortAscending:=lReg.ReadBool('SortAscending');
                  if lReg.ValueExists('NameOrder') then
                        FNameSort:=lReg.ReadBool('NameOrder');
            end;
      finally
            lReg.CloseKey;
            lReg.Free;
      end;

end

-----------------put this in the form close to save settings-------------------

procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
//saves the position, size and settings
var
      lReg:            TRegistry;
  lPl : TWindowPlacement;
  lR: TRect;
begin
      try
            LockWindowUpdate(Handle);
    lPl.Length := SizeOf(TWindowPlacement);
    GetWindowPlacement(Self.Handle, @lPl);
    lR := lPl.rcNormalPosition;
            lReg:=tRegistry.Create;
            try
                  lReg.RootKey := HKEY_CURRENT_USER;
                  if lReg.OpenKey('\Software\EsnView',true) then
                  begin
        lReg.WriteInteger('Left', lR.Left);
        lReg.WriteInteger('Top', lR.Top);
        lReg.WriteInteger('Height', lR.Bottom-lR.Top);
        lReg.WriteBool('NameOrder', FNameSort);
        lReg.WriteBool('SortAscending', FSortAscending);
        lReg.WriteInteger('SortColumn', FColumnSort);
                  end;
            finally
                  lReg.CloseKey;
                  lReg.Free;
            end;
      finally
            LockWindowUpdate(0);
      end;
end;

This way local settings will not interfere with the central information

regards
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
BlackTigerXCommented:
keeping the same concept you have... something like this:

procedure TForm1.FormCreate(Sender: TObject);
var
   i: integer;
   BaseFileName, BasePath:string;
  procedure LoadFile(const FileName:string; dbGrid:TDBGrid);
  begin
    if (FileExists(FileName)) then
      dbGrid.Columns.LoadFromFile(FileName)
  end;
begin
   CalledFromTargys := False;
   Application.OnMessage := AppMessage;

   bDebug := False; // MM

   if not Assigned(EsnViewDataModule) then
      Application.CreateForm(TEsnViewDataModule, EsnViewDataModule);

   Top := ini.ReadInteger(cfgEVew, 'Top', 100);
   Left := ini.ReadInteger(cfgEVew, 'Left', 100);
   Width := ini.ReadInteger(cfgEVew, 'Width', 753);
   Height := ini.ReadInteger(cfgEVew, 'Height', 550);

   dbGrid6.Width := ini.ReadInteger(cfgEVew, 'dbGrid6Width', 600);

   BasePath:=IncludeTrailingBackslash(ini.ReadString('Config', 'BasePath', 'c:\')); //default to c:\

   BaseFileName:=BasePath+cfgEVew;

   clmFile1 := BaseFileName + '1.clm';
   clmFile2 := BaseFileName + cfgEVew + '2.clm';
   clmFile3 := BaseFileName + cfgEVew + '3.clm';
   clmFile4 := BaseFileName + cfgEVew + '4.clm';
   clmFile5 := BaseFileName + cfgEVew + '5.clm';
   clmFile6 := BaseFileName + cfgEVew + '6.clm';
   LoadFile(clmFile1, dbGrid1);
   LoadFile(clmFile2, dbGrid2);
   LoadFile(clmFile3, dbGrid3);
   LoadFile(clmFile4, dbGrid4);
   LoadFile(clmFile5, dbGrid5);
   LoadFile(clmFile6, dbGrid6);

   sgActivity.Cells[colActSerialNo, 0] := 'Serial Number';
   sgActivity.Cells[colActPwrOn, 0] := '1st Power On';
   sgActivity.Cells[colActPwrLast, 0] := 'Last Power On';
   sgActivity.Cells[colActPwrTotal, 0] := 'Total Power On';
   for i := 0 to sgActivity.ColCount - 1 do
      begin
         sgActivity.ColWidths[i] :=
            ini.ReadInteger(cfgEVew, 'sgActivityCol' + zIntToStr(i, 3),
            100);
      end;
end;
0
 
Magneto_MystiqueAuthor Commented:
I tried changing the code like above.  I can successfully direct the path of the clm files to C:.  The ini file is created in the uGlobal.  I would like to direct it to the same path as the clm files.  I tried to change it like the below but it doesn't work.  Why?

var
    ini: TIniFile;
    semsfile, semsfilepath: string;

const
    ver = '8.30';

    cfgMain = 'Main';              
    cfgStat = 'CardStatus';
    cfgView = 'CardView';
    cfgEVew = 'ESNViewer';
    cfgFirmBrow = 'FirmBrow';
    cfgLostStolen = 'LostStolen';
    cfgSVew = 'RIM Software Viewer';
                                           
    techPCS     = 'PCS';
    techIDEN    = 'IDEN';
    techSIM     = 'SIM';
    techANALOG  = 'ANALOG';
    techPAGER   = 'PAGER';
    techCDPD    = 'MODEM';

    stBES = 'BES Software';
    stLicense = 'SOFTWARE LICENSE';

    SCHEMA = '';

implementation

initialization
    semsfilepath := IncludeTrailingBackslash(ini.ReadString('Config', 'semsfilepath', 'c:\Example')); //default to c

    semsfile:= semsfilepath + cfgEVew;

    ini := TIniFile.Create(semsfile + 'SEMS.ini');

finalization
    ini.Free;

end.
0
 
kfoster11CEOCommented:
In the example aboves initialization section you are accessing the variable 'ini' before it is created probably causing a GPF.

*** Lets start over ***

The initial problem makes sense because the file is locked so instead of dealing with file locking and opening the file readonly lets put it on a local drive for each user.

Each User has a 'My Documents' folder so lets put them under there

This function will get us this folder

function GetMyDocuments: string;
var
   buffer: array[0..MaxPath - 1] of Char;
begin
   ShGetFolderPath(0, csidl_Personal or csidl_Flag_Create, 0,
shgfp_Type_Current, buffer);
   Result := buffer;
end;

Next lets encapsulate that function into another function that will return us the SemsFileFolder -  This function will add a subfolder to the mydocuments folder and make sure that it exists.  (Assumming that the users have rights to there MyDocuments folder'  which is normally the case.

function GetSemsLocalPath : String;
var
    aPath : string;
begin
     aPath := IncludeTrailingBackslash(GetMyDocuments)+'SEMS\';
     ForceDirectories(aPath); //this call will create the entire directory tree if it doesnt exist - you can check the result if you want to make it more robust!

     result := aPath;
end;


Now lets redo the initialization section

Initilization
    semsfilepath := GetSemsLocalPath;
    semsfile:= semsfilepath + cfgEVew;

    ini := TIniFile.Create(semsfile + 'SEMS.ini');
finalization
   ini.Close;
   ini.Free;
end.

   
0
 
cwwkieCommented:
No comment has been added to this question in more than 21 days, so it is now classified as abandoned.

I will leave the following recommendation for this question in the Cleanup topic area:
   Accept: kfoster11 {http:#15810258}

Any objections should be posted here in the next 4 days. After that time, the question will be closed.

cwwkie
EE Cleanup Volunteer
0

Featured Post

Hire Technology Freelancers with Gigs

Work with freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely, and get projects done right.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now