Visual Basic 6.0 中級講座
VB6対応

 

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

第2回 バッファへのポインタ

 

APIを使って何かの情報を取得したい場合があります。たとえばユーザー名やコンピュータ名。もっとこったプログラムではディスプレイやプリンタの状態を知りたいときもあるでしょう。今回はAPI関数を使って情報を取得する基本的な方法を説明します。

 

この回の要約

・API関数 GetUserName()を使って Windowsのユーザー名を取得する方法。

・API関数から値を受け取る場合にはバッファへのポインタを使うことが多い。

・バッファへのポインタとは何かを代入してある文字列型の変数のこと。

・API関数が返した値の後ろには NULL(ヌル) が付加されている場合がある。

・NULLは邪魔なので Left関数やInStr関数を使って取り除いた方が良い。

 

1.戻り値

 

ユーザー名を取得するAPIは確かに存在します。このAPI関数を使うと現在ログオンしているユーザーの名前を取得できるという物です。ここでVBならば、ユーザー名は関数の戻り値として返されるのでしょうがAPIでは違います。この違いがAPI入門者には壁の一つとなっているのです。

ユーザー名を取得するAPIは GetUserName というものです。この関数を使用するためには宣言セクションに次のように記述しなければなりません。

Private Declare Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal lpBuffer As String, nSize As Long) As Long

もしVBの関数のようにこの関数がユーザ名を戻り値として返すのなら次のようにしてユーザー名を取得できるでしょう。

'これはまちがった例です。

Dim UserName As String

UserName = GetUserName()

ところが実際にはこの関数の戻り値はユーザー名ではなくエラー情報です。エラー情報は数字で表されますからユーザー名とはかけ離れた物が返されるわけです。

ではこの関数を利用してどうやってユーザー名を受け取るのでしょうか?

実は情報を返すAPIの多くは 「どこに情報を返すか」 を自分で指定しなければならないのです。この情報を返す場所を示す物を「バッファへのポインタ」と言います。(この言い方は少し乱暴な言い方です)。

VB風に言うと自分でユーザー名を格納するための文字列型の変数を用意しろと言うことです。この文字列型の変数がそのままバッファへのポインタとなります。

そこで、ただしくユーザー名を取得する例は次のようになります。

Dim UserName As String

Dim ReturnAPI As Long

UserName = Space(20)

ReturnAPI = GetUserName(UserName, Len(UserName))

MsgBox UserName

この4行の他にGetUserName関数のためのDeclare Function宣言も必要です。

さて、3行目の UserName = Space(20) は今回のメインですので解説しておきます。これはユーザー名を格納するための20文字分のバッファ(入れ 物)を用意(確保)しているわけです。API関数で値を受け取る場合にはこのようにあらかじめ領域、つまりバッファを確保しておくことが必要な場合が多いです。これはVBのString型の性質と関係があるのですがそこまで詳しく知らなくてもよいでしょう。

用語について整理しておくと、この例の場合 20文字分の領域のことを バッファ と言います。そしてそのバッファを表している変数は バッファへのポインタ と呼ばれます。「バッファへのポインタ」などとVBでは呼ばないのですがAPIのヘルプの中で「バッファへのポインタ」という記述が出てきたら、「あぁ領域を確保してある変数のことだなぁ」と思っていただいて十中八九問題ありません。

注意が必要なのは「単に宣言しただけの文字列型の変数はバッファへのポインタではない」ということです。何かを代入して初めてバッファへのポインタとなれるのです。

なお固定長の文字列型変数もバッファへのポインタです。

ReturnAPIはAPIの戻り値を格納するための変数です。今回は戻り値は使用しないので実際の役には立っていません。

4行目が核です。GetUserName関数は2つの引数をとり 第1引数がバッファへのポインタ、第2引数がバッファの大きさです。この例ではバッファへのポインタ(ユーザー名を格納するための変数)はUserName、バッファの大きさは 3行目で Space(20) としているようで直接 20 と書いても良いのですが後での変更が発生した場合に備えてLen関数を利用しています。。

これで一応ユーザー名を取得することができます。

 

2.NULL ヌル

 

上の例の最後の行を改造して次のようにしてみましょう。

MsgBox "私は" & UserName & "です。"

最後の行はすでに取得したユーザー名を表示するだけの部分なのでこの変更は重要ではないはずですが示唆に富む結果が現出します。試してみて下さい。

実行してみるとなんとメッセージボックスの中には最後の「です。」が表示されないではありませんか。これは困ります。この現象を知っておかないとAPIで取得した文字列を評価するときにおもわぬ論理エラーが発生してしまうのです。

この現象の原因はやはり文字列UserNameにあります。APIはユーザー名をこの変数に入れて返したわけですが、実際のユーザー名は多分20文字より少ないはずです。しかし、我々はUserNameに20文字 分のスペースを代入してしまいした。そのため、余った部分にAPI関数が勝手にNULL(ヌル)をつめこんだのです。

NULLとはVBではほとんど使わないもので、C言語などのユーザーが使用します。APIはVBからも他のプログラム言語からも使えるのでこのようにVBには関係ない、むしろ邪魔な現象がしばしば起こります。

しかし、原因が分かってしまえば後はこのNULLを取り除くだけです。この方法は次節で説明するとしてまずは NULLって何? という疑問に簡単に答えておきましょう。

基本的には NULL は 「値がない」という状態を示してます。

コンピュータは表示する文字を「文字コード」と呼ばれる数字で管理しています。たとえば 「C」 の文字コードは 67 です。(文字コードにもいろいろあってこの辺を説明しきることは到底不可能です。興味のある人は専門書をお読み下さい)。文字コードを使ってVBで文字を取得するには Chr関数 を使います。たとえば、MsgBox Chr(67) とすると C と書かれたメッセージボックスが表示されます。

さて、文字コードの中には特殊な物もあって たとえば コード 9 はスペースキーを表します。13 はEnterキーです。矢印キーを表すコードもあります。左が37で、上が38といった具合です。これらは普通の人は「文字」と呼ばないのですがコンピュータの文字コードには含まれているのです。

NULLもこのような特殊な文字(?)の一つで NULLの文字コードは 0 です。つまりChr(0)のことです。もちろん特殊な文字なので MsgBox Chr(0)としても何も表示されません。NULLはCプログラマーが文字列の終わりの印として使ったりする物でVBでは使いません。しかしVBでもAPIを使う場合にはこのようにNULLが登場してくるときもあります。

なお、NULLはこのように特殊な文字なので 定数 vbNullChar で表現することができます。 vbNullCharとChr(0)は同じ値です。

 

3.NULLを取る

 

では、NULLを取り去りましょう。何文字目からNULLになっているのかを調べて、後はLeft関数を使用すればNULLを除去できます。

何文字目からNULLになっているか調べるにはInStr関数が便利です。NULLは他の文字と違う扱いが必要な場合も多いのですが、InStr関数では他の文字と同様に扱うことができます。具体的には次のようになります。

InStr(1, UserName, vbNullChar)

そこでNULLを取り去る部分のコードは次のようになります。

UserName = Left(UserName, InStr(1, UserName, vbNullChar) - 1)

MsgBox "私の名前は " & MyName & " です。"

これでやっと、ユーザー名を正しく取得することができます。

 

4.最後に

 

ユーザー名を取得するという単純な要求だったのになんだか面倒くさい物でした。しかし、この方法さえ分かっていればVBだけでは得られないようないろいろな情報を取得することができます。

たとえば、コンピュータ名を得るには GetComputerName関数を使います。使い方はGetUserNameと同じです。他にも似たような使い方をするAPIがいくつか(もしかしたらたくさん)あります。

今回はだいぶ短くなりました。ちょっとテーマが小さかったかも知れません。最後にユーザー名を取得するオリジナルの関数を掲載しておきます。

Private Function UserName() As String

    Dim Name As String
    Name = Space(255)
    Call GetUserName(Name, Len(Name))
    UserName = Left(Name, InStr(1, Name, vbNullChar) - 1)

End Function

この関数を使ってユーザー名を取得するには Name = UserName のようにします。もっといえばプログラムの中でUserNameと書くだけでユーザー名を表すことになります。たとえば MsgBox UserName は正常に作動します。もちろんNULLも除去されます。プログラムに貼り付けて自由に使ってください。