Did you ever wonder how a program can remember the list of your most recently opened files, or your font preference, or that you are a registered user? There are several ways this can be done. One way is to write a simple text file, called an "ini" file.
INI FILES
"Ini" is short for "initialization". Liberty BASIC has an ini file that contains your font preference, your list of recent files, your list of externals, and other preferences and records. It is called lbasicxxx.ini and you will find it in the same folder that contains your copy of Liberty BASIC. When Liberty BASIC starts up it reads the information in this file and uses it to set your prefered font, list your recent files in the File menu, and so on. You can open this file in a texteditor and read it. The gui designer that comes with Liberty BASIC, Freeform, also has an ini file.
WRITING TO THE REGISTRY
Windows has a repository of information about the way it works. This is called The Registry. Windows looks in the registry to see which shortcuts should be displayed on your desktop, to record your list of recently opened files, to record your choice of desktop color scheme, display resolution, and all kinds of other information. Applications can write to the registry. This is a very bad idea for novice programmers! If the registry is corrupted Windows may not function properly, or some applications may not function properly. In the worst case the computer may not be usable at all! Considering the risks involved, it makes little sense to store information in the registry when something like an ini file works just fine.
USING THE API TO CREATE AN INI FILE
Earlier versions of Windows did not have a registry. All initialization data was stored in "Ini" files.
The two kernel32 functions, WritePrivateProfileStringA and GetPrivateProfileStringA provide an easy and precise way to write to and read from initialization files. These "ini" files are simple text files. Use this method as an alternative to writing information to the Windows registry. Tampering with the registry can have dire results, even causing Windows to become unusable. Writing to a private ini file can only have an impact on the single program referenced.
You might want to use ini files to record a user's list of recently opened files, or his preferences for use of the program, like syntax color "on" or "off", or even whether he is a registered user of your program.
WRITING AN INI FILE BY API
WritePrivateProfileStringA
First, we'll examine writing to a private ini file. Here is the syntax of the function, which is a part of kernel32.dll:
calldll#kernel32,"WritePrivateProfileStringA", _
Section$ asptr, _ 'section name
Entry$ asptr, _ 'entry name
String$ asptr, _ 'actual entry
FileName$ asptr, _ 'name of ini file
result aslong
Section$
Points to a null-terminated string that specifies the section name to which a string will be copied. Liberty BASIC automatically adds the necessary single null terminator, which is chr$(0), so we don't need to add it. If the section does not exist, it will be created. If you were to read the file in a texteditor, this entry would look like this -- the section name, contained in square brackets:
[section]
If the section were called "user", it would look like this:
[user]
Entry$
Points to a null-terminated string containing the name of the key to be associated with the string. If the entry does not exist it will be created.
If you were to read the file in a texteditor this entry would look like this -- the Entry$ followed by an = sign, followed by the String$
Entry=String
If the Entry was called "name" and string$ was "Carl Gundel", it would look like this:
name=Carl Gundel
If this is _NULL (=0) and passed as type ulong instead of ptr, the entire section is deleted.
_NULL asulong, _ 'section is null, delete section$
String$
Points to the null-terminated string value to be written to the file.
Entry=String
If the Entry was called "name", and the String$ was "Carl Gundel",it would look like this:
name=Carl Gundel
If this is _NULL (=0) and passed as type ulong instead of ptr, the entry is deleted.
_NULL asulong, _ 'entry is null, delete entry$
FileName$
Points to a null-terminated string that names the INI file. If this name is a fully-qualified path and file name, it will be used. If there is no path, Windows searches for the file in the Windows directory. If it doesn't exist, it will be created.
result
Returns zero if it fails, or nonzero if it is successful.
DEMO
Here is a demo. After running this small routine, look in the Windows folder for the file "testme.ini". Open it in Notepad to see the result. Notice that your program does not need to "open" or "close" the file as you would normally do when writing to a file in Liberty BASIC.
I ran the program then looked in my Windows folder for the file, "testme.ini" and this is what it contained:
[User]
Name=Carl Gundel
We can use this method to record many kinds of information.
READING AN INI FILE BY API
GetPrivateProfileStringA
This function reads a specific ini file. Many arguments are the same as the ones in WritePrivateProfileStringA. There are some additional arguments, which will be explained later.
Section$, and FileName$ are explained earlier in the decription of WritePrivateProfileStringA.
Entry$
Points to the null-terminated string that is associated with the value string. If this parameter is empty, the return string will contain a list of all values in the specified section, separated by null characters, and terminated with double null characters.
Default$
Points to a null-terminated string that specifies the default value for the given entry if the entry cannot be found in the initialization file. This parameter must never be NULL or empty. You might want to specify a value that makes it clear that this section of the ini file was blank.
Default$ = "no name given"
ReturnString$
Points to a null-terminated string that will contain the key value stored in the ini file. If the key value cannot be found, this buffer will contain the contents of the Default$ value. There is an important difference in the use of this string argument in GetPrivateProfileStringA. We will be reading data that is placed into this variables by the API function. This means that we must pass this argument "By Reference". Passing it this way means that we are not just passing the value of the string, we are passing its memory address so that the function can alter the data contained at that address. To let Liberty BASIC know that we want to pass the argument "By Reference", we include a null-termination on the string, like this:
ReturnString$ = space$(100) + chr$(0)
The addition of a null terminator to signal "by reference" no longer appears to be needed by Liberty BASIC. Strings appear to be passed "by reference" automatically.
Above, we are creating a buffer, or location in memory that is large enough to contain the data that will be placed there by the function.
SizeString
This parameter specifies the length of the buffer, ReturnString$
result
The return value specifies the number of bytes copied to the specified buffer, not including the terminating null character. This means that it specifies the length of the text that the function placed into the buffer. We can use this information to read the value in the ini file without extraneous characters that might be tacked onto the end.
Demo Two
Here is a working example, that reads the values written to "testme.ini" that were produced in the routine above:
If you were now to use Notepad to open "testme.ini" found in the Windows directory, it would look like this:
[User]
Name=Carl Gundel
DEMO THREE
Here is a small demo that checks the ini file to see if the user has registered. You would, of course, put your own code to handle the situation. The demo simply gives a notice telling if the user is registered when the program starts. There is a button that the user can click to enter his password. Run the program for the first time, and you will get a "Not registered." notice. Click the button and type the proper password. Close the program. Run the program again, and you should receive notice that you are a "Registered user."
This demo is similar to the earlier demos, but it uses a different section and entry name:
Section$="Register"
Entry$="Password"nomainwinbutton#1,"Register",[reg],UL,10,10,120,26statictext#1,"Password = 'Official'",10,50,200,30open"Register My App"for window_nf as#1print#1,"trapclose [quit]"gosub[readReg]'see if user has registeredif key$<>"Official"thennotice"Not registered."elsenotice"Registered user."endifwait[quit]close#1:end[reg]prompt"Enter password";pw$
if pw$=""thennotice"Not a valid password."endif
Section$="Register"
Entry$="Password"
String$=pw$
FileName$="testme.ini"CallDLL#kernel32,"WritePrivateProfileStringA", _
Section$ Asptr, _
Entry$ Asptr, _
String$ Asptr, _
FileName$ Asptr, _
result Aslongwait[readReg]
Section$="Register"
Entry$="Password"
FileName$="testme.ini"
Default$ ="no password"+Chr$(0)
SizeString=100
ReturnString$=Space$(SizeString)+Chr$(0)CallDLL#kernel32,"GetPrivateProfileStringA", _
Section$ Asptr, _
Entry$ Asptr, _
Default$ Asptr, _
ReturnString$ Asptr, _
SizeString Aslong, _
FileName$ Asptr, _
result Aslong
key$=Left$(ReturnString$,result)return
Using Structs
Analogous functions allow you to write and read the information in structs rather than strings. The following snippets of code are not full programs and cannot be run as is.
WritePrivateProfileStructA looks like this:
'code by Richard Russellstruct config, soundon aslong, fullscreen aslong
config.soundon.struct=1
config.fullscreen.struct=0
size =len(config.struct)calldll#kernel32,"WritePrivateProfileStructA", _
"settings"asptr, _ ' Section name "config"asptr, _ ' Key name
config asstruct, _ ' Structure
size asulong, _ ' Size of structure
inifile$ asptr, ret aslong
The data is then read with GetPrivateProfileStructA
'code by Richard Russell
size =len(config.struct)calldll#kernel32,"GetPrivateProfileStructA", _
"settings"asptr, _ ' Section name "config"asptr, _ ' Key name
config asstruct, _ ' Structure
size asulong, _ ' Size of structure
inifile$ asptr, ret aslong
an alternative to using the registry
originally published in Liberty BASIC Newsletter #102
-
Storing Program Initialization Data | INI FILES | WRITING TO THE REGISTRY | USING THE API TO CREATE AN INI FILE | WRITING AN INI FILE BY API | DEMO | READING AN INI FILE BY API | Demo Two | DEMO THREE | Using Structs
Storing Program Initialization Data
Did you ever wonder how a program can remember the list of your most recently opened files, or your font preference, or that you are a registered user? There are several ways this can be done. One way is to write a simple text file, called an "ini" file.INI FILES
"Ini" is short for "initialization". Liberty BASIC has an ini file that contains your font preference, your list of recent files, your list of externals, and other preferences and records. It is called lbasicxxx.ini and you will find it in the same folder that contains your copy of Liberty BASIC. When Liberty BASIC starts up it reads the information in this file and uses it to set your prefered font, list your recent files in the File menu, and so on. You can open this file in a texteditor and read it. The gui designer that comes with Liberty BASIC, Freeform, also has an ini file.WRITING TO THE REGISTRY
Windows has a repository of information about the way it works. This is called The Registry. Windows looks in the registry to see which shortcuts should be displayed on your desktop, to record your list of recently opened files, to record your choice of desktop color scheme, display resolution, and all kinds of other information. Applications can write to the registry. This is a very bad idea for novice programmers! If the registry is corrupted Windows may not function properly, or some applications may not function properly. In the worst case the computer may not be usable at all! Considering the risks involved, it makes little sense to store information in the registry when something like an ini file works just fine.USING THE API TO CREATE AN INI FILE
Earlier versions of Windows did not have a registry. All initialization data was stored in "Ini" files.The two kernel32 functions, WritePrivateProfileStringA and GetPrivateProfileStringA provide an easy and precise way to write to and read from initialization files. These "ini" files are simple text files. Use this method as an alternative to writing information to the Windows registry. Tampering with the registry can have dire results, even causing Windows to become unusable. Writing to a private ini file can only have an impact on the single program referenced.
You might want to use ini files to record a user's list of recently opened files, or his preferences for use of the program, like syntax color "on" or "off", or even whether he is a registered user of your program.
WRITING AN INI FILE BY API
WritePrivateProfileStringAFirst, we'll examine writing to a private ini file. Here is the syntax of the function, which is a part of kernel32.dll:
Section$
Points to a null-terminated string that specifies the section name to which a string will be copied. Liberty BASIC automatically adds the necessary single null terminator, which is chr$(0), so we don't need to add it. If the section does not exist, it will be created. If you were to read the file in a texteditor, this entry would look like this -- the section name, contained in square brackets:
[section]
If the section were called "user", it would look like this:
[user]
Entry$
Points to a null-terminated string containing the name of the key to be associated with the string. If the entry does not exist it will be created.
If you were to read the file in a texteditor this entry would look like this -- the Entry$ followed by an = sign, followed by the String$
Entry=String
If the Entry was called "name" and string$ was "Carl Gundel", it would look like this:
name=Carl Gundel
If this is _NULL (=0) and passed as type ulong instead of ptr, the entire section is deleted.
String$
Points to the null-terminated string value to be written to the file.
Entry=String
If the Entry was called "name", and the String$ was "Carl Gundel",it would look like this:
name=Carl Gundel
If this is _NULL (=0) and passed as type ulong instead of ptr, the entry is deleted.
FileName$
Points to a null-terminated string that names the INI file. If this name is a fully-qualified path and file name, it will be used. If there is no path, Windows searches for the file in the Windows directory. If it doesn't exist, it will be created.
result
Returns zero if it fails, or nonzero if it is successful.
DEMO
Here is a demo. After running this small routine, look in the Windows folder for the file "testme.ini". Open it in Notepad to see the result. Notice that your program does not need to "open" or "close" the file as you would normally do when writing to a file in Liberty BASIC.I ran the program then looked in my Windows folder for the file, "testme.ini" and this is what it contained:
[User]
Name=Carl Gundel
We can use this method to record many kinds of information.
READING AN INI FILE BY API
GetPrivateProfileStringAThis function reads a specific ini file. Many arguments are the same as the ones in WritePrivateProfileStringA. There are some additional arguments, which will be explained later.
Section$, and FileName$ are explained earlier in the decription of WritePrivateProfileStringA.
Entry$
Points to the null-terminated string that is associated with the value string. If this parameter is empty, the return string will contain a list of all values in the specified section, separated by null characters, and terminated with double null characters.
Default$
Points to a null-terminated string that specifies the default value for the given entry if the entry cannot be found in the initialization file. This parameter must never be NULL or empty. You might want to specify a value that makes it clear that this section of the ini file was blank.
Default$ = "no name given"
ReturnString$
Points to a null-terminated string that will contain the key value stored in the ini file. If the key value cannot be found, this buffer will contain the contents of the Default$ value. There is an important difference in the use of this string argument in GetPrivateProfileStringA. We will be reading data that is placed into this variables by the API function. This means that we must pass this argument "By Reference". Passing it this way means that we are not just passing the value of the string, we are passing its memory address so that the function can alter the data contained at that address. To let Liberty BASIC know that we want to pass the argument "By Reference", we include a null-termination on the string, like this:
ReturnString$ = space$(100) + chr$(0)
The addition of a null terminator to signal "by reference" no longer appears to be needed by Liberty BASIC. Strings appear to be passed "by reference" automatically.
Above, we are creating a buffer, or location in memory that is large enough to contain the data that will be placed there by the function.
SizeString
This parameter specifies the length of the buffer, ReturnString$
result
The return value specifies the number of bytes copied to the specified buffer, not including the terminating null character. This means that it specifies the length of the text that the function placed into the buffer. We can use this information to read the value in the ini file without extraneous characters that might be tacked onto the end.
Demo Two
Here is a working example, that reads the values written to "testme.ini" that were produced in the routine above:If you were now to use Notepad to open "testme.ini" found in the Windows directory, it would look like this:
[User]
Name=Carl Gundel
DEMO THREE
Here is a small demo that checks the ini file to see if the user has registered. You would, of course, put your own code to handle the situation. The demo simply gives a notice telling if the user is registered when the program starts. There is a button that the user can click to enter his password. Run the program for the first time, and you will get a "Not registered." notice. Click the button and type the proper password. Close the program. Run the program again, and you should receive notice that you are a "Registered user."This demo is similar to the earlier demos, but it uses a different section and entry name:
Using Structs
Analogous functions allow you to write and read the information in structs rather than strings. The following snippets of code are not full programs and cannot be run as is.WritePrivateProfileStructA looks like this:
The data is then read with GetPrivateProfileStructA
To retrieve the information from the struct:
For a working demonstration of WritePrivateProfileStructA by -
WritePrivateProfileStructA Full Demo
Storing Program Initialization Data | INI FILES | WRITING TO THE REGISTRY | USING THE API TO CREATE AN INI FILE | WRITING AN INI FILE BY API | DEMO | READING AN INI FILE BY API | Demo Two | DEMO THREE | Using Structs