CIniFile: Difference between revisions
m doh! - fixed cat tutorial |
m Sets _not_ Gets! |
||
(4 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
An object of the cIniFile class can be used for reading information avaiable from an INI file. | 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. | INI files are often used to store user preferences or setup options for applications. | ||
==INI files== | |||
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): | 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): | ||
<source lang="ini"> | |||
[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 | |||
</source> | |||
As you can see, it defines two sections - [boot loader] and [operating systems] - each with different settings within them. | 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 | ==Visual DataFlex Workspace files== | ||
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 article 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: | |||
<source lang="ini"> | |||
[Workspace] | |||
Home=..\ | |||
AppSrcPath=.\AppSrc | |||
AppHTMLPath=.\AppHtml | |||
BitmapPath=.\Bitmaps | |||
IdeSrcPath=.\IdeSrc | |||
DataPath=.\Data | |||
DDSrcPath=.\DdSrc | |||
HelpPath=.\Help | |||
ProgramPath=.\Programs | |||
FileList=.\Data\Filelist.cfg | |||
Description=MyFirstProject | |||
</source> | |||
Here only a single section - [Workspace] - is defined, however the fact that an INI file can 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. | Here only a single section - [Workspace] - is defined, however the fact that an INI file can 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. | ||
Line 33: | Line 39: | ||
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 [http://en.wikipedia.org/wiki/Camelcase camelCase] to supply readability). | 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 [http://en.wikipedia.org/wiki/Camelcase camelCase] to supply readability). | ||
==INI file advantages== | |||
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 [http://en.wikipedia.org/wiki/Windows_Registry 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. | 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 [http://en.wikipedia.org/wiki/Windows_Registry 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: | Here is an example where an additional section allowing the configuration of a database location and login has been added: | ||
<source lang="ini"> | |||
[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=MSSQLDRV | |||
</source> | |||
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. | 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. | ||
==Accessing INI files== | |||
So how do you access that information in your program? | So how do you access that information in your program? | ||
Line 67: | Line 76: | ||
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''): | 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''): | ||
<source lang="vdf"> | |||
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 | |||
Set psServer to sServer | |||
Set psLogin to sLogin | |||
Set psPassword to sPW | |||
Set psDriver to sDrv | |||
Set psDatabase to sDB | |||
Set pbDoLogin to bDB | |||
</source> | |||
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 to use 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. | 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 to use 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. | ||
Line 106: | Line 117: | ||
You could save some code by not retrieving the properties into local variables first, but using the properties as defaults directly: | You could save some code by not retrieving the properties into local variables first, but using the properties as defaults directly: | ||
<source lang="dataflex"> | |||
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 | |||
</source> | |||
Or even dispense with the local variables completely: | Or even dispense with the local variables completely: | ||
<source lang="dataflex"> | |||
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))) | |||
</source> | |||
But some might consider that a bridge too far! | But some might consider that a bridge too far! | ||
==Summary== | |||
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. | 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. | ||
Latest revision as of 09:01, 11 August 2021
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.
INI files
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.
Visual DataFlex Workspace files
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 article 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 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).
INI file advantages
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=MSSQLDRV
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.
Accessing INI files
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 in "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 Set psServer to sServer Set psLogin to sLogin Set psPassword to sPW Set psDriver to sDrv Set psDatabase to sDB Set 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 to use 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 consider that a bridge too far!
Summary
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