Visual Basic 6.0 中級講座
VB6対応

 

Visual Basic 中学校 > VB6 中級講座 >

8.ini

 

今回はiniの話です。iniはアプリケーションの設定やちょっとした情報を保存するのに便利なものです。通常は一度アプリケーションを終了させると記憶させておいたデータはファイルに保存しない限り消えてしまうのですが、iniに保存しておけば大丈夫です(iniもファイルですけど・・・)。iniは「イニ」と読む人が 多いようです。本当は「Initialize」(イニシャライズ:初期化)の略なので「初期化ファイル」と呼ぶ人もいます。

概要

・iniファイルを使えば、設定を保存しておくことができる。

・iniファイルを読み書きするにはAPIを使う。


1.はじめに

 

具体的な説明に入る前に知っておいた方がいいことがあります。Microsoft社(マイクロソフト社)はアプリケーションがその設定や情報を保存するなどの目的でINIを使用することを推奨していません。Microsoft社によるとそのような目的には「レジストリ」を使うようにとのことです。この意図からVBにはレジストリを操作するメソッドはあってもiniを操作するメソッドは無いのです。

念のために説明しておくと、レジストリ とはWindowsやその他のアプリケーションの情報を一括管理している巨大なデータベースのことです。このデータベースの中を見るには、「スタート」ボタンから「ファイル名を指定して実行」で「Regedit」と入力してください。ただし、レジストリの中をよくわからない人がいじるとWindowsが起動しなくなったりしますので要注意です 。

マイクロソフトがレジストリを推奨しているとは言え、iniはレジストリよりも手軽に使えて便利なので現在でも多くのアプリケーションがiniを使用しています。なんといってもiniは単なるテキストファイルの一形式ですので「持ち運びに便利」、「編集しやすい」、「わかりやすい」などの 利点が挙げられます。

 

2.iniの仕様

 

iniのプログラムを始める前にiniとはどういうものなのかもう少し詳しくに見ていきましょう。

iniの実体はテキストファイルです。だからINIを作るにはテキストファイルを作れば良いわけです。さらにiniには決まった構造があります。次の例を見てください。

[Data]

USERNAME = VBSchool
LANGUAGE = Visual Basic

[Window]

TOP    = 0
LEFT   = 0
WIDTH  = 400
HEIGHT = 200

■iniの構造

この中で [ ]で囲まれているのは「セクション」と呼ばれるものです。 = で結ばれているものの左側は「キー」、右側は「(キーの)値」と呼ばれます。それから、この例には登場しませんが行頭に ; をつけるとその行全体コメントとなります。

「キー」や「値」などの呼び方はいろいろ違う場合もあるようですが構造はこれだけなので難しくありません。

具体例を挙げると上の例ではDataとWindowの2つのセクションがあるわけです。セクションは自分で勝手に作って構いません。DataセクションにはUSERNAMEとLANGUAGEの2つのキーがあり、USERNAMEキーの値はVBSchoolです。キーも自分で作って構いません。構造さ えちゃんとなっていれば後は自由ということです。

あとはプログラムからこのiniにアクセスして値を読んだり書いたりできれば良いわけです。 必要があればもちろんメモ帳で開くなどして人間が直接値を編集することもできます。

 

3.値を読む

 

では、いよいよiniファイルをプログラムから読み込む例を作ってみましょう。まずは上の例と同じiniIを作ってください。作り方は上の例をテキストファイルにコピーするだけです。テキストファイルの名前は vbschool.ini としておきましょう。

プログラムにコマンドボタンを一つ貼り付けて次のように記述してください。

VB6対応

'A

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

Private Sub Command1_Click()

    MsgBox "@" & GetINIValue("USERNAME", "Data", App.Path & "\vbschool.ini") & "@" 'B

End Sub

Public Function GetINIValue(KEY As String, Section As String, ININame As String) As String

    Dim Value As String * 255
    Call
GetPrivateProfileString(Section, KEY, "ERROR", Value, Len(Value), ININame) 'C
    GetINIValue = Left$(Value, InStr(1, Value, vbNullChar) - 1) 'D

End Function

■リスト1:iniファイルの読み込み

できたら、プログラムを保存してください。そして、プログラムと同じ場所(フォルダ)に vbschool.ini をおいてください。

よければプログラムを開始させてコマンドボタンを押してみましょう。DataセクションのUSERNAMEキーの値を見事に取得したことでしょう。

それでは解説しましょう。Bの部分はiniファイルのどこを読むか指定している部分です。iniファイルの中から読み込む場所を指定するには先ほど説明したセクション名とキー名を使用します。この例ではDataセクションのUSERNAMEキーを指定しています。

たとえばこの部分をGetINIValue("LANGUAGE", "Data", App.Path & "\vbschool.ini") のようにすれば、今度は DataセクションのLANGUAGEキーの値を読むことができるわけです。すばらしく簡単ですね。

iniファイルの読み込みにはAの部分で定義しているGetPrivateProfileString関数を使用しますが、扱いやすくするために自作のGetINIValue関数を用意しています。この関数では引数は順番にキーの名前、セクション名、INIファイルのフルパス を指定するとキーの値を返すようにプログラムされています。

この関数は引数をほとんどそのままAPI関数であるGetProvateProfileString関数に渡しているだけでがいくつかの処理を追加してあります。まず、GetPrivateProfileString関数を呼び出すときに第4引数 として値を受け取る変数を指定しています。この変数はあらかじめ領域を確保しておく必要があるので今回は固定長で宣言しています。

上記の例ではとりあえず255文字分の領域を確保していますが、この「255」には特に根拠はありません。このくらい確保すれば大丈夫かなといった程度のものです。また、可変長で宣言してスペースかなにかをセットして領域を確保しておくという手法もあります。

第3引数はエラー時に第4引数に格納される文字列です。ここでいうエラー時とは指定されたセクションやキーが存在しない場合などを指します。

関数の呼出し後キーの値は第4引数にセットされるわけですが、例によって255文字に満たなかった部分はNULLで満たされるのでNULLを除去する必要があります。それがDの部分です。今回はInStr関数で最初のNULLを探し出して、そこから左にある部分を切り抜くようにしてみました。

VB6であれば、Dの部分は GetINIValue = Replace(Value, vbNullChar, "") と書いてもOKです。

 

4.値を書く

 

値を読むだけだけでもiniの使い道はありますが、やはり値を書き込むことができれば使い道はぐんと広がります。

今度は値を書くプログラムです。2つ目のコマンドボタンを配置して次のようにプログラムを書き足してください。色がついている部分が書き足す部分です。

VB6対応

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
'E
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
Private Sub Command1_Click()

    MsgBox "@" & GetINIValue("USERNAME", "Data", App.Path & "\vbschool.ini") & "@"

End Sub
Private Sub Command2_Click()

    MsgBox SetINIValue("HELLO", "USERNAME", "Data", App.Path & "\vbschool.ini")
'F

End Sub
Public Function GetINIValue(KEY As String, Section As String, ININame As String) As String

    Dim Value As String * 255

    Call GetPrivateProfileString(Section, KEY, "ERROR", Value, Len(Value), ININame)
    GetINIValue = Left$(Value, InStr(1, Value, vbNullChar) - 1)

End Function
Public Function SetINIValue(Value As String, KEY As String, Section As String, ININame As String) As Boolean

    Dim Ret As Long

    Ret = WritePrivateProfileString(Section, KEY, Value, ININame)
'G
    SetINIValue = CBool(Ret)
'H

End Function

■リスト2:iniファイルへの書き込みとiniファイルの読み込み

今度も構造はさっきと一緒ですね。実行して2つ目のコマンドボタンをクリックするとTrueと表示されるはずです。 Falseと表示される場合はなにかエラーが発生した場合です。成功した場合はvbschool.iniのDataセクションのUSERNAMEがHELLOに変わっているので確認してみてください。

この例はWritePrivateProfileStringという関数を使っているだけ なので見ただけでわかると思いますがHの部分は少しだけ見慣れない形かもしれませんので説明しておきましょう。この部分はAPI関数の処理が成功したか失敗したかをTrueまたはFalseで返しています。WritePrivateProfileString関数もGetPrivateProfileString関数も失敗時には 0 、成功時には 0以外の値を返します。VBのCBool関数は0をFalse, 0以外をTrueに変換するのでこの2つの関数からの戻り値をCBool関数を通して成功、失敗を表すTrue,False を返せるわけです。

発展学習

発展学習では意欲的な方のために現段階では特に理解する必要はない項目を解説します。

  以上の例ではiniファイルを読み書きすることはできるのですが、iniファイルを読み書きするための関数(GetIniValue, SetIniValue)の引数が多いし長くなってスマートではありません。
  本文中では、iniファイルの読み書きに焦点をしぼっているためこの点は気にしていませんが実際には気になるものです。そこでiniを読み書きする関数の引数を少なく短くするテクニックを紹介します。

  • ini名を省略可能にして既定値を設定するとININame引数を指定する必要がなくなります。
  • iniファイルを読み書きする関数をクラスとして実装するとiniファイル名やセクション名をプロパティにできるので関数を読み出すときにいちいち指定する必要がなくなります。
  • 上記の場合、さらにiniファイルを読み書きする関数をメソッドではなく既定プロパティとして実装するとiniファイルへのアクセスが格段と楽になります。

プロパティとしての実装例

Public Property Get Item(Key As String) As String

    Dim Value As String * 255

    Call GetPrivateProfileString(Section, Key, "ERROR", Value, Len(Value), ININame)
    Item = Left$(Value, InStr(1, Value, vbNullChar) - 1)   

End Property

既定プロパティとして実装した場合にINIにアクセスする例

'読み込む例

MsgBox INI("UserName")

'書き込む例

INI("UserName") = "Yamada"

(上記はあくまで部分的な一例です。この部分のみをコピー&貼り付けしても動作しません。)

 

 

5.キーを作る

 

読み書きだけできればとりあえずの用はたりるのですが、キーの作り方も解説しておきます。といってもこれもかんたんで書き込む例と一緒です。

書き込む時の例では G 部分で書き込み処理を行っていましたね?

もういちど、Gの部分だけ下に書きます。

Ret = WritePrivateProfileString(Section, KEY, Value, ININame) 'G

このWritePrivateProfileString関数のカッコの中は左から順に、セクション名、キー名、書き込む値、iniのファイル名となっています。このときにもし、存在しないセクションやキーに値を書き込もうとしたらどうなるでしょうか?

エラーになりそうな気もしますが、実は存在しないセクションやキーを指定すると、そのセクションやキーは自動的に作成されるのです。ですから、新しいセクションやキーを作るのも簡単というわけですね。

ただ、存在しないiniファイルを指定した場合は、そのファイルは作成されないので注意してください。

 

6.応用事例:位置復元プログラム

 

それでは、iniの知識を応用してあなたのプログラムに簡単な機能を追加してみましょう。プログラムを開始すると前回終了した位置と同じ位置にWindow(ウィンドウ)を表示する機能を作ります。

まずは、いままでの説明に出てきた2つの関数、GetINIValueSetINIValueをプログラムにコピーして貼り付けてください。この作業で次のような状態になっているはずです。コメントは私が新たに追加したものです 。

VB6対応

Option Explicit

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
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
'■GetINIValue
'■機能:INIから値を取得する。

Public Function GetINIValue(KEY As String, Section As String, ININame As String) As String

    Dim Value As String * 255

    Call GetPrivateProfileString(Section, KEY, "ERROR", Value, Len(Value), ININame)
    GetINIValue = Left$(Value, InStr(1, Value, vbNullChar) - 1)

End Function
'■SetINIValue
'■機能:INIに値を設定する。
'■備考:指定されたセクションやキーが存在しない場合は新たに作成される。

Public Function SetINIValue(Value As String, KEY As String, Section As String, ININame As String) As Boolean

    Dim Ret As Long

    Ret = WritePrivateProfileString(Section, KEY, Value, ININame)
    SetINIValue = CBool(Ret)

End Function

■リスト3:iniファイルへの読み書き用の関数を用意した状態

次に記録するiniの名前を設定します。ここでは ReWindow.ini という名前にします。この部分はフォームの宣言セクションに次のように書きます。

Private Const INI_REWINDOW As String = "ReWindow.ini"

Constは定数を定義するキーワードで以後プログラムの中で INI_REWINDOW と記述すると "ReWindow.ini" と置き換えて解釈されます。定数を使うメリットはあとでiniの名前を変更したくなった時にこの部分を変えるだけですむことと打ち間違えによるエラーがなくなることです。ときどきプログラムの中に直接固定されたファイル名や数字を書き込む人がいますがそのようにすると訂正する時に大変ですし 思わぬエラーの原因になります。

ここまで完成したら、次はiniに値を書き込む処理を記述します。具体的な記述に入る前にiniの構造を決めておきましょう。今回はフォームの座標を記録するのですから、フォームのLeftプロパティ、Topプロパティ、Widthプロパティ、Heightプロパティの4つを記録できれば良いわけです。そこでiniの構造は次のようにします。

[Location]

LEFT   = 0
TOP    = 0
WIDTH  = 2000
HEIGHT = 2000   
                                   

■ReWindow.iniの構造

今は仮に0とか2000とかの初期値を設定してあります。みなさんはプログラムを一旦セーブして、プログラムと同じフォルダにこのiniを作っておいてください。名前はもちろん「ReWindow.ini」です。

では、具体的な記述に入ります。今回はプログラムが終了した時、つまりウィンドウが閉じたタイミングでその時のウィンドウの座標をiniに記録すればよいのですからフォームのUnloadイベントに記述します。

VB6対応

Private Sub Form_Unload(Cancel As Integer)

    '●INIに現在の座標を書き込む
    SetINIValue Left, "LEFT", "LOCATION", App.Path & "\" & INI_REWINDOW
    SetINIValue Top, "TOP", "LOCATION", App.Path & "\" & INI_REWINDOW
    SetINIValue Width, "WIDTH", "LOCATION", App.Path & "\" & INI_REWINDOW
    SetINIValue Height, "HEIGHT", "LOCATION", App.Path & "\" & INI_REWINDOW

End Sub

■リスト4:フォームを閉じるときにフォームの位置と大きさをiniに記録する。

第4引数のiniの名前を指定する個所は INI_REWINDOWではなく、 App.Path & "\" & INI_REWINDOW となります。この部分を単にINI_REWINDOWと記述するとiniのフルパスではなくファイル名だけを指定していることになり、このような指定の仕方をするとWritePrivateProfileString関数 はWindowsフォルダの中から該当のiniファイルを探そうとしてしまいます。

ですから通常はここにはフルパスを指定することになるでしょう。その時にApp.Pathを使用するとプログラムと同じフォルダのフルパスを簡単に取得できるので便利です。

ここまで終われば後は簡単。最後はフォームのLoadイベントにiniの値を読み込んでプロパティにセットするコードを記述すれば完成です。この部分は次のようになります。

VB6対応

Private Sub Form_Load()

    '●INIから座標を読み込んでセットする。
    Left = GetINIValue("LEFT", "LOCATION", App.Path & "\" & INI_REWINDOW)
    Top = GetINIValue("TOP", "LOCATION", App.Path & "\" & INI_REWINDOW)
    Width = GetINIValue("WIDTH", "LOCATION", App.Path & "\" & INI_REWINDOW)
    Height = GetINIValue("HEIGHT", "LOCATION", App.Path & "\" & INI_REWINDOW)
   
End Sub

■リスト5:フォームを開いたときにフォームの位置と大きさをiniから読み込んでセットする。

完成したら試してみてください。フォームを移動させたり大きさを変えたりしてプログラムを終了します。もう一度開始すると最後に指定された位置と大きさでウィンドウが表示されるでしょう?

念のために完成版の全コードを下に示しておきます。

VB6対応

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
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

Private Const INI_REWINDOW As String = "ReWindow.ini"
'■GetINIValue
'■機能:INIから値を取得する。

Public Function GetINIValue(KEY As String, Section As String, ININame As String) As String

    Dim Value As String * 255

    Call GetPrivateProfileString(Section, KEY, "ERROR", Value, Len(Value), ININame)
    GetINIValue = Left$(Value, InStr(1, Value, vbNullChar) - 1)

End Function
'■SetINIValue
'■機能:INIに値を設定する。
'■備考:指定されたセクションやキーが存在しない場合は新たに作成される。

Public Function SetINIValue(Value As String, KEY As String, Section As String, ININame As String) As Boolean

    Dim Ret As Long

    Ret = WritePrivateProfileString(Section, KEY, Value, ININame)
    SetINIValue = CBool(Ret)

End Function
Private Sub Form_Load()

    '●INIから座標を読み込んでセットする。
    Left = GetINIValue("LEFT", "LOCATION", App.Path & "\" & INI_REWINDOW)
    Top = GetINIValue("TOP", "LOCATION", App.Path & "\" & INI_REWINDOW)
    Width = GetINIValue("WIDTH", "LOCATION", App.Path & "\" & INI_REWINDOW)
    Height = GetINIValue("HEIGHT", "LOCATION", App.Path & "\" & INI_REWINDOW)
   
End Sub
Private Sub Form_Unload(Cancel As Integer)

    '●INIに現在の座標を書き込む
    SetINIValue Left, "LEFT", "LOCATION", App.Path & "\" & INI_REWINDOW
    SetINIValue Top, "TOP", "LOCATION", App.Path & "\" & INI_REWINDOW
    SetINIValue Width, "WIDTH", "LOCATION", App.Path & "\" & INI_REWINDOW
    SetINIValue Height, "HEIGHT", "LOCATION", App.Path & "\" & INI_REWINDOW

End Sub
■リスト6:プログラム全体。前回閉じたときの位置にフォームを復元する。

 

7.おまけ

 

読み込み・書き込み・キーやセクションの作成。この3つができれば困ることはなさそうですが、他にもiniを操作する便利なAPI関数が提供されています。そのうちの2つを紹介しておきます。

MSDNライブラリを活用して使い方やその他のini操作関数も探してみてください。

GetPrivateProfileSectionNames iniの全セクション名を返す
GetPrivateProfileSection セクション内の全キー名と値を返す

■表1:その他のini操作関数

 

8.最後に

 

今回は中級編の割にはかんたんだったかもしれませんね。iniを使って最近開いたファイルをメニューに表示させる処理なんかもできますし、基本通りアプリケーション中の各種設定を保存することもできます。私自身はiniの最大の利点はアプリケーションの設定をUSBメモリやフロッピーディスクに入れて 簡単に持ち運べる点、そして、いざとなったらiniを直接開いて設定を変更できる点にあると思います。みなさんもいろいろ活用してください。