|
■No8941 (ことぶき さん) に返信
> vb6では当然の挙動なのかもしれませんが値渡しで渡した引数が書き換えられて戻ってくる(≠戻り値)事に
> 相当違和感を感じています。
確かに通常は、「値渡し」で内容が書き変わる事は無いのですが、Declare ステートメントを
使っている場合は、API 側でそのポインタの示す文字列の内容を編集する事ができるのです。
これは、文字列型変数が『文字列へのポインタ』として管理されているという事情によるものです。
(BSTR は、OLE ヘッダ ファイルでは OLECHAR FAR * として定義されます)
なお、Declare にて、文字列を参照渡しするのは、(LPSTRではなく)BSTRを受け取る場合だけです。
ついでに書いておくと、Declare では、文字列の ANSI/Unicode 変換も同時に行われるため、
文字列型では LPWSTR を受け取ることが出来ません。そのため、Unicode 文字列を渡す場合は、
バイト配列を使って渡すのが慣例となっています。(または、アドレスを値渡しする方法もあり)
より細かい内容について知りたいのであれば、MSDN ライブラリの
[MSDN ライブラリ 2001 年 4 月]
└[技術情報]
└[技術情報 (日本語)]
└[ビジュアル ツール]
└[Visual Basic]
└[Visual Basic]
└[Microsoft Visual Basic Version 5.0 で使用する DLL の開発に関する注意]
を参照してみてください。
以下、No8921で紹介されている内容に絡めた、String 型に関する実験コード。
変数のアドレスを取得する「VarPtr 関数」と、
文字列のアドレスを取得する「StrPtr 関数」を使っています。
'----------------------
Option Explicit
Private Declare Sub RtlMoveMemory Lib "KERNEL32" _
(ByRef hpvDest As Any, _
ByVal hpvSource As Long, _
ByVal cbCopy As Long)
Private Sub Command1_Click()
Dim S As String, bin() As Byte
S = Text1.Text
bin = S
Debug.Print "============="
Debug.Print "変数Sの文字列の長さ:="; Len(S); "(文字数)"
Debug.Print "変数Sの内容:=「"; S; "」"
Debug.Print "変数Sのバイナリ:=「"; DumpStr(bin); "」"
Dim pVar As Long, pStr As Long
pVar = VarPtr(S)
pStr = StrPtr(S)
Debug.Print "============="
Debug.Print "VarPtr(S):="; Hex(pVar); ":変数S のアドレス"
Debug.Print "StrPtr(S):="; Hex(pStr); ":文字列のアドレス"
Dim pVarValue As Long, size As Long
pVarValue = ReadLong(pVar)
size = ReadLong(pStr - 4)
Debug.Print "============="
Debug.Print Hex(pVarValue)
Debug.Print " = ReadLong(VarPtr(S))"
Debug.Print " これは、StrPtr(S) と一致する"
Debug.Print " 文字列変数の場合、VarPtrはStrPtrへのポインタを指す"
Debug.Print CStr(size)
Debug.Print " = ReadLong(StrPtr(S) - 4)"
Debug.Print " これは、文字数の2倍と一致する"
Debug.Print " StrPtrの直前4バイトには、文字列のバイト数が格納されている"
Debug.Print Dump(pStr, size)
Debug.Print " = Dump(pStr, バイト数)"
Debug.Print " これは変数 S のバイナリと一致する"
Debug.Print " StrPtrからのアドレスには、文字列本体が格納されている"
End Sub
Private Function ReadLong(ByVal Ptr As Long) As Long
RtlMoveMemory ReadLong, Ptr, 4
End Function
Private Function Dump(ByVal Ptr As Long, ByVal Length As Long) As String
Dim n As Long, b() As Byte
If Length > 0 Then
ReDim b(Length - 1)
RtlMoveMemory b(0), Ptr, Length
For n = 0 To Length - 1
Dump = Dump & Right("00" & Hex(b(n)), 2) & " "
Next
End If
End Function
Private Function DumpStr(ByRef bin() As Byte) As String
Dim v As Variant
For Each v In bin
DumpStr = DumpStr & Right("00" & Hex(v), 2) & " "
Next
End Function
Private Sub Form_Load()
Text1.Text = "あいうえお"
End Sub
|