CIniFile

From DataFlex Wiki
Revision as of 09:03, 5 April 2008 by 217.149.208.61 (talk)
Jump to navigationJump to search

An object of the cIniFile class can be used for reading information avaiable from an INI file.

INI files are often used to store user preferences or setup options for applications.

In Visual DataFlex you can freely use as many INI files as you require, however the two-level structure of INI files (sections and keys) means that there is often no need to use more than one. Here, for example, is a boot.ini file (usually found in the root directory of the system drive of Windows operating systems):

[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(2)\WINDOWS

[operating systems]
multi(0)disk(0)rdisk(0)partition(2)\WINDOWS="Microsoft Windows XP Professional" /fastdetect /NoExecute=OptIn

As you can see, it defines two sections - [boot loader] and [operating systems] - each with different settings within them.

Another example are the workspace configuration files used by Visual DataFlex itself (by default named "Config.ws", showing that they don't have to use the .ini extension - see the artice in "See Also" below), which must exist in the same directory the program is run from (usually the "Programs" subdirectory of the workspace). Here is an example:

[Workspace]
Home=..\
AppSrcPath=.\AppSrc
AppHTMLPath=.\AppHtml
BitmapPath=.\Bitmaps
IdeSrcPath=.\IdeSrc
DataPath=.\Data
DDSrcPath=.\DdSrc
HelpPath=.\Help
ProgramPath=.\Programs
FileList=.\Data\Filelist.cfg
Description=MyFirstProject

Here only a single section - [Workspace] - is defined, however the fact that an INI file can have have as many sections as it needs means that you can use this very file to set up options for how you want your program to behave.

Note that section names (the ones in the square brackets), key names ("Home", "AppSrcPath", etc.) and key values can all contain spaces (although for my own part I prefer not to use those and depend on camelCase to supply readability).

The advantage of the INI file approach is that it can make programs configurable for different environments or uses without them having to be recompiled with different settings each time: the program can be made with a set of default values which can then be overridden at run-time by the settings in an INI file. It has the advantage over Registry settings, which perform very much the same function, in that you don't need any special rights on the machine to set it up and make changes to it: you are just working with text files, so security policy issues about who has rights to the Windows Registry, or who can run RegEdit or RegEdit32 do not apply - if you can run Notepad and modify files you can configure your application.

Here is an example where an additional section allowing the configuration of a database location and login has been added:

[Workspace]
Home=..\
AppSrcPath=.\AppSrc
AppHTMLPath=.\AppHtml
BitmapPath=.\Bitmaps
IdeSrcPath=.\IdeSrc
DataPath=.\Data
DDSrcPath=.\DdSrc
HelpPath=.\Help
ProgramPath=.\Programs
FileList=.\Data\Filelist.cfg
Description=MyFirstProject

[Database Login]
Server=big-iron.database-servers.local
Login=itsme
Password=letmein
Database=Accounting
Driver=MSSQL

Combining these factors - the fact that there is probably no need to have more than one INI file, and the fact that Visual DataFlex requres one anyway - means that for most purposes you can just add what you need to the existing workspace configuration file.

So how do you access that information in your program?

For most purposes the information in an INI file will only be read at program start-up. This means that (a) the oApplication object is a good place to do such things (see the article in "See Also" below for some guidance on sub-classing the cApplicatiion class) and (b) the cIniFile object need not be retained after it has been used. (Of course you might have different requirements, but here we will assume these are true.)

So... in your oApplication object (perhaps in the "OnCreate" procedure, perhaps elsewhere, such as "Construct_Object" or "End_Construct_Object") what you need to do is dynamically create a cIniFile object, use it to get the information you want, then destroy it again. You also want to be able to access the workspace configuration file for the application, perhaps without knowing ahead of time what that is actually called.

Here is one way of doing it (note - this code is assumed to be in the oApplication object or a sub-class of the cApplication class; the only place this matters is in the "Set psFileName ..." line, where "Self" will refer to the oApplication object, and where the various properties are held):

  String  sServer sLogin sPW sDrv sDB
  Boolean bLogin
  Handle  hoIni

  // Retrieve your application defaults into local variables
  Get psServer   to sServer
  Get psLogin    to sLogin
  Get psPassword to sPW
  Get psDriver   to sDrv
  Get psDatabase to sDB
  Get pbDoLogin  to bDB

  Get Create U_cIniFile to hoIni    // Create INI file object

  // Make it use the workspace configuration file
  Set psFileName of hoIni to (psWorkspaceWSFile(phoWorkspace(Self)))

  // Read the information
  Move (ReadString(hoIni, "Database Login", "Server",   sServer)) to sServer
  Move (ReadString(hoIni, "Database Login", "Login",    sLogin))  to sLogin
  Move (ReadString(hoIni, "Database Login", "Password", sPW))     to sPW
  Move (ReadString(hoIni, "Database Login", "Driver",   sDrv))    to sDrv
  Move (ReadString(hoIni, "Database Login", "Database", sDB))     to sDB
  Move (ReadString(hoIni, "Database Login", "DoLogin",  bLogin))  to bLogin
     
  Send Destroy of hoIni             // And Destroy it again

  // Set the properties to make the information persistent
  Get psServer   to sServer
  Get psLogin    to sLogin
  Get psPassword to sPW
  Get psDriver   to sDrv
  Get psDatabase to sDB
  Get pbDoLogin  to bDB

The above code will retrieve the values set in the second workspace file example above. Note that in that example, the "DoLogin" value is not present - the "ReadString" method of the cIniFile class lets you supply a default value if the setting is not present, and here we have used the bLogin variable, which was set from the pbDoLogin property, and which is then used to set that property again... so the fact that the setting is absent (not "missing" - it is deliberate!) means that the default property remains unchanged.

You could save some code by not retrieving the properties into local variables first, but using the properties as defaults directly:

  Move (ReadString(hoIni, "Database Login", "Server",   psServer(Self)))   to sServer
  Move (ReadString(hoIni, "Database Login", "Login",    psLogin(Self)))    to sLogin
  Move (ReadString(hoIni, "Database Login", "Password", psPassword(Self))) to sPW
  Move (ReadString(hoIni, "Database Login", "Driver",   psDriver(Self)))   to sDrv
  Move (ReadString(hoIni, "Database Login", "Database", psDatabase(Self))) to sDB
  Move (ReadString(hoIni, "Database Login", "DoLogin",  pbDoLogin(Self)))  to bLogin

Or even dispense with the local variables completely:

  Set psServer   to (ReadString(hoIni, "Database Login", "Server",   psServer(Self)))
  Set psLogin    to (ReadString(hoIni, "Database Login", "Login",    psLogin(Self)))
  Set psPassword to (ReadString(hoIni, "Database Login", "Password", psPassword(Self)))
  Set psDriver   to (ReadString(hoIni, "Database Login", "Driver",   psDriver(Self)))
  Set psDatabase to (ReadString(hoIni, "Database Login", "Database", psDatabase(Self)))
  Set pbDoLogin  to (ReadString(hoIni, "Database Login", "DoLogin",  pbDoLogin(Self)))

But some might consder that a bridge too far!

The cIniFile has other methods as well: it can write as well as read (WriteString, DeleteKey and DeleteSection) and can dynamically determine the contents of the file (ReadSections, ReadSection, SectionExists and KeyExists) - see the VDF Help for full information - but the ReadString method is the one you will need in most circumstances.

See Also

Passing the workspace as a parameter

External references