Manipular ficheros INIs
usando el API

 

Publicado el 06/Mar/99
Revisado el 14/Sep/2003


Introducción:

Pues eso... que intentando mejorar el acceso a los ficheros INIs me "entretuve" en leer la ayuda del API para 32 bits y vi un par de funciones que... al menos en teoría, sólo servían para el Windows NT... y mira tú por dónde... también sirven para el Windows 98... no las he probado para el Windows 95, así que si lo haces y funciona, me lo cuentas... ¿vale? Gracias.

El código:

El código que te voy a mostrar ahora tiene dos funciones que ya habrás visto en algún otro sitio de mis páginas, son las funciones para leer y escribir en ficheros INIs; pero ahora te voy a dar otras tres que de seguro te interesarán:
Borrar claves o secciones de un fichero INI.
Leer todos las claves y valores de una sección.
Leer todas las secciones.

Decirte que de esta última, no viene la declaración del API en el fichero que se incluye con el VB, así que toma nota, porque es interesante.

Las declaraciones de las funciones del API

'
'--- Declaraciones para leer ficheros INI ---
'
' Leer todas las secciones de un fichero INI, esto seguramente no funciona en Win95
' *** Esta función no estaba en las declaraciones del API que se incluye con el VB ***
Private Declare Function GetPrivateProfileSectionNames Lib "kernel32" Alias "GetPrivateProfileSectionNamesA" _
    (ByVal lpszReturnBuffer As String, ByVal nSize As Long, _
    ByVal lpFileName As String) As Long
    
' Leer una sección completa
Private 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

' Leer una clave de un fichero INI
Private Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" _
    (ByVal lpApplicationName As String, ByVal lpKeyName As Any, _
     ByVal lpDefault As String, ByVal lpReturnedString As String, _
     ByVal nSize As Long, ByVal lpFileName As String) As Long

' Escribir una clave de un fichero INI (también para borrar claves y secciones)
Private 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

Ahora las funciones y después vendrá un ejemplo de cómo usarlas.

'
Private Function IniGet(ByVal lpFileName As String, ByVal lpAppName As String, _
                       ByVal lpKeyName As String, _
                       Optional ByVal lpDefault As String = "") As String
    '
    'Los parámetros son:
    'lpFileName:    La Aplicación (fichero INI)
    'lpAppName:     La sección que suele estar entrre corchetes
    'lpKeyName:     Clave
    'lpDefault:     Valor opcional que devolverá si no se encuentra la clave.
    '
    Dim LTmp As Long
    Dim sRetVal As String
    
    sRetVal = String$(255, 0)
    
    LTmp = GetPrivateProfileString(lpAppName, lpKeyName, lpDefault, sRetVal, Len(sRetVal), lpFileName)
    If LTmp = 0 Then
        IniGet = lpDefault
    Else
        IniGet = Left(sRetVal, LTmp)
    End If
End Function


Private Sub IniWrite(ByVal lpFileName As String, ByVal lpAppName As String, _
                    ByVal lpKeyName As String, ByVal lpString As String)
    '
    'Guarda los datos de configuración
    'Los parámetros son los mismos que en IniGet
    'Siendo lpString el valor a guardar
    '

    Call WritePrivateProfileString(lpAppName, lpKeyName, lpString, lpFileName)
End Sub


Private Sub IniDelete(ByVal sIniFile As String, ByVal sSection As String, _
                    Optional ByVal sKey As String = "")
    '
    ' Borrar una clave o entrada de un fichero INI                      (16/Feb/99)
    ' Si no se indica sKey, se borrará la sección indicada en sSection
    ' En otro caso, se supone que es la entrada (clave) lo que se quiere borrar
    '
    If Len(sKey) = 0 Then
        ' Borrar una sección
        Call WritePrivateProfileString(sSection, 0&, 0&, sIniFile)
    Else
        ' Borrar una entrada
        Call WritePrivateProfileString(sSection, sKey, 0&, sIniFile)
    End If
End Sub


Private Function IniGetSection(ByVal lpFileName As String, _
                              ByVal lpAppName As String) As Variant
    '
    ' Lee una sección entera de un fichero INI                          (27/Feb/99)
    '
    ' Usando Collection en lugar de cParrafos y cContenido              (06/Mar/99)
    '
    ' Esta función devolverá una colección con cada una de las claves y valores
    ' que haya en esa sección.
    ' Parámetros de entrada:
    '   lpFileName  Nombre del fichero INI
    '   lpAppName   Nombre de la sección a leer
    ' Devuelve:
    '   Una colección con el Valor y el contenido
    '   Para leer los datos:
    '       For i = 1 To tContenidos Step 2
    '           sClave = tContenidos(i)
    '           sValor = tContenidos(i+1)
    '       Next
    '
    Dim tContenidos As Collection
    Dim nSize As Long
    Dim i As Long
    Dim j As Long
    Dim sTmp As String
    Dim sClave As String
    Dim sValor As String
    
    
    ' El tamaño máximo para Windows 95
    sBuffer = String$(32767, Chr$(0))
    
    nSize = GetPrivateProfileSection(lpAppName, sBuffer, Len(sBuffer), lpFileName)
        
    If nSize Then
        Set tContenidos = New Collection
        
        ' Cortar la cadena al número de caracteres devueltos
        sBuffer = Left$(sBuffer, nSize)
        ' Quitar los vbNullChar extras del final
        i = InStr(sBuffer, vbNullChar & vbNullChar)
        If i Then
            sBuffer = Left$(sBuffer, i - 1)
        End If
        
        ' Cada una de las entradas estará separada por un Chr$(0)
        Do
            i = InStr(sBuffer, Chr$(0))
            If i Then
                sTmp = LTrim$(Left$(sBuffer, i - 1))
                If Len(sTmp) Then
                    ' Comprobar si tiene el signo igual
                    j = InStr(sTmp, "=")
                    If j Then
                        sClave = Left$(sTmp, j - 1)
                        sValor = LTrim$(Mid$(sTmp, j + 1))
                        ' Asignar la clave y el valor
                        tContenidos.Add sClave
                        tContenidos.Add sValor
                    End If
                End If
                sBuffer = Mid$(sBuffer, i + 1)
            End If
        Loop While i
        ' Por si aún queda algo...
        If Len(sBuffer) Then
            j = InStr(sBuffer, "=")
            If j Then
                sClave = Left$(sBuffer, j - 1)
                sValor = LTrim$(Mid$(sBuffer, j + 1))
                tContenidos.Add sClave
                tContenidos.Add sValor
            End If
        End If
    End If
    Set IniGetSection = tContenidos
End Function


Private Function IniGetSections(ByVal lpFileName As String) As Variant
    '
    ' Devuelve todas las secciones de un fichero INI                    (27/Feb/99)
    '
    ' Usando Collection en lugar de cParrafos y cContenido
    '
    ' Esta función devolverá una colección con todas las secciones del fichero
    ' Parámetros de entrada:
    '   lpFileName  Nombre del fichero INI
    ' Devuelve:
    '   Una colección con los nombres de las secciones
    '
    Dim tContenidos As Collection
    Dim nSize As Long
    Dim i As Long
    Dim sTmp As String
    
    ' El tamaño máximo para Windows 95
    sBuffer = String$(32767, Chr$(0))
    
    ' Esta función del API no está definida en el fichero TXT
    nSize = GetPrivateProfileSectionNames(sBuffer, Len(sBuffer), lpFileName)
        
    If nSize Then
        ' Crear una colección del tipo cParrafos que es una colección
        ' con elementos del tipo cContenido
        Set tContenidos = New Collection
        
        ' Cortar la cadena al número de caracteres devueltos
        sBuffer = Left$(sBuffer, nSize)
        ' Quitar los vbNullChar extras del final
        i = InStr(sBuffer, vbNullChar & vbNullChar)
        If i Then
            sBuffer = Left$(sBuffer, i - 1)
        End If
        
        ' Cada una de las entradas estará separada por un Chr$(0)
        Do
            i = InStr(sBuffer, Chr$(0))
            If i Then
                sTmp = LTrim$(Left$(sBuffer, i - 1))
                If Len(sTmp) Then
                    tContenidos.Add sTmp
                End If
                sBuffer = Mid$(sBuffer, i + 1)
            End If
        Loop While i
        If Len(sBuffer) Then
            tContenidos.Add sBuffer
        End If
    End If
    Set IniGetSections = tContenidos
End Function

Bueno... eso es todo lo que se necesita para usar esas funciones, en este caso, si te fijas, las funciones son Private, ya que las he "modificado" para usar en un Form directamente, pero si las quieres "encapsular" en una clase o en un módulo BAS, deberías cambiar las declaraciones a Public, pero no las de las funciones del API... esas pueden (y deberían) seguir siendo Privadas.

Del código para usar estas funciones sólo te voy a enseñar parte... el resto te lo imaginas... que con un poco de imaginación seguro que eres capaz de crear el ejemplo para que funcione... je, je... no es mala "leche", es que así te esfuerzas un poco... que os estoy acostumbrando a darlo todo hecho y eso no ayuda demasiado a aprender...

 

Aquí están los trozos del Form y una imagen de cómo queda en modo de diseño.

inis.gif (6192 bytes)
El form de prueba

'
' Leer todas las secciones del fichero indicado y guardarlas en el cboSecciones
Private Sub LeerSecciones()
    Dim tContenidos As Collection
    Dim i As Long
    
    ' Llenar las secciones de este fichero
    Set tContenidos = IniGetSections(txtFicIni)
    If Not tContenidos Is Nothing Then
        cboSecciones.Clear
        For i = 1 To tContenidos.Count
            cboSecciones.AddItem tContenidos(i)
        Next
        cboSecciones.ListIndex = 0
        txtValor = ""
    End If
End Sub


' Leer las claves de la sección seleccionada
Private Sub cboSecciones_Click()
    ' Mostrar las claves de esta sección
    Dim tContenidos As Collection
    Dim i As Long
    
    Set tContenidos = IniGetSection(txtFicIni, cboSecciones.Text)
    If Not tContenidos Is Nothing Then
        cboClaves.Clear
        For i = 1 To tContenidos.Count Step 2
            cboClaves.AddItem tContenidos(i)
        Next
        cboClaves.ListIndex = 0
        txtValor = ""
    End If
End Sub


Private Sub cmdBorrar_Click(Index As Integer)
    ' Borrar sección o clave
    Dim sFicINI As String
    Dim sSeccion As String
    Dim sClave As String
    
    sFicINI = Trim$(txtFicIni)
    sSeccion = Trim$(cboSecciones.Text)
    sClave = Trim$(cboClaves.Text)
    
    If Index = 0 Then
        ' Borrar sección
        IniDelete sFicINI, sSeccion
        ' Releer las secciones disponibles
        LeerSecciones
    Else
        ' Borrar clave
        IniDelete sFicINI, sSeccion, sClave
        ' Leer las claves de esta sección
        cboSecciones_Click
    End If
End Sub


Private Sub cmdLeer_Click()
    ' Leer del fichero INI
    Dim sFicINI As String
    Dim sSeccion As String
    Dim sClave As String
    Dim sValor As String
    
    sFicINI = Trim$(txtFicIni)
    sSeccion = Trim$(cboSecciones)
    sClave = Trim$(cboClaves.Text)
    sValor = Trim$(txtValor)
    
    txtValor = IniGet(sFicINI, sSeccion, sClave, sValor)
    
End Sub


Private Sub cmdAdd_Click()
    ' Añadir la sección, clave y/o valor
    Dim sFicINI As String
    Dim sSeccion As String
    Dim sClave As String
    Dim sValor As String
    
    sFicINI = Trim$(txtFicIni)
    sSeccion = Trim$(cboSecciones)
    sClave = Trim$(cboClaves.Text)
    sValor = Trim$(txtValor)
    
    IniWrite sFicINI, sSeccion, sClave, sValor
    
End Sub

Pues esto es todo... que no es poco... a disfrutar y... a completar el programilla de ejemplo.
Aunque todo sea dicho... te he dejado poco que hacer... pero...

Nos vemos.
Guillermo

Nota del 14/Sep/2003:

El código aquí mostrado sirve igualmente para VB5 como para VB6, pero en VB6 se podría cambiar el tipo de datos devuelto por las funciones IniGetSection e IniGetSections, para que en lugar de devolver un valor de tipo Variant, devuelva un array de tipo String. En el código que usa el Array de tipo String no existe la función IniDelete, sino que hay dos funciones, una para borrar una clave: IniDeleteKey y otra para borrar una sección: IniDeleteSection.

En estos dos ZIPs tienes los dos ejemplos, uno usando Variant y otro usando un Array del tipo String:
Usando Variant: INIVariant.zip 9.62 KB
Usando Array de String: INIArray.zip 13.7 KB
 


Volver a Mis Utilidades

la Luna del Guille o... el Guille que está en la Luna... tanto monta...