Starting a Program from INI File Settings

Posted on 1997-08-16
Last Modified: 2010-04-06
In my app, I have a form that contains two DB fields - email and website, with two associated buttons - Send and Connect, respectively.  If there is data in the field, its corresponding button becomes enabled.  Clicking on the button reads from an .ini file looking for the values stored in the [Email] or [Browser] sections.  If  'None' is found, the user is prompted with a dialog box allowing them to specify the e-mail or browsers of their choice and saves it in the .ini file.  Obviously, I'd like to start the e-mail or Internet Browser the user specified in the .ini file AND populate the To: field of the e-mail program with my apps DB email field data and/or populate the URL/Website field of the user's browser with my app's DB website field data.  My questions are;

1   Does it make sense for me to use .ini file, since it is a Win95/NT only app.  I'm not too familiar with the registry or Win95's equivalent to an ini file.
2   Is there a key in the registry detailing the e-mail and/or Internet browser programs?  If so, how do I use it?
3   How to I start (execute) the email or browser program using the values found in the .ini file.  For example, when I use the readString method it returns D:\MyApp\MyApp.exe.  Since this is a string, I can't figure out how to make WinExec or CreateProcess use this value.
4   Once I figure out how to start the program, how do I populate the fields mentioned above.
Question by:d4jaj1
  • 6
  • 4

Accepted Solution

sperling earned 70 total points
ID: 1341626
1) If possible, use the registry for 32-bit windows apps. At least, that's what MS suggests.

2) Yes, but you don't have to use it.

  add ShellAPI to your uses clause.

  s := '';
  ShellExecute(0, 'open', PChar(s), nil, nil, SW_SHOWNORMAL);

  s := '';
  ShellExecute(0, 'open', PChar(s), nil, nil, SW_SHOWNORMAL);

These lines will first open the users default browser and point it to experts exchange, then it'll open the default mail app and prepare a message with me as the recipient.




Author Comment

ID: 1341627
Thanks for your quick response.  I did have 3 questions though;

1) In regard to yur first answer; I agree I should be using the Registry, I guess my real question was - HOW?

2)  My code saves the full path of the email/browser executable to an ini file.  I do this because a user may have more than one email/browser package installed on their system, thus I give them the option to choose.  I don't see in your code where it reads from the INI file and uses the email/browser saved there, then assigns the emailID/URL, which leads me to believe its starting the default email/browser on the system.  I need it to get the exe from the ini file.

3)  Your example works fine except for trying to assign a value to 's'.  In my send button, I added a var statement of "s: PChar"  Then, I try to assign the DB email value to 's' and I get an error stating; "Incompatable Types - TCaption and PChar".  However; if I use your example and type out what 's' is, it works. What am I doing wrong?  Typing out what 's' is looks like a string to me, so I can't figure out why it won't work with the DB Text since the value is a string as well.  I have included my code below.

procedure TfrmPeople.btnSendClick(Sender: TObject);
  UseIni: TIniFile;
  s:       pchar;
  UseIni := TIniFile.Create('Homebase.INI');
  if UseIni.ReadString('E-Mail', 'Email', 'error') = 'None' then
       showmessage('There is no E-Mail program assosiated with HomeBase yet, please use the following dialog box to link you favorite E-Mail program');
       Application.CreateForm(TfrmINI, frmINI);
       frmINI.Caption := 'Set E-Mail Program';
       frmINI.showmodal;  //the ini form actually saves data to the ini file when closed.
       //(UseIni.ReadString('E-Mail', 'Email', 'error')); // This is where I want to retrive the email exe saved in the INI file.  The method returns the path & file name.
       s := fldEmail.text;  //this doesn't work, see error above
       s := '';  // this does, but it starts the default package - I think.
       ShellExecute(0, 'open', PChar(s), nil, nil, SW_SHOWNORMAL); //Where would the exe found in the ini file fit in here?
        //Start the program like above


Author Comment

ID: 1341628
Okay, forget the first question of my response if you like.  After reading it again, it seems out of the scope of my actual problem.  However, I do need an answer to two of my original questions fairly soon.

1  Your example of starting the default browser/email worked just fine, except I asked how to start a program from the ini file  path string (ie D:\MyApp\Myapp,exe) returned.

2  Your example of specifying what 's' is works just fine also, however, I asked how to assign 's' from 2 database fields (email & website).  See my original response for more details.

This fuctionality is part of an upcoming demo of my app, thus I need it fairly quickly.  If I don't receive a reponse by the end of the weekend, I'll assume you either don't have time or don't want to answer the question, thus I will open it up for others to answer.

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.


Expert Comment

ID: 1341629
To get the PChar to work, you need to use:

fldEmail.text:=fldEMail.Text + #0; //makes it null terminated
ShellExecute(0, 'open', PChar(fldEmail.text[1]), nil, nil, SW_SHOWNORMAL); //calls it with the string being pointed to

Otherwise you need to use StrAlloc and StrPCopy or StrPLCopy.

He didn't use an ini file entry due to the fact that he is calling the users default browsers in windows already.  I think that is the best way to do it.  Use the already made defaults so the user doesn't have to tell the program to use what they have already told windows to use as default.

To get the registry to work, just use the TRegistry object in Delphi.  It is very similar to the TIniFile object.  Its in the helpfile or I can help you if you need more help.

I am leaving this weekend to visit a friend.  I'll be back Monday if you need more help.

Author Comment

ID: 1341630
Your example does not work for me.  It compiles correctly, but when the button is press, nothing happens.  The code is below.

procedure TfrmPeople.btnConnectClick(Sender: TObject);
fldwebsite.text:=fldwebsite.Text + #0; //makes it null terminated
ShellExecute(0, 'open', PChar(fldwebsite.text[1]), nil, nil, SW_SHOWNORMAL);

Furthermore; I want to know how to do this from the INI file for 2 reasons, 1) my one of my customers requested this ability (never argue with the customer) and 2) I need to learn how to read for an INi file and do something with the value I return.

Expert Comment

ID: 1341631
Sorry, I forgot to make it a pointer before the type conversion.  This one little character change will do what you want:
(look for the @ sign.  It must be made into a pointer before converted to a PChar.)

procedure TForm1.BitBtn1Click(Sender: TObject);
     fldwebsite.text:=fldwebsite.Text + #0; //makes it null terminated
     ShellExecute(0, 'open', PChar(@fldwebsite.text[1]), nil, nil, SW_SHOWNORMAL);

I just ran this and it started Netscape Navigator (my default browser) and loaded that page that I typed into the TEdit field.  
About the IniFile.  Here is how to get it to work.

1.  Use TIniFile.Create (FileName) to open a new or old ini file.  Normally the file should reside in the Windows directory.  If that is the case, no path needs to be assigned.  Otherwise, you must specify a path.
2.  Use one of the write functions to write to a section/key (WriteBool, WriteInteger, WriteString).  If the section or key doesn't exist, it will be created.
3.  Use Read functions to read from values (ReadBool, ReadInteger, ReadString).  The Section/Key Must exist or it will return a default value that you send into the function as a parameter.
4.  Use ReadSections, ReadSection, ReadSectionValues to read entire sections or section titles.
5.  Use DeleteSeciton to delete an entire section.
6.  Use DeleteKey to delete a key in a section only.

That is all there is to it.  When you use create with the filename, it opens the file and is all ready.  From then on, the file is open and can be Read from or Written to.  When you call Free or Destroy, the file will be closed.  Make sure you call one of these to make sure all changed are written and the file is properly closed (can cause problems on a network if you don't close it properly).  

Just a little note:
Never argue with the customer is a good policy.  However, reasoning with him is allowable.  Sometimes the user wants it one way because he knows of no better way.  

INI files have always been a plague to the computing industry.  I have had many programs create it at first runtime and never remove it when I uninstall.  Terrible programming practice.  You can use an install program to create the registry keys you need and a deinstaller to remove them when they uninstall the program.  Clean and easy.  

If you must use an INI file, remember to remove it upon uninstalling the program.  Otherwise, reason with your customer and tell him of the benefits of using the registry.  He should also know that Delphi 2 and 3 only support INI files for backward compatability.  Borland recommends using the registry and not an INI file.

Author Comment

ID: 1341632
There's a few things I'm having a problem with in these suggestons.

1)  Your suggestion does not work for the Email field.  When the button is pushed, nothing happens.  I assume this is becaus ethe SendTo: wasn't taken into account, but I don't know where it should go in the ShellExecute.

2)   If you take a look at my original question, it states I already use the ReaString method to get data from the INI file.  My question was, HOW do I pass the value (ie D:\app\app.exe) to the ShellExecute statement.  I don't see the answer to that question in your answer.

3)   Your suggestion works if either Http// or www exists at the beginning of the Website field.  My client needs to connect to Intranet sites and sites that have IP addresses, nither of which have HTTP or WWW.  How do I ensure the Browser is started (from the INI file) using the value in the Website field -even if it say 'ABCDEFG' ????

Expert Comment

ID: 1341633
1.  If the user doesn't specify "mailto:" before the address, you must to get it work.  That will run the default mail program if there is one.  Otherwise, you will get an error to the effect of:  No default mail program specified.

2.  Use the same method used to send in the http or email address.  Add a null character to the end, make it a pointer to character 1, then typecast it to a PChar.

3.  Intranet I cannot help you with if I don't have more information.  However, if its the internet, just make sure "http://" is in front of the address before running it.  That makes sure it runs the default browser.  Add it on yourself if the user is lazy and doesn't do it themselves.

if Pos('HTTP://', UpperCase(Trim(YourString)))<>1 then
   YourString := 'http://' + Trim(YourString);

For intranet, what prefix does netscape put in front of it?  If none, you will have to find the default browser in the registry yourself and run it with the page as a parameter.  (If you want to know where it stores it, I can find out--don't know right at this minute.)

Here is the full helpfile entry for shellexecute:
HINSTANCE ShellExecute(

    HWND  hwnd,      // handle to parent window
    LPCTSTR  lpOperation,      // pointer to string that specifies operation to perform
    LPCTSTR  lpFile,      // pointer to filename string
    LPTSTR  lpParameters,      // pointer to string that specifies executable-file parameters
    LPCTSTR  lpDirectory,      // pointer to string that specifies default directory
    INT  nShowCmd       // whether file is shown when opened


Specifies a parent window. This window receives any message boxes that an application produces. For example, an application may report an error by producing a message box.  


Pointer to a null-terminated string that specifies the operation to perform. The following operation strings are valid:

String      Meaning
"open"      The function opens the file specified by lpFile. The file can be an executable file or a document file.
"print"      The function prints the file specified by lpFile. The file should be a document file. If the file is an executable file, the function opens the file, as if "open" had been specified.
The lpOperation parameter can be NULL. In that case, the function opens the file specified by lpFile


Pointer to a null-terminated string that specifies the file to open or print. The function can open an executable file or a document file. The function can print a document file.


If lpFile specifies an executable file, lpParameters is a pointer to a null-terminated string that specifies parameters to be passed to the application.
If lpFile specifies a document file, lpParameters should be NULL.


Pointer to a null-terminated string that specifies the default directory.


If lpFile specifies an executable file, nShowCmd specifies how the application is to be shown when it is opened.  This parameter can be one of the following values:

Value      Meaning
SW_HIDE      Hides the window and activates another window.
SW_MAXIMIZE      Maximizes the specified window.
SW_MINIMIZE      Minimizes the specified window and activates the next top-level window in the Z order.
SW_RESTORE      Activates and displays the window. If the window is minimized or maximized, Windows restores it to its original size and position. An application should specify this flag when restoring a minimized window.
SW_SHOW      Activates the window and displays it in its current size and position.
SW_SHOWDEFAULT      Sets the show state based on the SW_ flag specified in the STARTUPINFO structure passed to the CreateProcess function by the program that started the application. An application should call ShowWindow with this flag to set the initial show state of its main window.
SW_SHOWMAXIMIZED      Activates the window and displays it as a maximized window.
SW_SHOWMINIMIZED      Activates the window and displays it as a minimized window.
SW_SHOWMINNOACTIVE      Displays the window as a minimized window. The active window remains active.
SW_SHOWNA      Displays the window in its current state. The active window remains active.
SW_SHOWNOACTIVATE      Displays a window in its most recent size and position. The active window remains active.
SW_SHOWNORMAL      Activates and displays a window. If the window is minimized or maximized, Windows restores it to its original size and position. An application should specify this flag when displaying the window for the first time.
If lpFile specifies a document file, nShowCmd should be zero.

Return Value

If the function succeeds, the return value is the instance handle of the application that was run, or the handle of a dynamic data exchange (DDE) server application.
If the function fails, the return value is an error value that is less than or equal to 32. The following table lists these error values:

Value      Meaning
0      The operating system is out of memory or resources.
ERROR_FILE_NOT_FOUND      The specified file was not found.
ERROR_PATH_NOT_FOUND      The specified path was not found.
ERROR_BAD_FORMAT      The .EXE file is invalid (non-Win32 .EXE or error in .EXE image).
SE_ERR_ACCESSDENIED      Windows 95 only: The operating system denied access to the specified file.
SE_ERR_ASSOCINCOMPLETE      The filename association is incomplete or invalid.
SE_ERR_DDEBUSY      The DDE transaction could not be completed because other DDE transactions were being processed.
SE_ERR_DDEFAIL      The DDE transaction failed.
SE_ERR_DDETIMEOUT      The DDE transaction could not be completed because the request timed out.
SE_ERR_DLLNOTFOUND      Windows 95 only: The specified dynamic-link library was not found.
SE_ERR_FNF      Windows 95 only: The specified file was not found.
SE_ERR_NOASSOC      There is no application associated with the given filename extension.
SE_ERR_OOM      Windows 95 only: There was not enough memory to complete the operation.
SE_ERR_PNF      Windows 95 only: The specified path was not found.
SE_ERR_SHARE      A sharing violation occurred.

The file specified by the lpFile parameter can be a document file or an executable file. If the file is a document file, the ShellExecute function opens or prints it, depending on the value of the lpOperation parameter. If the file is an executable file, the ShellExecute function opens it, even if lpOperation specifies printing.
Windows 95: You can use ShellExecute to open or explore a Windows 95 folder. To open a folder, use either of the following calls:

ShellExecute(handle, NULL, "path_to_folder", NULL, NULL, SW_SHOWNORMAL);


ShellExecute(handle, "open", "path_to_folder", NULL, NULL, SW_SHOWNORMAL);

To explore a folder, use the following call:

ShellExecute(handle, "explore", "path_to_folder", NULL, NULL, SW_SHOWNORMAL);

If lpOperation is NULL, the function opens the file specified by lpFile. If lpOperation is "open" or "explore", the function will force a open window or explorer.

See Also

FindExecutable, ShellExecuteEx

Author Comment

ID: 1341634
I'm still having problems starting an e-mail editor other than the default.  I added a variable for the file name value returned from the ini file, but the default editor still activates.  

I have two variables 'ini' and 'email'.  The 'ini' variable contains the path/filename of the users application (i.e., D:\mail.exe) and 'email' is the value from the DBtext box.  According to your excerpt from the help file, both my INI variable and the EMAIL variable belong in the third slot, but the email variable is already there, so I put the INI variable in the forth.  Can you tell me what I'm doing wrong?  My code is below.

  UseIni: TIniFile;
  email:       string;
  ini:         string;
UseIni := TIniFile.Create('Homebase.INI');
if UseIni.ReadString('E-Mail', 'Email', 'None') <> 'None' then
   ini := UseIni.ReadString('E-Mail', 'Email', 'None') + #0;
   email:='mailto:' + fldemail.Text + #0;
   ShellExecute(0, 'open', PChar(@email[1]), PChar(@ini[1]), nil, SW_SHOWNORMAL);


Expert Comment

ID: 1341635
Ok, first you have to understand the ShellExecute to get it to work.  The default browser will run if you "run" an e-mail address.  That is what you are doing.  You are "running" the e-mail address and so it starts the default browser.  To get it to work, try:

ShellExecute(0, 'open', PChar(@ini[1]), PChar(@email[1]), nil, SW_SHOWNORMAL);

That does it.  You need to send the e-mail address as the parameter for the mail program.  Hopefully, the mail program in question will take commandline parameters or you will have to activate a DDE connection to do it (complicated because not all e-mail programs are the same and you will not be able to predict all possible programs that the user will want to use).  

Additionally, your code:

email:='mailto:'+fldemail.Text + #0;

is dangerous.  The reason for this is, "What if the user actually types in 'mailto:' before his E-Mail?"  Use the code I used in the HTTP example above to 1) see if it is there, 2) put it there if it is not, 3) leave it there if it already is.  That will guarentee it is there one way or another.  Additionally, if you are going to use the INI file, you may not need the MailTo: unless the E-Mail program requires it in the command line to detect it as the e-mail address (it may allow Subject, Etc to be defined as command line so this is a possibility).  

Think on one more thing:
If "NONE" is returned as the result of the INI file read, run the e-mail address as you have been to run the default browser.  Unless the user specifically tells the program to use a browser, it will automatically use the default one.  This is a normal windows programming technique--so you may want to use it.

Good Luck,

Author Comment

ID: 1341636
Thanks, that worked!  I was wondering, does the first person who answered my question get all of the points?  You answered al of my clarification questions, therefore it seems unfair for you not to receive anything.  How do they divide the points when more than one person provides feedback?

Featured Post

Networking for the Cloud Era

Join Microsoft and Riverbed for a discussion and demonstration of enhancements to SteelConnect:
-One-click orchestration and cloud connectivity in Azure environments
-Tight integration of SD-WAN and WAN optimization capabilities
-Scalability and resiliency equal to a data center

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Convert Jpg /PNG To GIF 5 149
Find and Replace Stream with 0s 8 69
how to update exe applicatio from internet ? 6 86
Delphi: barcode reading on android platform 1 51
A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
Email security requires an ever evolving service that stays up to date with counter-evolving threats. The Email Laundry perform Research and Development to ensure their email security service evolves faster than cyber criminals. We apply our Threat…
The Email Laundry PDF encryption service allows companies to send confidential encrypted  emails to anybody. The PDF document can also contain attachments that are embedded in the encrypted PDF. The password is randomly generated by The Email Laundr…

808 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question