DLL 関数から文字列を返す

Microsoft Office 2000/Visual Basic プログラマーズ ガイド   

DLL 関数は、VBA 関数とは異なる方法で文字列を返します。通常、文字列は参照により DLL 関数に渡されるため、DLL 関数は文字列型 (String) の引数の値を修正することができます。文字列を関数の戻り値として返すのではなく、VBA で行うように、DLL 関数は渡された文字列型の "引数" に文字列を返します。多くの場合、この関数に対する実際の戻り値は、文字列型の引数に書き込まれた、バイト数を指定する長整数です。

文字列型の引数を取得する DLL 関数は、文字列のメモリ位置への "ポインタ" を受け取ります。ポインタは、文字列が保存されている位置を示すメモリのアドレスです。VBA で DLL 関数に文字列を渡す際は、実際には、メモリに存在する文字列へのポインタが DLL 関数に渡されます。DLL 関数は、そのアドレスに保存されている文字列を変更します。

文字列型の変数への書き込みを実行する DLL 関数を呼び出すには、文字列を適切にフォーマットするために追加の手順が必要です。まず、文字列型の変数は、Null 終端の文字列である必要があります。Null 終端の文字列の最後の文字は、VBA 定数の vbNullChar で指定された特定の Null 文字です。

次に、DLL 関数では、作成された文字列の長さを変更できないため、関数に渡す文字列が、戻り値を保持できる十分な長さに設定されていることを確認します。通常、文字列を DLL 関数に渡すときに、ほかの引数に渡した文字列の長さを設定する必要があります。Windows では、文字列が使用しているメモリが上書きされないように、文字列の長さが記録されます。

文字列を DLL 関数に渡す方法として、文字列型の変数を作成し、String$ 関数を使用してその変数に Null 文字を入力する方法をお勧めします。この方法では、文字列型の変数が、関数が返す文字列の受け取りに十分な長さに設定されます。たとえば、次のコードでは、長さが 144 バイトで、Null 文字が入力された文字列が作成されます。

  Dim strTempPath As String

strTempPath = String$(144, vbNullChar)

DLL 関数に渡す文字列の長さが不明の場合、Len 関数を使用して長さを確認することができます。

Windows の一時フォルダへのパスを取得する GetTempPath 関数は、文字列型の値を返す DLL 関数の例です。GetTempPath 関数は、Null 終端の文字列型の変数、および文字列の長さを含む数値変数の 2 つの引数を取得し、文字列を変更して "C:\Temp\" などのパスが含まれるようにします。

メモ   Windows を起動するには一時フォルダが必要なため、この関数は一時フォルダへのパスを必ず返します。一時フォルダへのパスが返されない場合、GetTempPath 関数はゼロを返します。

次のプロシージャは、GetTempPath 関数を呼び出して、Windows の一時フォルダへのパスを取得します。

  Declare Function GetTempPath Lib "kernel32" Alias "GetTempPathA" _
   (ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long

Property Get GetTempDir() As String
   ' 使用している Temp フォルダへのパスを返します。
   ' Windows を起動するには一時フォルダが必要なため、確実に
   ' パスには 1 が返されますが、一応 GetTempPath の戻り値を
   ' 確認します。
   
   Dim strTempPath As String
   Dim lngTempPath As Long
   
   ' 文字列に Null 文字を入力します。
   strTempPath = String(144, vbNullChar)
   ' 文字列の長さを取得します。
   lngTempPath = Len(strTempPath)
   ' GetTempPath を呼び出し、文字列の長さと文字列を渡します。
   If (GetTempPath(lngTempPath, strTempPath) > 0) Then
      ' GetTempPath はパスを文字列に返します。
      ' 最初の Null 文字を切り捨てます。
      GetTempDir = Left(strTempPath, _
         InStr(1, strTempPath, vbNullChar) - 1)
   Else
      GetTempDir = ""
   End If
End Property

GetTempFolder のプロパティ プロシージャは、Office 2000 Developer CD-ROM の ODETools\V9\Samples\OPG\Samples\CH10 フォルダにある System.xls の System クラス モジュールにあります。

メモ   Windows の API 関数と DLL 関数の戻り値の多くは、バイト単位になっています。この戻り値は、"A" というサフィックスの付いた ANSI バージョンの API 関数では、ANSI 文字および DBCS 文字で構成される文字列のサイズを表しています。ただし、Visual Basic では、ANSI バージョンの API 関数でも、実際に返される文字列は Unicode 文字列になります。したがって、戻り値で取得したサイズを文字列のサイズとして使用することはできません。次のコード例は、返される文字列を正しく取得します。

    buffer = String(145, vbNullChar)
   ret = GetPrivateProfileString(section, _
      entry, default, buffer, Len(buffer)-1, filename)
   retstring = Left(buffer, Instr(buffer, vbNullChar)-1)

図 10.1 は、strTempPath 文字列が GetTempPath 関数に渡される場合、および関数の呼び出しが終了した場合に、strTempPath 文字列がメモリ上でどのように現れるかを示しています。

図 10.1 DLL 関数から文字列を返す

この文字列が関数に渡されるとき、文字列には Null 文字が含まれています。関数は、文字列型の戻り値である "C:\Temp\" を文字列型の変数の最初の部分に書き込みます。残りの部分には、Null 文字が挿入されます。この Null 文字は、Left 関数を使用して切り捨てることができます。

GetTempPath 関数の実際の戻り値は、文字列型の変数に書き込まれている半角文字の数です。たとえば、返された文字列が "C:\Temp\" の場合、GetTempPath 関数は 8 を返します。

Null 終端の文字列およびその長さを渡す必要があるのは、関数から文字列を返す場合のみです。関数が文字列型の引数に文字列を返すのではなく、情報を含む文字列を取得する場合は、通常の VBA 文字列型の変数を渡すことができます。