MoveMemoryの使い方

解決


プログラムはじめ  2010-08-07 21:29:35  No: 102495  IP: [192.*.*.*]

いつもお世話になってます。
下記のページを参考にして変数のコピーをRtlMoveMemoryを使って行う方法を勉強中ですが、変なエラーがでてうまく行きません。

http://msdn.microsoft.com/en-us/library/aa366788(VS.85).aspx

Private Declare Sub MoveMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal Destination As Long, ByVal Source As Long, ByVal Length As Long)
Private Sub test()
    Dim a As String, b As String
    
    a = "あああaaa"
    Debug.Print LenB(a)
    MoveMemory VarPtr(b), VarPtr(a), LenB(a)
    MsgBox b

End Sub

LenB(a)をLen(a)に変えたらうまくいくようなのですが、第3引数にはコピーするバイト数を指定するのではないのでしょうか?ご教示ください。

編集 削除
花ちゃん  2010-08-08 12:51:38  No: 102496  IP: [192.*.*.*]

>LenB(a)をLen(a)に変えたらうまくいくようなのですが、

a = "あああaaa"  では、Len(a)= 6 になり、異常終了しませんか?

>第3引数にはコピーするバイト数を指定するのではないのでしょうか?

多分、この場合は、文字列のポインタをコピーしているので、Long 型の
4 バイト固定でいいのではないでしょうか?

Private Sub test()
    Dim a As String, b As String
    a = "あああaaa"
    MoveMemory VarPtr(b), VarPtr(a), 4
    MsgBox b
    a = "a"
    MoveMemory VarPtr(b), VarPtr(a), 4
    MsgBox b
    a = "あああaaaあああaaa"
    MoveMemory VarPtr(b), VarPtr(a), 4
    MsgBox b
End Sub

編集 削除
プログラムはじめ  2010-08-08 17:00:11  No: 102497  IP: [192.*.*.*]

花ちゃん様、ありがとうございます。
うまくいきました。
僕の最初の書き方のようにしようとすると一度byte型で受ける必要があると考えましたがあってますでしょうか?

Private Declare Sub MoveMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

Private Sub test3()
    Dim a As String, b As String
    Dim c() As Byte, d() As Byte

    a = "あああaaa"
    ReDim c(0 To LenB(a) - 1)
    ReDim d(0 To LenB(a) - 1)
    c() = a
    MoveMemory d(0), c(0), UBound(c) + 1
    
    MsgBox d
    
End Sub

編集 削除
Abyss  2010-08-08 21:54:38  No: 102498  IP: [192.*.*.*]

最初と、その後のAPI宣言で変数の渡す方法が違うのは
意図的なものですか?

編集 削除
プログラムはじめ  2010-08-08 22:27:58  No: 102499  IP: [192.*.*.*]

Abyss様、いつもご指導ありがとうございます。
配列を引き渡すので参照引渡ししないとだめなのかと思いました。間違っていますでしょうかl?

編集 削除
Abyss  2010-08-08 22:39:54  No: 102500  IP: [192.*.*.*]

いいえ。間違いとかではありません。
参照渡し、値渡しの問題がなければ良いとします。
気になっただけですので。

編集 削除
プログラムはじめ  2010-08-08 22:57:42  No: 102501  IP: [192.*.*.*]

Abyss様、いつもありがとうございます。
APIは勉強を始めて日が浅く、まだまだ見習い状態です。今後ともなにかありましたらご指摘くださると非常にうれしいです。

編集 削除
Abyss  2010-08-08 23:19:38  No: 102502  IP: [192.*.*.*]

今回のご質問はAPIよりVB6における
文字列(String型)の扱いが問題な気がします。

dim c() as byte
c = "あああaaa"

の場合、cは文字列(String型)ではありませんよね?
msgbox c

とした場合、VBが文字列への変換をしてくれただけです。

編集 削除
プログラムはじめ  2010-08-09 01:02:18  No: 102503  IP: [192.*.*.*]

Abyss様
いつもお世話になっております。

>cは文字列(String型)ではありませんよね?
>msgbox c

>とした場合、VBが文字列への変換をしてくれただけです。

ここは意図してやっていました。花ちゃん様とAbyss様のご指導により、僕が当初理解できていなかったのは、文字列型の変数が参照型ということがわかっていなかったのだと気づきました。
string型変数を書き換えるときは参照型変数の確保領域の4バイトを引き渡して、Byte型を引き渡すときは、Byte数を引き渡す必要があると理解しましたが、あってますでしょうか?

編集 削除
Abyss  2010-08-09 01:34:05  No: 102504  IP: [192.*.*.*]

> ここは意図してやっていました。
了解です。
> ...あってますでしょうか?
と思います。文字列をバイト単位で扱う一つの例です。

Declare Sub MoveMemory Lib "Kernel32" Alias "RtlMoveMemory" _
  (pDest As Any, pSrc As Any, ByVal cbLen As Long)
  
Sub Test()

  Dim a As String, c() As Byte
  
  a = "あああaaaあああaaaa"
  ReDim c(1 To LenB(a))
  MoveMemory c(1), ByVal StrPtr(a), LenB(a)
  MsgBox c
End Sub

編集 削除
Abyss  2010-08-09 01:56:37  No: 102505  IP: [192.*.*.*]

学習のためですと↓のもご参考になるかと。
余計でしたらすみません。

  Dim a As String, c() As Byte
  Dim i As Long
  
  a = "あああaaaあああaaaa"
  'LenB(a)の代わり...
  MoveMemory i, ByVal StrPtr(a) - 4, 4
  MsgBox "文字列のバイト長=" & i
  
  ReDim c(1 To i)
  MoveMemory c(1), ByVal StrPtr(a), i
  MsgBox c

編集 削除
プログラムはじめ  2010-08-09 03:03:27  No: 102506  IP: [192.*.*.*]

Abyss様ありがとうございます。

>MoveMemory c(1), ByVal StrPtr(a), LenB(a)

なるほど。勉強になります。今回の質問をさせていただくまで、StrPtr、VarPtrの違いがよく分かってなかったことにも気づきました。

>MoveMemory i, ByVal StrPtr(a) - 4, 4

bstr型についても、このように調べると書物で読むより、理解が深まります。本当にありがとうございました。とてもすっきりしました。

編集 削除