怠日記

写真・金魚・昆虫・プログラミングの趣味を語るサイトです。似たようなことをnoteにも書いたり書いてなかったり。

VBA: Unicodeのiniファイルを読み取るには | GetPrivateProfileStringW関数

VBA で ANSI の ini ファイルを読み取る方法は以下のページに書いたとおり。

nmk365.hatenablog.jp

それと同様に Unicode の ini ファイルから文字列を読み取るには、Win32API の GetPrivateProfileStringW 関数を使う。

サンプルコード

以下に GetPrivateProfileStringW 関数を使った読み取りのサンプルを示す。

Option Explicit

Private Declare PtrSafe Function GetPrivateProfileStringW Lib "kernel32" ( _
    ByVal lpAppName As LongPtr, _
    ByVal lpKeyName As LongPtr, _
    ByVal lpDefault As LongPtr, _
    ByVal lpReturnedString As LongPtr, _
    ByVal nSize As Long, _
    ByVal lpFileName As LongPtr _
) As Long

Public Sub Main()

    'マクロブックと同じ場所の app.ini ファイルを対象とする
    Dim iniFilePath As String
    iniFilePath = ThisWorkbook.Path & "\app.ini"

    'バッファを確保する
    Dim buffer As String
    buffer = String$(512, Chr$(0))

    Dim bufferLength As Long
    bufferLength = Len(buffer)

    '値を読み込む
    '  関数の戻り値はバッファに入れた文字数
    '  読み込んだ文字列は引数 buffer に入れられる
    Dim retLength As Long
    retLength = GetPrivateProfileStringW(StrPtr("TestSection"), _
                                         StrPtr("TestKey"), _
                                         StrPtr("デフォルト値"), _
                                         StrPtr(buffer), _
                                         bufferLength, _
                                         StrPtr(iniFilePath))

    'バッファから読み込んだ文字列を抽出する
    '  このようにしないと不要な値 (バッファ確保で使ったChr$(0)) も一緒に取得してしまうため
    MsgBox Left$(buffer, InStr(buffer, Chr$(0)) - 1), title:="GetPrivateProfileStringW()"

End Sub

マクロを実行する前に、マクロブックと同じ場所に以下のような内容で app.ini ファイルを作っておく。
文字コードは Unicode(UTF-16 LE)にしておくこと。

; iniファイルテスト
[TestSection]
TestKey=読み取りテスト♡

マクロ実行で「読み取りテスト♡」と表示された。
「♡」は Unicode 文字だが問題なく読み取られた。

…となってほしかったが、「♡」は「?」になっていた。
VBA の MsgBox 関数では Unicode 文字が表示できないのかもしれない。

Win32API の MessageBoxW 関数を使ったところ、問題なく表示できた。

解説

ANSI 版と大差ないので、異なる部分を中心に解説する。

まず、GetPrivateProfileStringW 関数は次のように定義されている。

DWORD GetPrivateProfileStringW(
  [in]  LPCWSTR lpAppName,
  [in]  LPCWSTR lpKeyName,
  [in]  LPCWSTR lpDefault,
  [out] LPWSTR  lpReturnedString,
  [in]  DWORD   nSize,
  [in]  LPCWSTR lpFileName
);

データ型が LPWSTR、LPCWSTR の引数には、文字列のポインタを渡すようにしなければならない。

なので VBA で宣言するときは、次のようにデータ型を LongPtr にする。

Private Declare PtrSafe Function GetPrivateProfileStringW Lib "kernel32" ( _
    ByVal lpAppName As LongPtr, _
    ByVal lpKeyName As LongPtr, _
    ByVal lpDefault As LongPtr, _
    ByVal lpReturnedString As LongPtr, _
    ByVal nSize As Long, _
    ByVal lpFileName As LongPtr _
) As Long


GetPrivateProfileStringW 関数は以下のように呼び出す。

StrPtr 関数を使って、VBA の文字列のポインタを引数に渡すのがポイントである。

retLength = GetPrivateProfileStringW(StrPtr("TestSection"), _
                                     StrPtr("TestKey"), _
                                     StrPtr("デフォルト値"), _
                                     StrPtr(buffer), _
                                     bufferLength, _
                                     StrPtr(iniFilePath))

戻り値は、バッファに設定された文字数になる。