■ 構造体へのRtlMoveMemoryでOutOfMemory?

[Visual Basic Q & A 掲示板] [過去ログの一覧]


zzz 2008/02/16(土) 17:22:39 <初心者>
VB.net2003にて、FORTRANのexeファイルが出力した文字列を
共有メモリを介してVBで取得する機能を作っています。
タイマーにより逐次データを取得する仕組みなのですが
徐々にメモリを消費し、OutOfMemoryとなってしまいます。

Private Declare Sub CopyMemoryStruct Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As SEND_DATA, ByVal Source As Integer, ByVal Length As Integer)

  '構造体定義
  <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
  Public Structure STRUCT_DATA
    <VBFixedString(DataLength), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=DataLength)> _
    Dim msg As String
    ReadOnly Property getMsg() As String
      Get
        Return msg
      End Get
    End Property
    Sub msgSet(ByVal str As String)
      msg = str
    End Sub
  End Structure

  'データ取得メソッド
  Private Sub getDataMethod(...)

    Dim data As STRUCT_DATA
    Dim str As String
    Dim lpFileMap As Integer  '共有メモリのマッピングアドレス
    
    '構造体にデータを格納
    CopyMemoryStruct(data, lpFileMap, Marshal.SizeOf(data))
    
    str = sendData.getMsg()

    'ここでstrを用いた処理を行いますが何もなくても
    'OutOfMemoryになります

  End Sub

複数のマッピングファイルに対してこのメソッドを呼ぶ構成です。
マッピングファイルのオープン/クローズは
このメソッドの呼び出し元で行っています。
上のプログラムで何かしら原因となる箇所がありましたら
ご指摘いただけますでしょうか。
このメソッドを抜けたときに構造体dataは
メモリから解放されると思っているのですが。

VBでの構造体及び共有メモリについて明るくないので
的外れな質問をしているかもしれませんが、
どうぞよろしくお願いいたします。

やじゅ 2008/02/16(土) 18:12:48 <上級者>
ByVal Source As Integer?はいいのかな

Private Declare Sub CopyMemory Lib "kernel32" 
Alias "RtlMoveMemory" ( _ 
Destination As Any, Source As Any, ByVal length As Long)

やじゅ 2008/02/16(土) 18:35:27 <上級者>
As AnyはVB6でしたね、ByVal Source As Longとか

魔界の仮面弁士 2008/02/16(土) 21:57:26 <常連>
> Dim lpFileMap As Integer  '共有メモリのマッピングアドレス
そういった物に対しては、IntPtr 型を使うべきかと。

> ご指摘いただけますでしょうか。
ソースから想像すると、共有メモリから得たい値は ANSI 形式の文字列の
ようですが、そこに含まれるデータは、ASCII 文字だけですか?
それとも、2バイト文字を含んだ Shift_JIS データでしょうか?

もし、2バイト文字を含んでいるのだとしたら、構造体に指定している
DataLength というのは、「バイト数」と「文字数」のどちらの意図ですか?


> VBでの構造体及び共有メモリについて明るくないので
構造体のマーシャリングは、それなりの前提知識が必要ですよ。
特に、文字列を含んでいるような場合には。

構造体の前に、単純なバイト配列で受け取る事から始めては如何でしょう? 
たとえば、

 Dim ptr As IntPtr = [参照先のアドレス]

 Dim buf(DataLength - 1) As Byte
 Marshal.Copy(ptr, buf, 0, DataLength)
 Dim str As String = System.Text.Encoding.GetEncoding("Shift_JIS").GetString(buf)

のようにするとか。
(検証しようが無いので、保証はできませんけれども)


> 上のプログラムで何かしら原因となる箇所がありましたら
まずは、プログラムの仕様(共有メモリ上のデータ配置など)を
提示してもらわないことには、どうにもならないです。
(属性の指定が正しく行われているかどうかすら、判断できません)


そもそも、STRUCT_DATA の実装意図もわかりません。

(1) getMsg とくれば、対義語 は setMsg だと思うのですが、
 なぜ、msgSet なのでしょうか? (まぁ、これは本題とは無関係ですが)

(2) msg フィールドを使って、文字列にアクセスできるというのに、
 わざわざ、プロパティ/メソッドを用意しているのはなぜですか?

(3) 代入をメソッド化しているのに、取得がメソッドでは無いのは何故ですか?
 (というよりも、プロパティを Get/Set の両対応にすれば済むような)


>> やじゅさん
ByVal Source As Long ではマズイのでは…?

魔界の仮面弁士 2008/02/16(土) 22:27:46 <常連>
それからここは [VB2-VB6専用] の掲示板なので、2003 は対象外です。

もし続けるのであれば、隣の掲示板に移動してくださいね。

zzz 2008/02/17(日) 12:18:47 <初心者>
やじゅさん
魔界の仮面弁士さん

ご意見ありがとうございます。
参考にさせていただきます。

あと、質問内容のアバウトさや板間違いについては
申し訳ありません。以後、気をつけます。

毎週金曜日はポイント最大3倍!さらに4倍のチャンスも!

Programming Library