- ベストアンサー
バイナリ→構造体
- 仕様の都合でLong型のポインタにしたいと思ってます。
- VarPtrを使ってLong型のポインタに変換し、別の構造体に格納して共有メモリに移す方法を教えてください。
- 別ウインドウから共有メモリからデータを取り出し、Long型のポインタから構造体に戻す方法を教えてください。
- みんなの回答 (15)
- 専門家の回答
質問者が選んだベストアンサー
> ついでを言えば、共有メモリを扱うクラスもあります。こんな感じです。 ということでどんな実装になっているかがわかったので、 対応策を。 対応策1 Cue構造の要素1つずつに個別の領域をSetBuffName()を使って割り当てて行き、要素の位置はアドレスではなく領域名を導き出せる数字等(たとえば"Cue1"だったら1)を別の構造体に格納して連結していく 対応策2 要素1つずつに個別の共有メモリを割り当てるのではなく一括にしか取得できない場合は、VarPtr()で取得されるローカルの変数のアドレスを入れるのではなく、共有メモリに書き込む大きな領域の先頭からのオフセットを入れておく。 みたいな感じでできそうですね。 やっぱり対応策1が楽かな。
その他の回答 (14)
- taka_tetsu
- ベストアンサー率65% (1020/1553)
>「どっちが書く」なんてことは、確かに全然重要ではないように思いますがいかがですか? 単なる「共有メモリのサンプル」でしたら重用ではないですけど、「OCXを使った共有メモリのサンプル」となった時点で非常に重要になると思っています。ポイントがここではないのなら、元のサンプルだけで十分かと。 >っていか、突っ込みばかりですが、オタクは何がベストだと思っているの? 現在Chirs_Elfirdさんが使われているOCX中での共有メモリの実装にもとづいた対応策です。 OCXを選択している時点で他のプロセスでも使用していると考えるのが当然でしょう。 つまり、処理が既に出来上がっていると考えるべきです。 >これを回避するには、OCX側で共有メモリの領域をどのように確保しているか、 >複数回確保の要求があった場合、どのように割り当てているかの >実装方法に依存してくるため、ここでは記述できません。 >#2の方の参考urlのようにOCXでReadProcessMemory()も >ひとつの手ですが、OCX自体もChirs_Elfirdさんが作られてるんですか? なので、この回答待ちです。とはいってもChirs_ElfirdさんがOCXまで作ってて新規に全部作れる場合の案を下に書いておきますが。 >私もtaka_tetsuさんがそれほどのツッコミを入れるなら、どのような手段をとるのか見てみたいと思っております。 なんかツッコミいれた場所の観点がずれちゃいましたね(^^;;; ReadProcessMemory()等を使った共有メモリ、OKだと思いますよ。 ただ、2chさんの今回#5にかかれたサンプル、 http://oshiete1.goo.ne.jp/kotaeru.php3?q=817941 をもとに、 >正直、無視されていると思っているので、腹が立っています。 という気分で無理やり作ったんだろうなぁというのが見て取れるようなソースだったんで。 おそらく完璧と思って提示されたんだろうなとは思って突っ込んでみたのが火に油を注いでしまったようですね。 確かに「無茶苦茶」はちょっと書きすぎでしたね。失礼しました。ちゃんと理解した上で突っ込んでるんでお間違えなく。 >ほかに共有メモリを利用したやり取りする手法をお持ちなのですか? で、これなんですが、今回の事例ではファイルマッピング+MapViewOfFileExを使うのがベストかと思っています。 ・実装個所がOCXである。 ・・・共有メモリを保持するプロセスが特定できない可能性がある。WriteProcessMemoryで書き込むには書き込み対象のプロセスが一意に特定できる状態であることが必要です。しかし、OCXという実装を取っていることから考えると、特定の共有メモリ管理用のプロセスが存在しない可能性もある。 MapViewOfFileやMapViewOfFileExであれば、起動されたプロセスのうちどれか1つハンドルを開いていればオブジェクトは消滅しないため、管理用プロセスが不要となる。 管理用プロセスが要るというのであれば、OCXではなくActiveX EXEにして共有メモリなんて使わないのがベスト。 ・Cue構造にしたいため、共有メモリ中のアドレスを必要とする。 ・・・MapViewOfFileでは割当ての先頭アドレスがプロセスごとに同じとは限らないのでアドレスを格納しても無意味。MapViewOfFileExなら先頭アドレスを指定できるのでアドレスが有効になる。まぁ、こちらはWriteProcessMemoryでも出来るかとは思いますが。 といったところですかね。 メモリマップドファイルだとサイズ拡張できないというのがありますが、そしたら複数個作っちゃえばいいだけですし。 でも、やっぱり、 >なぜOCX?ActiveX EXEという選択肢はNGだったんですか? >これならプロセス空間を意識しないで情報のやり取りできますが。 なんですけどね。VBですから。 納得していただけますか?
補足
すいません、理解力がまったく追いつかず完全に亀レスになってしまいました。個人的にはサンプルソースをそのままコピペしてはい解決とは言いたく無い物で…2chさんを怒らせてしまったのは単に私の理解力不足です。申し訳ありませんでした。 > 現在Chirs_Elfirdさんが使われているOCX中での共有メモリの実装にもとづいた対応策です。 > OCXを選択している時点で他のプロセスでも使用していると考えるのが当然でしょう。 > つまり、処理が既に出来上がっていると考えるべきです。 つまりはその通りです。共有メモリを扱う事自体はできているので、問題はOCX内で共有メモリを使う事にあるのです。 ついでを言えば、共有メモリを扱うクラスもあります。こんな感じです。 Private Declare Function CreateFileMapping Lib "kernel32" Alias "CreateFileMappingA" _ (ByVal hFile As Long, _ lpFileMappigAttributes As SECURITY_ATTRIBUTES, _ ByVal flProtect As Long, _ ByVal dwMaximumSizeHigh As Long, _ ByVal dwMaximumSizeLow As Long, _ ByVal lpName As String) As Long Private Declare Function OpenFileMapping Lib "kernel32" Alias "OpenFileMappingA" _ (ByVal dwDesiredAccess As Long, _ ByVal bInheritHandle As Long, _ ByVal lpName As String) As Long Private Declare Function MapViewOfFile Lib "kernel32" _ (ByVal hFileMappingObject As Long, _ ByVal dwDesiredAccess As Long, _ ByVal dwFileOffsetHigh As Long, _ ByVal dwFileOffsetLow As Long, _ ByVal dwNumberOfBytesToMap As Long) As Long Private Declare Sub MoveMemory Lib "kernel32" Alias "RtlMoveMemory" _ (ByVal Destination As Long, _ ByVal Source As Long, _ ByVal Length As Long) Private Declare Sub ZeroMemory Lib "kernel32" Alias "RtlZeroMemory" _ (ByVal Destination As Any, _ ByVal Length As Long)
- TAGOSAKU7
- ベストアンサー率65% (276/422)
通りすがりの間違いサンプル提示したものです。 すいません。私のLenサンプルが間違っていたようですね。 ご迷惑おかけしました。m(_ _)m 私自身、結構サンプルを適当に書いているので、私のサンプルを見るときは、「手抜き」で「間違いがある」と思っておいてくださいませ。m(_ _)m ------------------------------------------------ 久々発言ついでですが、確かにツッコミどころが気になるのですが、taka_tetsuさんはどうお思いですか? 題意から外れている内容にこだわり過ぎに思うのは私だけ? 2chさんも熱くなり過ぎ。 私個人的にには、「共有メモリ」に関しては、2chさんのサンプル以外は考えられないように思いますが、taka_tetsuさんはどうお思いですか? 「どっちが書く」なんてことは、確かに全然重要ではないように思いますがいかがですか? 見ていて、ちょっと見苦しい言い回しが多いように感じたので、私も個人的ツッコミ入れさせていただきました。 前後の文言が無く「滅茶苦茶」と言われたら、誰だって熱くなると思います。 でも私には、全然滅茶苦茶と思えません。 それ以外に考えられないと思っております。 >そこは一緒なんですけど(^^;;; >この手法が使えないとは書いてません。 ほかに共有メモリを利用したやり取りする手法をお持ちなのですか? 私もtaka_tetsuさんがそれほどのツッコミを入れるなら、どのような手段をとるのか見てみたいと思っております。
補足
すいません、入らないのでこっちにわけます。 Public Function SetBuffName(ByVal vstrBufferName As String, _ Optional ByVal vblnOwner As Boolean = False) As Boolean Dim blnResult As Boolean Dim lngpBuff As Long Dim bytBuff(2049012 - 1) As Byte Dim udtSA As SECURITY_ATTRIBUTES blnResult = False udtSA.nLength = Len(udtSA) '// オーナーモードならファイル作成。使用者モードならファイルオープン ' If (vblnOwner = True Or True) Then If (vblnOwner = True) Then '// メモリマップトファイル作成 m_lnghMap = CreateFileMapping(INVALID_HANDLE_VALUE, _ udtSA, _ PAGE_READWRITE, _ 0&, _ m_lngTableSize, _ vstrBufferName) Else '// メモリマップトファイルオープン m_lnghMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, _ 0&, _ vstrBufferName) End If If (m_lnghMap = 0) Then Beep Debug.Print Err.LastDllError Else '// マッピング lngpBuff = MapViewOfFile(m_lnghMap, _ FILE_MAP_WRITE Or FILE_MAP_READ, _ 0, _ 0, _ 0) If (lngpBuff <> 0) Then '// オーナーモードなら、バッファ内容初期化 m_lngpBuff = lngpBuff If (vblnOwner = True) Then Call ZeroMemory(m_lngpBuff, m_lngTableSize) End If '// 排他用セマフォ名生成 m_strSema = Format$(vstrBufferName, m_FORMAT_SEMA_NAME) blnResult = True Else Beep Debug.Print Err.LastDllError End If End If SetBuffName = blnResult End Function '// バッファ取得 Public Function GetBuffer(ByVal vlngPtr As Long) As Boolean Dim blnResult As Boolean Dim lngSema As Long If m_lngpBuff <> 0 Then '// MoveMemoryは#1,#2ともByValのLong宣言してるので、ロングポインタ以外 '// 使えないようになってます。 Call MoveMemory(vlngPtr, m_lngpBuff, m_lngTableSize) blnResult = True Else '// Not Open End If GetBuffer = blnResult End Function '// バッファ更新 Public Function SetBuffer(ByVal vlngPtr As Long) As Long Dim lnghSema As Long Dim blnResult As Boolean If m_lngpBuff <> 0 Then '// セマフォでの排他処理 lnghSema = CreateBuffSemaphore() If (0 <> lnghSema) Then Call MoveMemory(m_lngpBuff, vlngPtr, m_lngTableSize) blnResult = True End If Call ReleaseBuffSemaphore(lnghSema) Else '// Not Open End If SetBuffer = blnResult End Function 会社のだからもしかしたらマズいかなーと思い今まで出すに出せなかったんですが、この際なので出してしまいます。これを使ってました。 元々は別なフォームにあったこのクラスをOCXで呼び出しCue構造にして構造体でも扱えるようにする、と言うのが最終的な目標だった訳です。 このクラスを使うことに絶対性は無いんですが、OCXとCue構造は外せ無い条件なので… 先輩のサンプルソースを元に二月ほどの付け焼刃な知識のため、理解力が追いつかないので…ってまあ、完全にいい訳になってますが…少し、じっくりと読む時間をください。熱くなられるとこちらとしても焦ってしまいますので…
- taka_tetsu
- ベストアンサー率65% (1020/1553)
もひとつおまけ。 Type AAA AAA_int As Integer AAA_long As Long End Type Sub main() Dim a As AAA MsgBox VarPtr(a.AAA_long) - VarPtr(a.AAA_int) End Sub 表示されるのは2ですか?4ですか? >LenBでやってみてください。メモリを破壊します。 これの根拠は?経験則?
- 2ch
- ベストアンサー率51% (64/125)
まず最初にLen問題 私の間違いのようです。 すいません。 私もかなりあつくなっておりましたので、言い過ぎもありました。 >当然こういうサンプル出されるんでしたらOCXに置く必要があるんじゃないんですか? >OCX自体はそれぞれ別のプロセスでコールされるので、OCX側に領域を置くのが筋だと思いますけど、違いますか? これは決して大事ではありません。 それは設計がどのようになっていて、何をしたいかにより異なると思います。 大事なのは、 構造体の値をが別プロセスでも、容易に構造体として渡す ということでは? 共有メモリに書き込むのが逆であれば、 書くと読むを逆に行えばいいだけっしょ。
- taka_tetsu
- ベストアンサー率65% (1020/1553)
おまけ。 Type AAA AAA_int As Integer AAA_long As Long End Type Sub main() Dim a(0 To 1) As AAA MsgBox VarPtr(a(1)) - VarPtr(a(0)) End Sub 表示されるのは6ですか?8ですか?
- taka_tetsu
- ベストアンサー率65% (1020/1553)
>EXEであろうとActiveXであろうと、メモリ共有に関しての手段は一緒です。 そこは一緒なんですけど(^^;;; この手法が使えないとは書いてません。 1.複数プロセスが立ち上がった場合、どのようにして共有情報が書かれている領域のアドレスをこのサンプルで別プロセスに渡すんですか? すべてのプロセスが、EXE+OCXという構成で起動するんですよ。 > 3で別なウインドウになるので別プロセスになると思いますが…う、駄目ですか。 とChirs_Elfirdさんが書かれているのですから、当然別プロセスを意識したサンプルを提示してあげないとまずいですよね? 2.このサンプル、共有メモリを保持しているモジュール、どこという想定ですか?私にはEXEにしか見えないんですけど。 >共有メモリを扱うOCXを作る必要がありまして、 当然こういうサンプル出されるんでしたらOCXに置く必要があるんじゃないんですか? OCX自体はそれぞれ別のプロセスでコールされるので、OCX側に領域を置くのが筋だと思いますけど、違いますか? まぁ、同一プロセスなんだからどっちに置いてもいいのはわかりますけどね。 >実際にやってみました?構造体のサイズ取得方法を理解してます? >LenBでやってみてください。メモリを破壊します。 Type AAA AAA_int As Integer AAA_long As Long End Type Sub main() Dim a As AAA MsgBox Len(a) MsgBox LenB(a) End Sub Lenは6、LenBは8です。 なぜLenだとまずいか理解されてますか? 6だとAAA_longの後半2バイト欠けますよ。 欠けても問題ないとお思いですか?
- 2ch
- ベストアンサー率51% (64/125)
追記 以前のサンプルはこちらの勘違いでActiveXExeで作ってしまったんだけど、 OCX化指令を出している先輩社員もいるのだから、読み替えてくれると思って わざわざ再投稿しなかったんだけど、なんかうるさいので、作り直し。 でもほとんど差はなし っていうか、ActiveX.DLLで通るならそれからOCXなんて、当たり前にできます。 「AcitveXDLLのインターフェイスに肉付けしたのがOCX」 だから、AcitveXDLLにできて、OCXにできないなんてこたぁありえません。 AcitveXEXEも同じこと。 ↓↓↓↓↓↓↓↓ 重要ここから ↓↓↓↓↓↓↓↓ 「反論するなら、意味も無く『無茶苦茶』発言はご勘弁」 「もしあるなら、調査・結果を書いた上でお願いします」 ↑↑↑↑↑↑↑↑ 重要ここまで ↑↑↑↑↑↑↑↑↑ Project1(EXE) ├Form1 │└UserControl1(Project2を参照し、コントロールを貼り付け) └Module1(EXEとOCX兼用) Project2(OCX) ├UserControl1 └Module1(EXEとOCX兼用) '''--------------------------------------------- '''---------- Project1.Form1 ここから ---------- '''--------------------------------------------- Option Explicit Private pProcID As Long Private hProcess As Long Private pShared As Long Private pSharedLen As Long Private Type typData a As Long b As Long c As Long End Type Private pDat As typData '別アプリ起動 Private Sub Command1_Click() On Error GoTo PGMERR Dim strWk As String '共有メモリに値を書き込む If Not memWrite(hProcess, pShared, VarPtr(pDat), pSharedLen) Then Call MsgBox("共有メモリへの書き込み失敗") GoTo PGMEND End If 'ActiveXをたたく 'プロセスID/配列要素数/共有メモリ先頭ポインタ If Not Me.UserControl11.RunExec(pProcID, pShared, strWk) Then GoTo PGMEND End If MsgBox strWk PGMEND: Exit Sub PGMERR: Call MsgBox(Err.Description, vbCritical) GoTo PGMEND End Sub 'ロード Private Sub Form_Load() Me.Command1.Caption = "ActiveX起動" Me.Command1.Enabled = False 'プロセスIDを取得する If Not GetThreadProcessId(Me.hwnd, pProcID) Then Call MsgBox("プロセス情報取得失敗") GoTo PGMEND End If '共有メモリオープン pSharedLen = Len(pDat) If Not memOpen(pProcID, pSharedLen, hProcess, pShared) Then Call MsgBox("共有メモリ確保失敗") GoTo PGMEND End If 'ダミーの値をセット Call setValues Me.Command1.Enabled = True PGMEND: End Sub 'アンロード Private Sub Form_Unload(Cancel As Integer) Call memFree(hProcess, pShared) End Sub 'ダミー値セット Private Sub setValues() With pDat .a = 2 .b = 4 .c = 6 End With End Sub '''--------------------------------------------- '''---------- Project1.Form1 ここまで ---------- '''--------------------------------------------- '''--------------------------------------------- '''---------- Project2.UserControl1 ここから --- '''--------------------------------------------- Option Explicit Private Type typData a As Long b As Long c As Long End Type Private pDat As typData 'メイン部 Public Function RunExec(ByVal inProcID As Long, ByVal inShared As Long, ByRef otBuff As String) As Boolean On Error GoTo PGMERR If Not memDataRead(inProcID, inShared, otBuff) Then GoTo PGMEND End If RunExec = True PGMEND: Exit Function PGMERR: Err.Raise Err.Number, Err.Source, Err.Description, Err.HelpContext, Err.HelpFile GoTo PGMEND End Function '読み取りと画面反映 Private Function memDataRead(ByVal inAppID As Long, ByVal lngMemPointer As Long, ByRef otBuff As String) As Boolean On Error GoTo PGMEND Dim hProcess As Long Dim dwSize As Long Dim strBuff As String otBuff = "" 'メモリサイズを取得 dwSize = Len(pDat) '共有メモリ確保 If Not procOpen(inAppID, hProcess) Then Call MsgBox("共有メモリ確保失敗") GoTo PGMEND End If '共有メモリから値を読み込む If Not memRead(hProcess, lngMemPointer, VarPtr(pDat), dwSize) Then Call MsgBox("共有メモリからの読み込む失敗") GoTo PGMEND End If 'デバッグ用 With pDat strBuff = "" strBuff = strBuff & "受けデータ" & vbCrLf strBuff = strBuff & " A:" & .a & vbCrLf strBuff = strBuff & " B:" & .b & vbCrLf strBuff = strBuff & " C:" & .c & vbCrLf End With otBuff = strBuff memDataRead = True PGMEND: Call procFree(hProcess) Exit Function PGMERR: Call procFree(hProcess) Err.Raise Err.Number, Err.Source, Err.Description, Err.HelpContext, Err.HelpFile GoTo PGMEND End Function '''--------------------------------------------- '''---------- Project2.UserControl1 ここまで --- '''--------------------------------------------- '''----------------------------------------------- '''---------- Project1.Module1 ここから ---------- '''---------- Project2.Module1 ここから ---------- '''---------- 二つのプロジェクトで必要 ---------- '''----------------------------------------------- Option Explicit Private Declare Function OpenProcess Lib "kernel32" ( _ ByVal dwDesiredAccess As Long, _ ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long Private Declare Function VirtualAllocEx Lib "kernel32" ( _ ByVal hProcess As Long, _ ByVal lpAddress As Long, _ ByVal dwSize As Long, _ ByVal flAllocationType As Long, _ ByVal flProtect As Long) As Long Private Declare Function VirtualFreeEx Lib "kernel32" ( _ ByVal hProcess As Long, _ ByVal lpAddress As Long, _ ByVal dwSize As Long, _ ByVal dwFreeType As Long) As Long Private Declare Function GetWindowThreadProcessId Lib "user32" ( _ ByVal hwnd As Long, _ ByRef lpdwProcessId As Long) As Long Private Declare Function CloseHandle Lib "kernel32" ( _ ByVal hObject As Long) As Long Private Declare Function WriteProcessMemory Lib "kernel32" ( _ ByVal hProcess As Long, _ ByVal lpBaseAddress As Long, _ ByVal lpBuffer As Long, _ ByVal nSize As Long, _ ByRef lpNumberOfBytesWritten As Long) As Long Private Declare Function ReadProcessMemory Lib "kernel32" ( _ ByVal hProcess As Long, ByVal lpBaseAddress As Long, _ ByVal lpBuffer As Long, _ ByVal nSize As Long, _ ByRef lpNumberOfBytesWritten As Long) As Long Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long) Private Const STANDARD_RIGHTS_REQUIRED As Long = &HF0000 Private Const SYNCHRONIZE As Long = &H100000 Private Const PROCESS_TERMINATE As Long = &H1 Private Const PROCESS_CREATE_THREAD As Long = &H2 Private Const PROCESS_SET_SESSIONID As Long = &H4 Private Const PROCESS_VM_OPERATION As Long = &H8 Private Const PROCESS_VM_READ As Long = &H10 Private Const PROCESS_VM_WRITE As Long = &H20 Private Const PROCESS_DUP_HANDLE As Long = &H40 Private Const PROCESS_CREATE_PROCESS As Long = &H80 Private Const PROCESS_SET_QUOTA As Long = &H100 Private Const PROCESS_SET_INFORMATION As Long = &H200 Private Const PROCESS_QUERY_INFORMATION As Long = &H400 Private Const PROCESS_ALL_ACCESS As Long = STANDARD_RIGHTS_REQUIRED Or SYNCHRONIZE Or &HFFF Private Const PAGE_NOACCESS As Long = &H1 Private Const PAGE_READONLY As Long = &H2 Private Const PAGE_READWRITE As Long = &H4 Private Const PAGE_WRITECOPY As Long = &H8 Private Const PAGE_EXECUTE As Long = &H10 Private Const PAGE_EXECUTE_READ As Long = &H20 Private Const PAGE_EXECUTE_READWRITE As Long = &H40 Private Const PAGE_EXECUTE_WRITECOPY As Long = &H80 Private Const PAGE_GUARD As Long = &H100 Private Const PAGE_NOCACHE As Long = &H200 Private Const PAGE_WRITECOMBINE As Long = &H400 Private Const MEM_COMMIT As Long = &H1000 Private Const MEM_RESERVE As Long = &H2000 Private Const MEM_DECOMMIT As Long = &H4000 Private Const MEM_RELEASE As Long = &H8000 Private Const MEM_FREE As Long = &H10000 Private Const MEM_PRIVATE As Long = &H20000 Private Const MEM_MAPPED As Long = &H40000 Private Const MEM_RESET As Long = &H80000 Private Const MEM_TOP_DOWN As Long = &H100000 Private Const MEM_4MB_PAGES As Long = &H80000000 'プロセスオブジェクトのハンドルを開く Public Function procOpen(ByVal inAppID As Long, otProc As Long) As Boolean otProc = OpenProcess(PROCESS_VM_OPERATION Or PROCESS_VM_READ Or PROCESS_VM_WRITE, 0, inAppID) If otProc = 0 Then GoTo PGMEND End If procOpen = True PGMEND: End Function 'プロセスオブジェクトのハンドルを開放する Public Sub procFree(inProc As Long) Call CloseHandle(inProc) inProc = 0 End Sub '共有メモリをオープン Public Function memOpen(ByVal inAppID As Long, ByVal inSize As Long, otProc As Long, otSharedAddress As Long) As Boolean '共有メモリをクローズする Call memFree(otProc, otSharedAddress) 'プロセスオブジェクトのハンドルを開く If Not procOpen(inAppID, otProc) Then GoTo PGMEND End If '共有メモリを開放する otSharedAddress = VirtualAllocEx(otProc, 0, inSize, MEM_RESERVE Or MEM_COMMIT, PAGE_READWRITE) If otSharedAddress = 0 Then GoTo PGMEND End If memOpen = True PGMEND: If Not memOpen Then Call memFree(otProc, otSharedAddress) End If End Function '共有メモリをクローズ Public Sub memFree(inProc As Long, inSharedAddress As Long) 'クローズ Call VirtualFreeEx(inProc, inSharedAddress, 0, MEM_RELEASE) inSharedAddress = 0 'プロセスオブジェクトのハンドルを開放する Call procFree(inProc) End Sub '共有メモリ領域に書き込む Public Function memWrite(ByVal inProc As Long, ByVal inSharedAddress As Long, ByVal inMemPnt As Long, ByVal inSize As Long, Optional otSize As Long) As Boolean Dim lngSts As Long otSize = 0 lngSts = WriteProcessMemory(inProc, inSharedAddress, ByVal inMemPnt, inSize, otSize) memWrite = (lngSts <> 0) End Function '共有メモリ領域から読み込む Public Function memRead(ByVal inProc As Long, ByVal inSharedAddress As Long, ByVal inMemPnt As Long, ByVal inSize As Long, Optional otSize As Long) As Boolean Dim lngSts As Long otSize = 0 lngSts = ReadProcessMemory(inProc, inSharedAddress, ByVal inMemPnt, inSize, otSize) memRead = (lngSts <> 0) End Function 'ハンドルから、プロセスIDとスロッドIDを取得する Public Function GetThreadProcessId(ByVal inWnd As Long, Optional otProcID As Long, Optional otThred As Long) As Boolean otProcID = 0 otThred = 0 otThred = GetWindowThreadProcessId(inWnd, otProcID) GetThreadProcessId = (otThred <> 0) End Function '''----------------------------------------------- '''---------- Project1.Module1 ここまで ---------- '''---------- Project2.Module1 ここまで ---------- '''---------- 二つのプロジェクトで必要 ---------- '''-----------------------------------------------
- 2ch
- ベストアンサー率51% (64/125)
まず反論の前に実行してみてください。 ReadProcessMemoryを利用することにより、プロセスを意識しないでいいことになります。 >いくらなんでもexeとexeのサンプルを、無理矢理exeとOCXを想定したActiveXDLLのサンプルにするのは無茶苦茶かと。 EXEであろうとActiveXであろうと、メモリ共有に関しての手段は一緒です。 >>メモリサイズを取得 >> dwSize = Len(pDat) >これ、LenBにしないとアライメントずれてサイズたんないかも知れないし。 実際にやってみました?構造体のサイズ取得方法を理解してます? LenBでやってみてください。メモリを破壊します。
- taka_tetsu
- ベストアンサー率65% (1020/1553)
>もしくは共有メモリ上にこの構造体の内容をそのままCopyMemoryしてますか? >(そしたら、別の構造体に入れるアドレスは共有メモリ上をさしますよね) 大事なことを忘れてました。 OCXでの共有メモリのアドレスのマッピングの方法でMapViewOfFileを使用している場合、 プロセスごとに異なるアドレス空間に割り当てられるので、共有メモリにアドレス値を 書き込んでいても別プロセスでは無効なアドレスを指してしまっています。 これを回避するには、OCX側で共有メモリの領域をどのように確保しているか、複数回確保の要求があった場合、どのように割り当てているかの実装方法に依存してくるため、ここでは記述できません。 #2の方の参考urlのようにOCXでReadProcessMemory()もひとつの手ですが、OCX自体もChirs_Elfirdさんが作られてるんですか? > 3で別なウインドウになるので別プロセスになると思いますが…う、駄 >目ですか。 これなんですけど、とーーーーーっても気になってるんですが(^^;;;; 本当に別プロセスなんですか? 「プロセス」って単位わかってますか?ウィンドウが違ってもプロセス一緒なんてごく当たり前ですが。 前回の質問 http://oshiete1.goo.ne.jp/kotaeru.php3?q=1087139 で、 >VALIANTだとサイズが大きすぎて実用性がありませんし、 という???なことを書かれているのがかなり気になります。 Variantなら簡単に扱えるような仕様の共有メモリなのですか? で、ツッこんでいいのかなぁ・・・ 元はちゃんとしてるように見えるんだけど。 いくらなんでもexeとexeのサンプルを、無理矢理exeとOCXを想定したActiveXDLLのサンプルにするのは無茶苦茶かと。 元のサンプルはコマンドラインで別exeに共有させるメモリの先頭アドレス渡してますけど、 これじゃだめですよねぇ・・・ > 'プロセスID/配列要素数/共有メモリ先頭ポインタ > If Not objPro2.RunExec(pProcID, pShared, strWk) Then OCXの想定だったらアドレス空間一緒ですよね。 あと、構造体なんだから > '共有メモリオープン > pSharedLen = Len(pDat) と、 >メモリサイズを取得 > dwSize = Len(pDat) これ、LenBにしないとアライメントずれてサイズたんないかも知れないし。
- 2ch
- ベストアンサー率51% (64/125)
#2で挙げたサンプル見てます? そのまんま使えるはずです。 Project1(EXE) ├Form1 └Module1(EXEとOCX兼用) Project2(OCX) ├Class1 └Module1(EXEとOCX兼用) '''--------------------------------------------- '''---------- Project1.Form1 ここから ---------- '''--------------------------------------------- Option Explicit Private pProcID As Long Private hProcess As Long Private pShared As Long Private pSharedLen As Long Private Type typData a As Long b As Long c As Long End Type Private pDat As typData '別アプリ起動 Private Sub Command1_Click() On Error GoTo PGMERR Dim strParam As String Dim objPro2 As Object Dim strWk As String '共有メモリに値を書き込む If Not memWrite(hProcess, pShared, VarPtr(pDat), pSharedLen) Then Call MsgBox("共有メモリへの書き込み失敗") GoTo PGMEND End If 'ActiveXをたたく Set objPro2 = CreateObject("Project2.Class1") 'プロセスID/配列要素数/共有メモリ先頭ポインタ If Not objPro2.RunExec(pProcID, pShared, strWk) Then GoTo PGMEND End If MsgBox strWk PGMEND: Exit Sub PGMERR: Call MsgBox(Err.Description, vbCritical) GoTo PGMEND End Sub 'ロード Private Sub Form_Load() Me.Command1.Caption = "ActiveX起動" Me.Command1.Enabled = False 'プロセスIDを取得する If Not GetThreadProcessId(Me.hwnd, pProcID) Then Call MsgBox("プロセス情報取得失敗") GoTo PGMEND End If '共有メモリオープン pSharedLen = Len(pDat) If Not memOpen(pProcID, pSharedLen, hProcess, pShared) Then Call MsgBox("共有メモリ確保失敗") GoTo PGMEND End If 'ダミーの値をセット Call setValues Me.Command1.Enabled = True PGMEND: End Sub 'アンロード Private Sub Form_Unload(Cancel As Integer) Call memFree(hProcess, pShared) End Sub 'ダミー値セット Private Sub setValues() With pDat .a = 2 .b = 4 .c = 6 End With End Sub '''--------------------------------------------- '''---------- Project1.Form1 ここまで ---------- '''--------------------------------------------- '''--------------------------------------------- '''---------- Project2.Class1 ここから --------- '''--------------------------------------------- Option Explicit Private Type typData a As Long b As Long c As Long End Type Private pDat As typData 'メイン部 Public Function RunExec(ByVal inProcID As Long, ByVal inShared As Long, ByRef otBuff As String) As Boolean On Error GoTo PGMERR If Not memDataRead(inProcID, inShared, otBuff) Then GoTo PGMEND End If RunExec = True PGMEND: Exit Function PGMERR: Err.Raise Err.Number, Err.Source, Err.Description, Err.HelpContext, Err.HelpFile GoTo PGMEND End Function '読み取りと画面反映 Private Function memDataRead(ByVal inAppID As Long, ByVal lngMemPointer As Long, ByRef otBuff As String) As Boolean On Error GoTo PGMEND Dim hProcess As Long Dim dwSize As Long Dim strBuff As String otBuff = "" 'メモリサイズを取得 dwSize = Len(pDat) '共有メモリ確保 If Not procOpen(inAppID, hProcess) Then Call MsgBox("共有メモリ確保失敗") GoTo PGMEND End If '共有メモリから値を読み込む If Not memRead(hProcess, lngMemPointer, VarPtr(pDat), dwSize) Then Call MsgBox("共有メモリからの読み込む失敗") GoTo PGMEND End If 'デバッグ用 With pDat strBuff = "" strBuff = strBuff & "受けデータ" & vbCrLf strBuff = strBuff & " A:" & .a & vbCrLf strBuff = strBuff & " B:" & .b & vbCrLf strBuff = strBuff & " C:" & .c & vbCrLf End With otBuff = strBuff memDataRead = True PGMEND: Call procFree(hProcess) Exit Function PGMERR: Call procFree(hProcess) Err.Raise Err.Number, Err.Source, Err.Description, Err.HelpContext, Err.HelpFile GoTo PGMEND End Function '''--------------------------------------------- '''---------- Project2.Class1 ここまで --------- '''--------------------------------------------- '''----------------------------------------------- '''---------- Project1.Module1 ここから ---------- '''---------- Project2.Class1 ここから ---------- '''---------- 二つのプロジェクトで必要 ---------- '''----------------------------------------------- Option Explicit Private Declare Function OpenProcess Lib "kernel32" ( _ ByVal dwDesiredAccess As Long, _ ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long Private Declare Function VirtualAllocEx Lib "kernel32" ( _ ByVal hProcess As Long, _ ByVal lpAddress As Long, _ ByVal dwSize As Long, _ ByVal flAllocationType As Long, _ ByVal flProtect As Long) As Long Private Declare Function VirtualFreeEx Lib "kernel32" ( _ ByVal hProcess As Long, _ ByVal lpAddress As Long, _ ByVal dwSize As Long, _ ByVal dwFreeType As Long) As Long Private Declare Function GetWindowThreadProcessId Lib "user32" ( _ ByVal hwnd As Long, _ ByRef lpdwProcessId As Long) As Long Private Declare Function CloseHandle Lib "kernel32" ( _ ByVal hObject As Long) As Long Private Declare Function WriteProcessMemory Lib "kernel32" ( _ ByVal hProcess As Long, _ ByVal lpBaseAddress As Long, _ ByVal lpBuffer As Long, _ ByVal nSize As Long, _ ByRef lpNumberOfBytesWritten As Long) As Long Private Declare Function ReadProcessMemory Lib "kernel32" ( _ ByVal hProcess As Long, ByVal lpBaseAddress As Long, _ ByVal lpBuffer As Long, _ ByVal nSize As Long, _ ByRef lpNumberOfBytesWritten As Long) As Long Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long) Private Const STANDARD_RIGHTS_REQUIRED As Long = &HF0000 Private Const SYNCHRONIZE As Long = &H100000 Private Const PROCESS_TERMINATE As Long = &H1 Private Const PROCESS_CREATE_THREAD As Long = &H2 Private Const PROCESS_SET_SESSIONID As Long = &H4 Private Const PROCESS_VM_OPERATION As Long = &H8 Private Const PROCESS_VM_READ As Long = &H10 Private Const PROCESS_VM_WRITE As Long = &H20 Private Const PROCESS_DUP_HANDLE As Long = &H40 Private Const PROCESS_CREATE_PROCESS As Long = &H80 Private Const PROCESS_SET_QUOTA As Long = &H100 Private Const PROCESS_SET_INFORMATION As Long = &H200 Private Const PROCESS_QUERY_INFORMATION As Long = &H400 Private Const PROCESS_ALL_ACCESS As Long = STANDARD_RIGHTS_REQUIRED Or SYNCHRONIZE Or &HFFF Private Const PAGE_NOACCESS As Long = &H1 Private Const PAGE_READONLY As Long = &H2 Private Const PAGE_READWRITE As Long = &H4 Private Const PAGE_WRITECOPY As Long = &H8 Private Const PAGE_EXECUTE As Long = &H10 Private Const PAGE_EXECUTE_READ As Long = &H20 Private Const PAGE_EXECUTE_READWRITE As Long = &H40 Private Const PAGE_EXECUTE_WRITECOPY As Long = &H80 Private Const PAGE_GUARD As Long = &H100 Private Const PAGE_NOCACHE As Long = &H200 Private Const PAGE_WRITECOMBINE As Long = &H400 Private Const MEM_COMMIT As Long = &H1000 Private Const MEM_RESERVE As Long = &H2000 Private Const MEM_DECOMMIT As Long = &H4000 Private Const MEM_RELEASE As Long = &H8000 Private Const MEM_FREE As Long = &H10000 Private Const MEM_PRIVATE As Long = &H20000 Private Const MEM_MAPPED As Long = &H40000 Private Const MEM_RESET As Long = &H80000 Private Const MEM_TOP_DOWN As Long = &H100000 Private Const MEM_4MB_PAGES As Long = &H80000000 'プロセスオブジェクトのハンドルを開く Public Function procOpen(ByVal inAppID As Long, otProc As Long) As Boolean otProc = OpenProcess(PROCESS_VM_OPERATION Or PROCESS_VM_READ Or PROCESS_VM_WRITE, 0, inAppID) If otProc = 0 Then GoTo PGMEND End If procOpen = True PGMEND: End Function 'プロセスオブジェクトのハンドルを開放する Public Sub procFree(inProc As Long) Call CloseHandle(inProc) inProc = 0 End Sub '共有メモリをオープン Public Function memOpen(ByVal inAppID As Long, ByVal inSize As Long, otProc As Long, otSharedAddress As Long) As Boolean '共有メモリをクローズする Call memFree(otProc, otSharedAddress) 'プロセスオブジェクトのハンドルを開く If Not procOpen(inAppID, otProc) Then GoTo PGMEND End If '共有メモリを開放する otSharedAddress = VirtualAllocEx(otProc, 0, inSize, MEM_RESERVE Or MEM_COMMIT, PAGE_READWRITE) If otSharedAddress = 0 Then GoTo PGMEND End If memOpen = True PGMEND: If Not memOpen Then Call memFree(otProc, otSharedAddress) End If End Function '共有メモリをクローズ Public Sub memFree(inProc As Long, inSharedAddress As Long) 'クローズ Call VirtualFreeEx(inProc, inSharedAddress, 0, MEM_RELEASE) inSharedAddress = 0 'プロセスオブジェクトのハンドルを開放する Call procFree(inProc) End Sub '共有メモリ領域に書き込む Public Function memWrite(ByVal inProc As Long, ByVal inSharedAddress As Long, ByVal inMemPnt As Long, ByVal inSize As Long, Optional otSize As Long) As Boolean Dim lngSts As Long otSize = 0 lngSts = WriteProcessMemory(inProc, inSharedAddress, ByVal inMemPnt, inSize, otSize) memWrite = (lngSts <> 0) End Function '共有メモリ領域から読み込む Public Function memRead(ByVal inProc As Long, ByVal inSharedAddress As Long, ByVal inMemPnt As Long, ByVal inSize As Long, Optional otSize As Long) As Boolean Dim lngSts As Long otSize = 0 lngSts = ReadProcessMemory(inProc, inSharedAddress, ByVal inMemPnt, inSize, otSize) memRead = (lngSts <> 0) End Function 'ハンドルから、プロセスIDとスロッドIDを取得する Public Function GetThreadProcessId(ByVal inWnd As Long, Optional otProcID As Long, Optional otThred As Long) As Boolean otProcID = 0 otThred = 0 otThred = GetWindowThreadProcessId(inWnd, otProcID) GetThreadProcessId = (otThred <> 0) End Function '''----------------------------------------------- '''---------- Project1.Module1 ここまで ---------- '''---------- Project2.Class1 ここまで ---------- '''---------- 二つのプロジェクトで必要 ---------- '''-----------------------------------------------
- 1
- 2
お礼
つまり…BufNameをバッファ名として渡された場合、BufName_1、BufName_2、みたいな感じでOCX内で定義してバッファを並べればいい訳ですね?で、それを管理する構造体を作り、読み込む構造体の名前を格納しておく…ってなんだか分かったような分かって無いような言い方してますが、出来てるので分かったんだと思います。まあ、アドレスにこだわったのがそもそもの間違いだと… お二人には大変ご迷惑をおかけいたしました。おかげさまで足りない頭でも何とか完成には至れました…分かってみれば単純な理屈でしたけど。何故これが思いつかなかったのかと… 初めからこの実装を出していれば話もこじれずに済んだのかもしれませんが…色々と勉強させていただいただきました。Lenやポインタの事もどこかでそのうち参考にさせていただきます。 本当にありがとうございました。