Статьи

Грамотно работаем с реестром

Часть 2. Работа с ini-файлами.

Как говорилось выше, ini-файлы – это наследие прошлого. Хорошо это или плохо? Однозначного ответа нет. Существует много сторонников ini-файлов, и их основным аргументом является доступность и легкость в редактировании. Что такое, по сути, ini-файл? Это текстовый файл, разбитый внутри на секции. Заголовок каждой секции заключен в квадратные скобки. Каждая секция состоит из строк, представляющих собой название параметра (ключ) и через равно (=) – его значение. Все элементарно просто и понятно для восприятия. Однако это же самое является и отрицательным моментом. Учитывая, что нынешний Windows занимает порядка 150-300 мегабайт, имеет массу встроенных программ и каждой из них необходим свой собственный ini-файл. А, кроме того, мы инсталлируем у себя, как минимум, Офис. А как максимум еще 3-4 десятка программ. Представляете в какую "выгребную яму" превратится директория, хранящая ini-файлы? Кроме того, из-за своей простоты, ini-файлы не могут предоставить иерархическую структуру вложенности, то, что так легко удается реестру. И в заключение: ini-файл – это отдельный файл, т.е. принципиально он может храниться в любом месте, а не только Windows\System. Насколько усложнится поиск необходимого файла, из-за кажущейся "простоты редактирования".

Однако, несмотря на все минусы ini-файлы продолжают жить. Не так вольготно, как в Windows 3x, но все же. По-прежнему сохраняются 2 основных файла, несущих информацию о самом Windows (win.ini, system.ini). Поэтому давайте разберемся, как все-таки с ними надо работать.

Встроенных VB-функций для работы с ini-файлами нет, однако существуют API-функции. Излагаемый ниже материал полностью приведен в Листинге. Его можно просто скопировать и оформить как отдельный модуль или класс, который подключается по мере надобности.

Private Declare Function GetPrivateProfileInt Lib "kernel32" _
  Alias "GetPrivateProfileIntA" _
  (ByVal strSection As String, _
    ByVal strKeyName As String, _
    ByVal lngDefault As Long, _
    ByVal strFileName As String) _
As Long

 

Private Declare Function GetPrivateProfileString Lib "kernel32" _
  Alias "GetPrivateProfileStringA" _
  (ByVal strSection As String, _
    ByVal strKeyName As String, _
    ByVal strDefault As String, _
    ByVal strReturned As String, _
    ByVal lngSize As Long, _
    ByVal strFileName As String) _
As Long

Private Declare Function WritePrivateProfileString Lib "kernel32" _
  Alias "WritePrivateProfileStringA" _
  (ByVal strSection As String, _
    ByVal strKeyNam As String, _
    ByVal strValue As String, _
    ByVal strFileName As String) _
As Long

Приведенные здесь три основные функции служат для работы с ini-файлами 2 на запись (для строкового и целочисленного параметров) и одна на чтение.

Кроме того, существует еще три API-функции (по тому же принципу), но работающие ТОЛЬКО с одним файлом WIN.INI

Private Declare Function GetProfileInt Lib "kernel32" _
  Alias "GetProfileIntA" _
  (ByVal strSection As String, _
    ByVal strKeyName As String, _
    ByVal lngDefault As Long) _
As Integer

Private Declare Function GetProfileString Lib "kernel32" _
  Alias "GetProfileStringA" _
  (ByVal strSection As String, _
    ByVal strKeyName As String, _
    ByVal strDefault As String, _
    ByVal strReturned As String, _
    ByVal intSize As Long) _
As Long

Private Declare Function WriteProfileString Lib "kernel32" _
  Alias "WriteProfileStringA" _
  (ByVal strSection As String, _
    ByVal strKeyName As String, _
    ByVal strValue As String) _
As Integer

Нетрудно заметить, что последние три функции, практически полностью повторяют первые, за исключением одного параметра – путь файла. Однако, благодаря этому, скорость их работы значительно выше.

Внутренняя структура представленных API-функций достаточно проста, и, в принципе их можно использовать "напрямую" в своих приложениях. Однако я рекомендую все же сделать функции-"обертки", так как API-функции не поддерживают обработку ошибок, и лучше это сделать самому, не дожидаясь, когда Ваша программа "скоропостижно" закончит работу.

Public Function GetValueInteger(strSection As String, _
  strKey As String, strFile As String) As Integer

Dim intValue As Integer

On Error GoTo PROC_ERR

  intValue = GetPrivateProfileInt(strSection, strKey, 0, strFile)

  GetValueInteger = intValue

 

PROC_EXIT:

  Exit Function

PROC_ERR:

  MsgBox "Ошибка: <" & Err.Number & "> - " & Err.Description, _
    vbExclamation + vbOKOnly, "GetValueInteger"

  Resume PROC_EXIT

End Function

Данная функция возвращает целочисленное значение из ini-файла. Где имя секции – strSection, имя ключа – strKey и strFile – полный путь к ini-файлу.

Public Function GetValueString(strSection As String, _
  strKey As String, strFile As String) As String

Dim strBuffer As String * 256

Dim intSize As Integer

On Error GoTo PROC_ERR

  intSize = GetPrivateProfileString(strSection, strKey, "", _
    strBuffer, 256, strFile)

  GetValueString = Left$(strBuffer, intSize)

 

PROC_EXIT:

  Exit Function

PROC_ERR:

  MsgBox "Ошибка: <" & Err.Number & "> - " & Err.Description, _
    vbExclamation + vbOKOnly, "GetValueString"

  Resume PROC_EXIT

End Function

Данная функция возвращает строковое значение из ini-файла. Где имя секции – strSection, имя ключа – strKey и strFile – полный путь к ini-файлу. Обратите внимание, что вначале резервируется пустая строка, а из результата функции выкидываются пустоты.

Public Function SetValue(strSection As String, strKey As String, _
  strValue As String, strFile As String) As Integer

Dim intStatus As Integer

On Error GoTo PROC_ERR

  intStatus = WritePrivateProfileString(strSection, strKey, _
    strValue, strFile)

  SetValue = (intStatus <> 0)

 

PROC_EXIT:

  Exit Function

PROC_ERR:

  MsgBox "Ошибка: <" & Err.Number & "> - " & Err.Description, _
    vbExclamation + vbOKOnly, "SetValue"

  Resume PROC_EXIT

End Function

Данная функция записывает в файл значение strValue и возвращает целочисленное значение: True, если запись произведена и False, в случае ошибки записи. Имя секции – strSection, имя ключа – strKey и strFile – полный путь к ini-файлу.

Как уже говорилось выше, работа с файлом WIN.INI строится аналогичным образом. Поэтому повторяться здесь не буду.

До этого момента все было легко и просто. Однако встречаются ситуации, когда нам необходимо считать все значения в конкретной секции. И данные функции нам не помогут. Оказывается, существует еще одна API-функция, которая нам в этом поможет:

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

Для нее так же напишем функцию-"обертку".

Public Function GetSection(strSection As String, strFile As String)

Dim strBuffer As String * 512

Dim intSize As Integer

Dim strTemp As String

Dim intTemp As Integer

Dim Index As Integer

Dim arrSection() As String

Dim key As String, value As String, str As String

On Error GoTo PROC_ERR

  intSize = GetPrivateProfileSection(strSection, strBuffer, 512, strFile)

  strTemp = Left$(strBuffer, intSize)

 

  Do Until Len(strTemp) = 0

    intTemp = InStr(1, strTemp, Chr(0))

    ReDim Preserve arrSection(1, Index) As String

    str = Mid(strTemp, 1, intTemp)

    key = Mid(str, 1, InStr(1, str, "=") - 1)

    value = Mid(str, InStr(1, str, "=") + 1)

    arrSection(0, Index) = key

    arrSection(1, Index) = value

    Index = Index + 1

    strTemp = Mid(strTemp, intTemp + 1, Len(strTemp))

  Loop

  GetSection = arrSection

 

PROC_EXIT:

  Exit Function

PROC_ERR:

  MsgBox "Ошибка: <" & Err.Number & "> - " & Err.Description, _
    vbExclamation + vbOKOnly, "GetValueString"

  Resume PROC_EXIT

End Function

Данная функция возвращает двумерный массив значений конкретной секции. Вначале, с помощью API-функции в буферизованную строку (strBuffer) считывается значение всей секции и определяется количество знаков (intSize). Далее, обрезаем строку от пустот и передаем это значение переменной strTemp. Затем в цикле Do-Loop считываем значение каждой строки (они разделены символом Chr(0)) и, предварительно разделив их на имя ключа и его значение, сбрасываем в двумерный массив. Первый параметр в массиве – будет означать, что мы считываем: имя ключа (0) или его значение (1).

Давайте сделаем маленький пример, чтобы стало понятнее, как работает наша функция. В качестве примера возьмем всем известную игру "Минер". Расположите на форме кнопку и список. При нажатии на кнопку в список последовательно передаются значения из секции [Сапер].

Private Sub Command1_Click()

Dim i As Integer, arrList As Variant

  List1.Clear

  arrList = GetSection("Сапер", "C:\Windows\winmine.ini")

  For i = 0 To UBound(arrList, 2)

    List1.AddItem arrList(1, i)

  Next

End Sub

Обратите внимание, что если мы запишем arrList(0, i), то будем передавать уже не значения, а имена ключей.

Думаю на этом раздел, посвященный ini-файлам, можно закончить.

2001 г.

К статьям Часть 1 Листинг Часть 3
Hosted by uCoz