Hacker’s Guide to Visual FoxPro
An irreverent look at how Visual FoxPro really works. Tells you the inside scoop on every command, function, property, event and method of Visual FoxPro.
INI Files
INI Files
are nothing more than text files used to store settings. INI Files
come in two flavors: public and private. The public INI file is Win.INI; all applications are supposed to share this file politely. Private INI Files
are specific to an application. This section discusses how you can read and write to both.
Win.INI is a throwback to Windows 3.1 and is currently supported only for compatibility with 16-bit applications. I would not trust entries in Win.INI to be at all accurate (such as which files are associated with which extension, which printer is currently selected as the default, what other printers are available, international settings for currency, date and time, and other vital information like what wallpaper background is in use).
However, in the current incarnations of Win32 (Windows 9x and NT 4.0), Microsoft has modified the Windows API so calls to read and write the Win.INI actually talk to the Windows Registry. Don’t be surprised to find that your SetProfileString call doesn’t seem to affect the Win.INI text, but works anyway. (For the hackers who just really have to know, the mappings are stored in HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\IniFileMapping\win.ini under NT; we haven’t figured out exactly how Win9x does it.) Since the Win.INI and its Registry equivalent are public information available to all applications, you may want to read the settings there.
The Windows API GetProfileString() function returns the specified value, or a default string passed to it if it is unable to locate the entry. Following is a simple routine to use this function:
* ReadWini - read the WIN.INI file
* Returns a WIN.INI entry 'cEntry' from section 'cSection'
* or blank if not found
PARAMETERS cSection, cEntry
LOCAL cDefault, cRetVal, nRetLen
cDefault = ""
cRetVal = SPACE(255)
nRetLen = LEN(cRetVal)
DECLARE INTEGER GetProfileString IN WIN32API ;
STRING cSection, ;
STRING cEntry, ;
STRING cDefault, ;
STRING @cRetVal, ;
INTEGER nRetLen
nRetLen = GetProfileString(cSection, ;
cEntry, ;
cDefault, ;
@cRetVal, ;
nRetLen)
RETURN LEFT(cRetVal,nRetLen)
Some of our favorite parameters to send to READWINI:
Section Parameter |
Entry Parameter |
Returns: |
.NULL. or 0 |
.NULL. or 0 |
List of all section names, each separated by CHR(0). This seems to work reliably under Windows NT, but it returns empty strings under Windows 95. |
{any section name} |
.NULL. or 0 |
List of all entries in that section, each separated by CHR(0). |
"Ports" |
.NULL. or 0 |
Returns a CHR(0)-delimited list of all ports defined on the machine. |
"Ports" |
Port name returned above |
Returns a string of settings for that port. |
Microsoft has made it a little easier with the addition in Visual FoxPro 3.0b of two new functions to FoxTools.FLL, GetProStrg() and PutProStrg(), to read and write these “public” profile strings.
SET LIBRARY TO HOME()+"FOXTOOLS.FLL" ADDITIVE
LcBuffer = SPACE(1000)
* The function fills lcBuffer with the WIN.INI section
* names out of the Registry, each separated with CHR(0)
lnLen = GetProStrg(0,0,"Empty", @lcBuffer, LEN(lcBuffer)
? LEFT(lcBuffer, lnLen)
* Typical sections include Ports, Devices, etc.
* Let's look at one
lcBuffer = SPACE(1000) && reset the buffer
lnLen = GetProStrg("PrinterPorts", 0, "Empty", ;
@lcBuffer, LEN(lcBuffer))
? LEFT(lcBuffer, lnLen)
* lcBuffer should now contain a list of printers
lcBuffer = SPACE(1000) && reset the buffer
lnLen = GetProStrg("PrinterPorts", "Epson Stylus Color 500",;
"Empty", @lcBuffer, LEN(lcBuffer))
? LEFT(lcBuffer, lnLen)
* lcBuffer should now have the settings for your printer,
* in this case, "winspool, Ne00:, 15, 45"
INI Files
Private information is practically the source of every large modern fortune.
—Oscar Wilde
A private INI file is just a text file, and it is something that every Tom, Dick and Harry can open and mess with using Notepad. That’s the bad news, but also the good news. If we have to dial into a client site and view a set of preferences, an INI file is easy. If we have to coach a client through rebuilding one over the phone (heaven forbid starting with the COPY CON command!), it is far easier to create a few lines of an INI file than it is to rebuild the Registry (see “Registration Database
” for more information on the Registry). On the other hand, the Registry does include some nice features, like automatic system backup, that our poor little INI file will be without.
The Win32 SDK documentation is pretty firm about these commands existing for “backwards compatibility,” and insisting that real 32-bit apps use the Registry instead. We sympathize with Microsoft wanting everyone to play with their new toy, and agree that the Registry does offer wonderful features of security, reliability, multi-user support, and remote administration, but the use of INI Files
is so darned easy, it will be a while until they disappear. Even Microsoft continues to use INI Files
, although not for as sweeping a purpose as in Windows 3.1. Check your Windows directory for *.INI—there are still a few there.
The two routines that follow, to read and write private INI Files
, look an awful lot like the code above. Note that the API functions are not case sensitive—they locate the appropriate sections and settings regardless of the case. READPINI() reads a specified section and entry from a private INI file. Specify the full path of the INI file, unless you want the file stored in the Windows directory.
* ReadPini - read a private .INI file
* Returns the .INI entry 'cEntry' from section 'cSection'
* or blank if not found
PARAMETERS cSection, cEntry, cINIFile
LOCAL cDefault, cRetVal, nRetLen
cDefault = ""
cRetVal = space(255)
nRetLen = LEN(cRetVal)
DECLARE integer GetPrivateProfileString IN WIN32API ;
STRING cSection, ;
String cEntry, ;
STRING cDefault, ;
STRING @cRetVal, ;
INTEGER nRetLen, ;
STRING cINIFile
nRetLen = GetPrivateProfileString(cSection,;
cEntry, ;
cDefault, ;
@cRetVal, ;
nRetLen, ;
cINIFile)
return left(cRetVal,nRetLen)
RITEPINI() writes out a new value to an INI file, and returns a logical value for the success of the operation.
* RitePini - Write an entry in a private .INI file
* returns .T. if successful, .F. if not
PARAMETERS cSection, cEntry, cValue, cINIFile
LOCAL nRetVal
DECLARE Integer WritePrivateProfileString IN WIN32API ;
STRING cSection, ;
STRING cEntry, ;
STRING cValue, ;
STRING cINIFile
nRetVal = WritePrivateProfileString(cSection, ;
cEntry, ;
cValue, ;
cINIFile)
RETURN nRetVal=1
? ReadPini("ODBC 32 bit Drivers", ;
"Microsoft Visual FoxPro Driver (32 bit)", ;
"ODBCINST.INI")
Configuration files, Declare-DLL, Registration Database, Set, Set Resource, Sys(2005), Sys(2019)