トロPのVBAホビラボ Stringを調べてみる [トロPのVBAホビラボ]
前回はメモリーイメージを調査する際に使う、簡単なユーティリティーを準備しました(→ご参照)。と、同時に単に使い方をみるためだけのサンプルプログラムを提示して終わりましたが、
せっかく作ったので今回は少し使ってみましょう。
今回は、String型のメモリーイメージです。
1点お断りしておきますが、今後も基本的に32ビット環境で実施していきます。
(理由は主旨から外れますのでここでは控えたいと思います。ご容赦を。)
さて、話を戻しましょう。
String型の変数の場合、VBAには変数のアドレスを返す関数が2つあります。
- VarPtr
- StrPtr
1つの変数に2種類のアドレス???
私は即座に違和感がありましたが、みなさんはいかがでしょうか。この疑問は言い換えればこの2つのどちらを使えばいいの?使いどころは?ということです。
では実際にメモリーイメージを見てみましょう。
サンプル |
---|
Public Sub StringMemory() Dim l_AString As String Dim l_AStringPos As Long Dim l_BSTRLenPfx As Long Dim l_ChrCodes As String l_AString = "私は文字列A。" Debug.Print "AString: " & l_AString Debug.Print Debug.Print "[VBA Information]" Debug.Print "VarPtr: " & Hex(VarPtr(l_AString)) Debug.Print "StrPtr: " & Hex(StrPtr(l_AString)) Debug.Print "Len: " & Len(l_AString) Debug.Print "LenB: " & LenB(l_AString) l_ChrCodes = "" For l_AStringPos = 1 To Len(l_AString) If 0 < Len(l_ChrCodes) Then l_ChrCodes = l_ChrCodes & ", " l_ChrCodes = l_ChrCodes & Hex(AscW(Mid(l_AString, l_AStringPos, 1))) Next l_AStringPos Debug.Print "Character codes: " & l_ChrCodes Debug.Print Debug.Print "[As BSTR]" ModUtility.CopyMemory VarPtr(l_BSTRLenPfx), StrPtr(l_AString) - 4, 4 Debug.Print "Length Prefix: " & l_BSTRLenPfx Debug.Print "--- Data string ---" ModUtility.DisplayMemory StrPtr(l_AString), l_BSTRLenPfx Debug.Print "--- Terminator ---" ModUtility.DisplayMemory StrPtr(l_AString) + l_BSTRLenPfx, 2 End Sub |
イミディエイトウィンドウ |
---|
AString: 私は文字列A。 [VBA Information] VarPtr: 1FF490 StrPtr: 1537345C Len: 7 LenB: 14 Character codes: 79C1, 306F, 6587, 5B57, 5217, 41, 3002 [As BSTR] Length Prefix: 14 --- Data string --- 1537345C C1 79 6F 30 87 65 57 5B 17 52 41 00 02 30 --- Terminator --- 1537346A 00 00 |
わかりにくいので、上の結果を少し図示してみました。
VarPtrとStrPtrのアドレスがどういう位置なのかわかりました。
また、Stringが文字データの他若干10バイトほどの領域が必要というようなことがオンラインヘルプに書かれていたことがあったかと思いますが、どうやらその正体は上の(1)(2)(4)ですね。まあ、このことは広大なメモリーを搭載している現在のパソコンでは何ら問題になりませんが。
さて、ここで次のプログラムを実行するとイミディエイトウィンドウには何と表示されるでしょうか。
サンプル |
---|
Public Sub NullWithinString() Dim l_AString As String l_AString = "A" & vbNullChar & "B" Debug.Print Len(l_AString) End Sub |
C言語に慣れておられる方には違和感があるでしょうが、実は「3」と表示されます。
もう1回メモリーイメージの結果を思い出してみましょう。
確かに(4)で終端にヌル文字を持っていますので、これを使って文字列の終端判別をしそうなものです。ですが、ならなぜ(2)でデータ本体のサイズを持っているのでしょうか。
これは読みやすさのためというより、このように任意の文字を含めることができるような構造にするためなのでしょう。
実は、ちょくちょくBSTRという謎めいた記述にお気づきかと思います。
少し脇道ですが、VBA(ないし古いVB)は、COMオブジェクトを使いやすくした抽象データを
定義できる言語ということができるでしょう。COMオブジェクトというのは参照設定してつかうあれです。
COMでは文字列をBSTR型で扱うことをご存知の方は、正解できたのではないでしょうか。
このようにVBAのString型はCOMとの親和性のある構造になっていますが、一方そのために
Windows APIを使うときに違和感を生じる原因にもなっているのではなかろうかと思います。
次回はAPIとの関連について調べてみましょうか。
今日の結論 |
---|
VBAのStringはBSTR実体+BSTRへのポインター。 |
コメント 0