Creating an INI File EditorNow that you are familiar with the set of API functions that are used to access INI files, a sample program that better illustrates how the functions are used is in order. The program only uses the functions for accessing private INI files because it's not a good idea to casually fool around with the system INI file (WIN.INI). The program that is created here will be built on later in this chapter in order to show how the API functions for accessing the System Registry are used. For now, however, we'll only concentrate on the INI functions. To create the sample program, first build its user interface using Table 32.3, Table 32.4, and Figure 32.1 as guides. Table 32.3 lists the various controls that make up the interface, along with their properties. Table 32.4 lists the menu items that need to be added to the program's menu using VB's Menu Editor: |
Table 32.3. The controls and their properties for the INI File/System Registry Editor program.
Control Type |
Property |
Value |
Form | Name | frmINIEdit |
StartUpPosition | 2 - Center Screen | |
Label | Name | lblSectionName |
Caption | Section Name | |
Height | 255 | |
Left | 240 | |
Top | 120 | |
Width | 1815 | |
TextBox | Name | txtSectionName |
Enabled | False | |
Height | 285 | |
Left | 240 | |
Top | 360 | |
Width | 4575 | |
Label | Name | lblKeyName |
Caption | Key Name | |
Height | 255 | |
Left | 240 | |
Top | 720 | |
Width | 1575 | |
TextBox | Name | txtKeyName |
Enabled | False | |
Height | 285 | |
Left | 240 | |
Top | 960 | |
Width | 4575 | |
Label | Name | lblValue |
Caption | Value | |
Height | 255 | |
Left | 240 | |
Top | 2640 | |
Width | 1575 | |
TextBox | Name | txtValue |
Enabled | False | |
Height | 285 | |
Left | 240 | |
Top | 1560 | |
Width | 4575 | |
CommandButton | Name | cmdRetrieve |
Caption | Retrieve | |
Enabled | False | |
Height | 375 | |
Left | 240 | |
Top | 2040 | |
Width | 1095 | |
CommandButton | Name | cmdUpdate |
Caption | Update | |
Enabled | False | |
Height | 375 | |
Left | 1440 | |
Top | 2040 | |
Width | 1095 | |
CommandButton | Name | cmdAdd |
Caption | False | |
Height | 375 | |
Left | 2640 | |
Top | 2040 | |
Width | 1095 | |
CommandButton | Name | cmdDelete |
Caption | False | |
Height | 375 | |
Left | 3840 | |
Top | 2040 | |
Width | 1095 | |
CommandButton | Name | cmdRefresh |
Caption | False | |
Height | 375 | |
Left | 5040 | |
Top | 2040 | |
Width | 1095 | |
Label | Name | lblFileContents |
Caption | INI File Contents | |
Height | 255 | |
Left | 240 | |
Top | 2640 | |
Width | 1575 | |
ListBox | Name | lstFileContents |
Height | 2205 | |
Left | 240 | |
Top | 2880 | |
Width | 5895 | |
Label | Name | lblLastOpStatus |
Caption | Last Operation Status | |
Height | 240 | |
Left | 240 | |
Top | 5280 | |
Width | 1575 | |
Label | Name | lblStatus |
Alignment | 2 - Center | |
BorderStyle | 1 - Fixed Single | |
Height | 255 | |
Left | 240 | |
Top | 5520 | |
Width | 5895 | |
CommonDialog | Name | dlgGetFilename |
Left | 5160 | |
Top | 480 | |
FileName | *.ini | |
Filter | *.ini | |
OptionButton | Name | optType |
Caption | Registry | |
Enabled | False | |
Height | 255 | |
Index | 1 | |
Left | 5160 | |
Top | 1440 | |
Value | True | |
Width | 1215 | |
OptionButton | Name | optType |
Caption | INI File | |
Enabled | True | |
Height | 195 | |
Index | 0 | |
Left | 5160 | |
Top | 1200 | |
Value | False | |
Width | 1095 |
Table 32.4. The menu items for the sample program, to be added with VB's Menu Editor.
Menu Item Name |
Caption |
mnuFile | File |
mnuFileOpenINIFile | Open INI File... |
mnuExit | Exit |
Figure 32.1 The INI File/System Registry Editor program's user interface. After the user interface has been designed, the program code can be added. But first, add a new module to the project so the API functions can be declared. Call the module INIEdit, then add the code in Listing 32.1. Listing 32.1. - The code for the INIEdit module. |
Public Declare Function GetPrivateProfileSection Lib "kernel32" _ Alias "GetPrivateProfileSectionA" (ByVal lpAppName As String, _ ByVal lpReturnedString As String, ByVal nSize As Long, _ ByVal lpFileName As String) As Long Public Declare Function GetPrivateProfileString Lib "kernel32" _ Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String,ByVal lpKeyName As Any, ByVal lpDefault As Strng, _ ByVal lpReturnedString As String, ByVal nSize As Long, _ ByVal lpFileName As String) As Long Public Declare Function WritePrivateProfileSection Lib "kernel32" _ Alias "WritePrivateProfileSectionA" (ByVal lpAppName As String, _ ByVal lpString As String, ByVal lpFileName As String) As Long Public Declare Function WritePrivateProfileString Lib "kernel32" _ Alias "WritePrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpString As Any, _ ByVal lpFileName As String) As Long Public gstrKeyValue As String * 256
Note that in the previous code, a global
fixed-length string (gstrKeyValue) is also declared. This string will be used as the
buffer for retrieving or setting key values using the API functions. The next section of code to be added (Listing 32.2) is for the cmdAdd CommandButton control's Click event and INIAdd, the function that it calls to add a section or key to an INI file. Listing 32.2. - The cmdAdd_Click event and the INIAdd function, which adds a section or key to the INI file. |
Private Sub cmdAdd_Click() ' Make sure the user entered a section name. If txtSectionName.Text = "" Then MsgBox "Please enter a section name first." Exit Sub End IF ' For INI files, call the INIAdd function. For ' the Registry, call the RegAdd function. If optType(0).Value = True Then lblStatus = INIAdd() Else lblStatus = RegAdd() End If End Sub Private Function INIAdd() As String Dim lonStatus As Long Dim strSectionName As String ' Remove brackets from section name, if necessary. strSectionName = FixSectionName(txtSectionName.Text) If txtKeyName.Text = "" Then<' No key name was specified, so add a new (empty) ' section with the WritePrivateProfileSection ' API function. lonStatus="WritePrivateProfileSection(strSectionName," _ "", dlgGetFilename.FileName) ' Determine the status of the operation. If lonStatus="0" Then INIAdd=""Error" Section could not be added" Else INIAdd=""Section" added succesfully" ReadFile End If Else ' Use the WritePrivateProfileString API function ' to add the key and, if necessary, the section. lonStatus="WritePrivateProfileString(strSectionName," _ txtKeyName.Text, txtValue.Text, dlgGetFilename.FileName) ' Determine the status of the operation. If lonStatus="0" Then INIAdd=""Error" Key could not be added" Else INIAdd=""Key" added successfully" ReadFile End If End If End Function
The cmdAdd_Click event first ensures that a
section name has been entered in the txtSectionName text box. It then calls one of two
functions, INIAdd or RegAdd, based on the state of the INI File/Registry option buttons.
Each function returns a string value that indicates the status of the operation. This
status string is displayed in the lblStatus Label control. This format[md] checking the
text boxes, calling separate routines for INI file or Registry operations, and then
displaying the status[md]is used for all of the command buttons except the Refresh button,
which is disabled when the Registry option button is selected. The RegAdd function will be added later in this chapter when the Registry functions are discussed. No error can occur because the Registry option button is currently disabled. The INIAdd function first ensures first calls the FixSectionName function, which removes brackets that enclose the section name. This function will be added later. If no key name has been provided by the user in the txtKeyName text box, then it is assumed that a section is to be added. Because it has already been verified that a section name has been entered, the procedure can then use the WritePrivateProfileSection API function to create the new section. Note that the lpString argument for the API function is passed as an empty string (""), indicating that there is no list of keys to be updated. If a key name has been provided, then the procedure uses the WritePrivateProfileString API function to add or update the key and its value. The key value is taken from the txtValue text box. The name and path of the INI file, which is obtained using the CommonDialog control dlgGetFilename, is passed to the API functions as the lpFileName argument. It is the same way in the rest of the INI functions that compose the sample program. After the WritePrivateProfileSection or WritePrivateProfileString functions are called, the status of the operation is returned by the INIAdd function. If the functions are successful, the contents of the INI file are re-displayed using the ReadFile procedure, which will also be added later. The next section of program code (Listing 32.3) is for the Retrieve button. Again, two procedures are used: the cmdRetrieve_Click event and the INIRetrieve function. Listing 32.3. - The cmdRetrieve_Click event and the INIRetrieve function, which retrieves a given key's value from the INI file. |
Private Sub cmdRetrieve_Click() Dim lonOpStatus As Long ' Make sure both a key name and a section name ' have been specified by the user. If txtSectionName.Text = "" Then MsgBox "Please enter a section name first." Exit Sub End If If txtKeyName.Text = "" Then MsgBox "Please enter a key name first." Exit Sub End If ' For INI files, call the INIRetrieve function. For ' the Registry, call the RegRetrieve function. If optType(0).Value = True Then lblStatus = INIRetrieve() Else lblStatus = RegRetrieve() End If End Sub Private Function INIRetrieve() As String Dim lonValueSize As Long Dim strSectionName As String ' Remove brackets from section name, if necessary. strSectionName = FixSectionName(txtSectionName.Text) ' Use the GetPrivateProfileString API function to ' retrieve the key's value from the file. A default ' value of "?!?" is used to see if the key has been ' retrieved successfully. lonValueSize = GetPrivateProfileString(strSectionName, _ txtKeyName.Text, "?!?", gstrKeyValue, 256, _ dlgGetFilename.FileName) ' Determine the status of the operation. If the<' value of the key is the same as the default value ' ("?!?"), then the key was probably not found. If Left$(gstrKeyValue, 3)=""?!?"" Then INIRetrieve=""Error" Key could not be located" Else INIRetrieve=""Key" retrieved successfully" txtValue.Text="Left$(gstrKeyValue," lonValueSize) End If End Function
You already know how the cmdRetrieve_Click
event works, since it is very similar to the cmdAdd_Click event that was added earlier.
Therefore, we'll press on to the discussion of the INIRetrieve function. The first thing the INIRetrieve function does is strip the brackets from the section name using the FixSectionName function. This is pretty much standard in all of the program's INI functions. The GetPrivateProfileString API function is used to retrieve the key's value. A default value of "?!?" is given so the success of the operation can be determined later. If the function places a value of "?!?" in the buffer (gstrKeyValue), it's a pretty safe bet that the key was not found. The gstrKeyValue, which is used as the buffer in which the key value is to be placed by the function, was declared globally in the module that was added earlier. It is a fixed-length string of 256 characters, so a value of 256 is passed as the API function's nSize argument. If the key is found (that is, a value of anything other than "?!?" is placed in gstrKeyValue), then the key value is displayed in the txtValue text box. Again, the status of the operation is returned by the function. Next, add the code for the Update button (Listing 32.4). The cmdUpdate_Click event and the INIUpdate function are the procedures that are used. Listing 32.4. - The cmdUpdate_Click event and the INIUpdate function, which updates a given key's value in the INI file. |
Private Sub cmdUpdate_Click() ' Make sure both a key name and a section name ' have been specified by the user. If txtSectionName.Text = "" Then MsgBox "Please enter a section name first." Exit Sub End If If txtKeyName.Text = "" Then MsgBox "Please enter a key name first." Exit Sub End If ' For INI files, call the INIUpdate function. For ' the Registry, call the RegUpdate function. If optType(0).Value = True Then lblStatus = INIUpdate Else lblStatus = RegUpdate End If End Sub Private Function INIUpdate() As String Dim lonStatus As Long Dim strSectionName As String ' Remove brackets from section name, if necessary strSectionName = FixSectionName(txtSectionName.Text) ' Use the WritePrivateProfileString API function to ' update the key. lonStatus = WritePrivateProfileString(strSectionName, _ txtKeyName.Text, txtValue.Text, dlgGetFilename.FileName) ' Display the status of the operation and update ' the file contents list box if successful. If lonStatus = 0 Then INIUpdate = "Error - Key could not be updated" Else INIUpdate = "Key updated successfully" ReadFile End If End Function
If you've been following along, then the
INIUpdate function will be pretty easy to figure out. First, the FixSectionName function
strips the brackets from around the section name, if necessary. The
WritePrivateProfileString function is then called and is passed the section name, key
name, and value. The status of the operation is returned by the INIUpdate function and the
contents of the INI file are re-read and displayed using the ReadFile function if the
operation is successful. The next command button to be coded is the Delete button. Add the code for the cmdDelete_Click event and the INIDelete function as shown in Listing 32.5: Listing 32.5. - The cmdDelete_Click event and the INIDelete function, which deletes a key or section from the INI file. |
Private Sub cmdDelete_Click() ' Make sure the user entered a section name. If txtSectionName.Text = "" Then MsgBox "Please enter a section name first." Exit Sub
The cmdDelete_Click event is slightly
different than the rest of the Click events so far. For INI files, it only checks to see
if the section name has been entered. This is because it is possible to delete an entire
section from the INI file, so a key name is not necessary. When dealing with the Registry,
however, both the txtSectionName and txtKeyName text boxes need to be used. The INIDelete event is perhaps a little more complicated than the other procedures, but it's still pretty straightforward. As always, the FixSectionName function is called. Then the txtKeyName text box is examined to see if a key name was entered. If not, it is assumed that the section is to be deleted. The user is prompted to ensure that this is really what was intended. If the user okays the section deletion, the strKeyName variable is set to vbNullString. Later, this variable will be passed to the WritePrivateProfileString API function. The vbNullString value tells the function that the entire section is to be deleted rather than an individual key. If the txtKeyName text box does contain a key name, the name is assigned to the strKeyName variable. When that value is passed to the API function, the function knows that it is supposed to delete a single key. After the strKeyName variable has been assigned, the WritePrivateProfileString API function is called. The status is returned by the INIDelete function. If the operation is successful, the txtKeyName and txtValue text boxes are cleared because the key no longer exists, and the contents of the INI file are re-displayed with the ReadFile function. The last button event code to add is for the cmdRefresh_Click event (Listing 32.6): Listing 32.6. - The cmdRefresh button's Click event, which simply uses the ReadFile function to re-display the INI file's contents. |
Private Sub cmdRefresh_Click() ' Update the contents of the list box with the ' ReadFile procedure. ReadFile End Sub
The cmdRefresh_Click event simply calls the
ReadFile procedure, which re-displays (refreshes) the contents of the INI file in the
lstFileContents ListBox control. Speaking of the ReadFile procedure, that is to be added next (Listing 32.7): Listing 32.7. - The ReadFile procedure, used for reading the contents of the INI file and displaying them in a list box. |
Private Sub ReadFile() Dim intFileNum As Integer Dim strLineIn As String ' Re-read the current INI file and display it ' in the list box lstFileContents. lstFileContents.Clear If Dir$(dlgGetFilename.FileName) <> "" Then intFileNum = FreeFile Open dlgGetFilename.FileName For Input As #intFileNum While Not EOF(1) Line Input #intFileNum, strLineIn lstFileContents.AddItem strLineIn Wend Close #intFileNum End If End Sub
This is another simple piece of code. The
file name specified by the CommonDialog control's FileName property
(dlgGetFilename.FileName) is read sequentially, with each line being added to the
lstFileContents list box. Another procedure that has been used often in the functions added earlier is the FixSectionName procedure (Listing 32.8): Listing 32.8. - THe FixSectionName function, used to remove the brackets from around a section name. |
Private Function FixSectionName(sOldName As String) As String Dim strNewName As String ' Remove the [brackets] around the section name ' field. The Windows API functions add the brackets ' for you. If Left$(sOldName, 1) = "[" Then strNewName = Mid$(sOldName, 2) Else strNewName = sOldName End If If Right$(sOldName, 1) = "]" Then strNewName = Left$(strNewName, Len(strNewName) - 1) End If FixSectionName = strNewName End Function
Again, this procedure is pretty simple. The
left and right brackets are removed from the section name that is passed to the function,
and the new section name is returned by the function. This function is necessary because the API functions that write sections add the brackets automatically. If you already have the brackets around the section name, the result will be a section name with double brackets added to the INI file. Because the contents of the INI file are displayed in a ListBox control, it would be nice to make use of the situation and have a key or section name appear in the program's text box fields when it is clicked on. In order to facilitate such a feature, code needs to be added to the lstFileContents_Click event (Listing 32.9): Listing 32.9. - The lstFileContents_Click event, which transfers a key or section name to the program's text boxes when it is clicked on in the list box. |
Private Sub lstFileContents_Click() Dim intEqualPos As Integer Dim lonListPtr As Long Dim strListItem As String txtKeyName.Text = "" txtValue.Text = "" ' Get the item that was chosen from the list box. strListItem = lstFileContents.List(lstFileContents.ListIndex) ' Did the user click on a section name (enclosed in ' brackets) or a key name? If Left$(LTrim$(strListItem), 1) = "[" Then txtSectionName.Text = strListItem Else txtSectionName.Text = "" ' Separate the key info into the key name and ' its value. intEqualPos = InStr(strListItem, "=") If intEqualPos > 1 Then txtKeyName.Text = Left$(strListItem, intEqualPos - 1) txtValue.Text = Mid$(strListItem, intEqualPos + 1) End If ' Loop backwards through the list and try to<' find the section name to which the key belongs. For lonListPtr="lstFileContents.ListIndex" To 0 Step 1 strListItem="LTrim$(lstFileContents.List(lonListPtr))" If Left$(strListItem, 1)=""["" Then txtSectionName.Text="strListItem" Exit For End If Next lonListPtr End If End Sub
The first thing this procedure needs to
determine is if the user clicked on a section name or a key name. This is easy to figure
out because section names are always enclosed in brackets. If a section name is clicked on, the name of the section is placed in the txtSectionName control and the procedure ends. However, if a key name is clicked on, things are a little more complicated. The key name and it's value have to be separated, because they are listed in the INI file using the format key=value. Also, it is a good idea to determine the section in which the key is contained. This requires looping back through the INI file contents to find the first section name, which is placed in txtSectionName. The next procedures that need to be added to the program are for the two menu items (Listing 32.10): Listing 32.10. - The code for the program's menu items. |
Private Sub mnuExit_Click() ' Exit the program. Unload Me End End Sub Private Sub mnuFileOpenINIFile_Click() Dim intFileNum As Integer Dim strFileName As String ' Show the Open File dialog box dlgGetFilename.FileName = "*.ini" dlgGetFilename.Filter = "*.ini" dlgGetFilename.ShowOpen ' If a file was selected, then enable some of the ' components of the user interface. Then read in ' and display the contents of the file. strFileName = dlgGetFilename.FileName If strFileName <> "" And strFileName <> "*.ini" Then txtSectionName.Enabled = True txtKeyName.Enabled = True txtValue.Enabled = True cmdRefresh.Enabled = True ' If no file for the selected name exists, ' make one. If Dir$(strFileName) = "" Then intFileNum = FreeFile Open strFileName For Output As #intFileNum Close #1 End If ' Show the file name in the status area. lblStatus = "File " & strFileName & " opened." ReadFile End If End Sub
The mnuExit_Click routine simply ends the
program. The mnuFileOpenINIFile_Click routine uses the dlgGetFilename CommonDialog control
to determine the name and path of the INI file that is to be edited. If the file is found,
its contents are displayed using the ReadFile procedure added earlier. Because none of the API functions are valid until at least the name of a section has been entered, code needs to be added to keep the user from clicking on any of the command buttons until they have entered a section or key name. The last three procedures for the sample program (Listing 32.11) implement this safety measure: Listing 32.11. - Procedures needed to ensure that no command buttons are used until an INI file has been selected. |
Private Sub txtKeyName_Change() ' Check the status of the txtKeyName and ' txtSectionName fields to see if some command ' buttons can be enabled. ToggleCmdButtons End Sub Private Sub txtSectionName_Change() ' Check the status of the txtKeyName and ' txtSectionName fields to see if some command ' buttons can be enabled. ToggleCmdButtons End Sub Private Sub ToggleCmdButtons() ' Disable/enable certain command buttons based on ' whether or not the txtSectionName and txtKeyName ' fields are blank. If txtSectionName.Text = "" And txtKeyName.Text = "" Then
That's all there is to the sample program.
When you try it out, its probably a good idea to create a new INI file just for
fooling around with. Select the Open INI File option from the File menu and type in the
name of an INI file that doesn't already exist, such as VBU-CH32.INI. Try experimenting with the Add, Update, Retrieve, and Delete buttons. Just remember that you have to enter at least a section name before choosing any of the options. If you haven't already, make sure you save the program because it will be used in the next section for performing System Registry editing functions. |
|
![]() |
![]() |
|||