none
Windows7上でのRtlMoveMemoryについて RRS feed

  • 質問

  • VisualBasic6.0で作成された実行形式ファイルをWindows7で動かしており、

    その処理の中で、RtlMoveMemoryを使用して変数に内容を移動しています。

    WindowsXPでは問題なく動作しますが、Windows7で動かすと落ちます(APPCRASH)。

    対処方法が発見できず困っております。

    情報がありましたら、よろしくおねがいいたします。

    以下にサンプルコードを記載します。

    Public Declare Sub memcpy Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, pSrc As Any, ByVal iSize&)

    Type COPYDATASTRUCT
            dwData As Long
            cbData As Long
            lpData As String
    End Type

    Public Function WndProc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
        Dim Str As String
        Dim lngret As Long


        Call memcpy(ByVal VarPtr(sdtCOPYDATASTRUCT), ByVal lParam&, LenB(sdtCOPYDATASTRUCT)) ←ここは正常に処理されます

        Call memcpy(ByVal Str, ByVal sdtCOPYDATASTRUCT.lpData, sdtCOPYDATASTRUCT.cbData) ←ここでストップします

    2012年7月10日 9:28

回答

  • 自信はありませんが、Str って固定長でも何でもないので、移動先として適切なのでしょうか?
    Win32API にバッファとして String を渡すときは、String * 100 のように固定長にしてメモリを確保していた記憶があるので、どうなのかな…。
    • 回答としてマーク ひろまつ 2012年7月11日 1:10
    2012年7月10日 13:48
    モデレータ
  • ありがとうございました。

    >そもそも XP で動いているのも偶然で

    この一文のおかげで、悪循環から抜け出せました。

    ご指摘の内容を踏まえて、以下のように修正したところ

    WinXP、Win7ともにAPPCRASHは発生しなくなりました。

    大変助かりました。

    (修正後サンプル)

    Type COPYDATASTRUCT
            dwData As Long
            cbData As Long
            lpData As String * 100 ←固定長に修正
    End Type

    Public Function WndProc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
        Dim Str As String * 100 ←固定長に修正
        Dim lngret As Long

    • 回答としてマーク ひろまつ 2012年7月11日 1:14
    2012年7月11日 1:14
  • 当然ですが、 *100 だと 100 文字までしか保持されません。また、構造体の名称から WM_COPYDATA を利用されようとしているのであれば、google 等で検索すると一杯サンプルが手に入ると思います。

    MSDN でも文字列を送受信するサンプルがあります。http://support.microsoft.com/kb/176058/ja

    • 回答としてマーク ひろまつ 2012年7月11日 8:55
    2012年7月11日 1:24

すべての返信

  • 自信はありませんが、Str って固定長でも何でもないので、移動先として適切なのでしょうか?
    Win32API にバッファとして String を渡すときは、String * 100 のように固定長にしてメモリを確保していた記憶があるので、どうなのかな…。
    • 回答としてマーク ひろまつ 2012年7月11日 1:10
    2012年7月10日 13:48
    モデレータ
  • そもそも XP で動いているのも偶然で、数万回に1度ぐらいエラーになっているのではないでしょうか? また、MoveMemory が成功した後であっても、コピー先の lpData にアクセスした時点で異常終了したり、期待していない内容になったりしていませんか?(可変長文字列はアドレスを保持しているだけなので、参照先の内容がコピーされないため)

    通常は、String ではなく String * 100 等として固定長文字列にして、連続したメモリ領域に確保されるようにします。こちらなら WinXP, Win7 ともに正常に動くのではないか?と期待します。

    2012年7月11日 0:00
  • 以前、Typeの要素「lpData」のみ固定長にしてみたのですが、APPCRASHで落ちていました。

    ご指摘の通り、引き受け側の「str」も併せて固定長にしたところAPPCRASHは発生しなくなりました。

    大変助かりました。ありがとうございました。

    以下のように修正しました。

    Type COPYDATASTRUCT
            dwData As Long
            cbData As Long
            lpData As String * 100 ←固定長に修正
    End Type

    Public Function WndProc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
        Dim Str As String * 100 ←固定長に修正
        Dim lngret As Long

    2012年7月11日 1:10
  • ありがとうございました。

    >そもそも XP で動いているのも偶然で

    この一文のおかげで、悪循環から抜け出せました。

    ご指摘の内容を踏まえて、以下のように修正したところ

    WinXP、Win7ともにAPPCRASHは発生しなくなりました。

    大変助かりました。

    (修正後サンプル)

    Type COPYDATASTRUCT
            dwData As Long
            cbData As Long
            lpData As String * 100 ←固定長に修正
    End Type

    Public Function WndProc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
        Dim Str As String * 100 ←固定長に修正
        Dim lngret As Long

    • 回答としてマーク ひろまつ 2012年7月11日 1:14
    2012年7月11日 1:14
  • 当然ですが、 *100 だと 100 文字までしか保持されません。また、構造体の名称から WM_COPYDATA を利用されようとしているのであれば、google 等で検索すると一杯サンプルが手に入ると思います。

    MSDN でも文字列を送受信するサンプルがあります。http://support.microsoft.com/kb/176058/ja

    • 回答としてマーク ひろまつ 2012年7月11日 8:55
    2012年7月11日 1:24
  • 追加情報ありがとうございます。

    実は・・・。APPCRASHで落ちなくなったのですが、構造体のlpDATAを固定長にすると、

    いままでの内容と違うデータが設定されてきてしまいました。

    参考にいただいたサイト等、勉強してみます。

    2012年7月11日 8:58
  • いろいろと、ご教授ありがとうございました。

    構造体のlpDATAは、String型ではWin7環境でうまく処理できませんでした。

    結局、送信したいメッセージが何型であれ、アドレスを渡すのが正しいのだとわかりました。

    現在、WinXp,Win7ともに問題なく稼働させることができております。

    以下に修正点のサンプルを記載します。

    '*** メッセージ送信側PG

    Private Type COPYDATASTRUCT
            dwData As Long 'データ識別等   
            cbData As Long 'データ長(バイト)
            lpData As Long 'データ格納アドレス ←StringからLongに修正
    End Type

    Private Const WM_COPYDATA = &H4A

    Private Declare Function FindWindow Lib "user32" Alias _
            "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName _
             As String) As Long

    Private Declare Function SendMessage Lib "user32" Alias _
            "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal _
            wParam As Long, lParam As Any) As Long

    Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
            (hpvDest As Any, hpvSource As Any, ByVal cbCopy As Long)

    Private Command1_Click()
        Dim cds     As COPYDATASTRUCT '--- 受け渡し用構造体
        Dim ThWnd   As Long           '--- 画面ハンドル
        Dim msgText As String         '--- 送信文字列格納変数

        msgText = "ABCD123"

        cds.cwData = 0
        cds.cbData = LenB(msgText) + 1
        cds.lpData = StrPtr(msgText) ←テキストデータの格納変数のアドレスを渡すように修正

        ThWnd = FindWindow(vbNullString, "Target")
        i = SendMessage(ThWnd, WM_COPYDATA, Me.hwnd, cds)
       :
       :
       :


    '*** メッセージ受信側PG

    Private Type COPYDATASTRUCT
            dwData As Long 'データ識別等   
            cbData As Long 'データ長(バイト)
            lpData As Long 'データ格納アドレス ←StringからLongに修正
    End Type

    Private Const WM_COPYDATA = &H4A

    Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
            (hpvDest As Any, hpvSource As Any, ByVal cbCopy As Long)

    Function WindowProc(ByVal hw As Long, ByVal uMsg As Long, _
                        ByVal wParam As Long, ByVal lParam As Long) As Long
        Dim cds     As COPYDATASTRUCT '--- 受け渡し用構造体
        Dim msgText As String         '--- 受信文字列格納変数

        If uMsg = WM_COPYDATA Then
            Call CopyMemory(ByVal VarPtr(cds), ByVal lParam&, LenB(cds))

            msgText = String$(sdtCOPYDATASTRUCT.cbData, vbNullChar)
            Call CopyMemory(ByVal msgText, ByVal cds.lpData, cds.cbData)

            msgText = StrConv(msgText, vbFromUnicode) '--- Unicodeから元に戻す

       :
       :
       :

    2012年7月20日 1:52