忍者ブログ

VB.NET-TIPS などプログラミングについて

VB.NETのTIPS(小技集)を中心に、その他のプログラミングについて少し役に立つ情報を発信します。いわゆる個人的な忘備録ですが、みなさんのお役に立てれば幸いです。

共有メモリとしてのメモリマップドファイルの使い方2・構造体の書込と読込

メモリマップドファイルを使ったバイト配列の読み書きの記事は前回紹介しましたが、 今回は構造体をそのままで読み書きする例を示します。

尚、今回は、実際のデータファイルを指定する方法で、メモリマップドファイルを使います。 ファイルに書込んだ後で、「秀丸」などのエディタで内容を確認する為です。

以下のソースにその関数を記します。
このフォームは、ボタンを2個と、テキストボックスを1個配置します。 Button1 はテキストボックスの文字列をInteger型データに設定し、メモリマップドファイルへの書込み処理を行い、 Button2 はメモリマップドファイルから読込みを行います。

MemoryMappedFile.CreateFromFile は実際のファイル名とマップ名とメモリ領域のサイズを指定し、メモリマップドファイルのオープンを行います。 その後、MemoryMappedFile.CreateViewAccessor のアクセサを使って、メモリ空間への読み書きを行います。

共有メモリとしてのメモリマップドファイルの使い方2・構造体の書込と読込

Imports System.IO
Imports System.IO.MemoryMappedFiles
Imports System.Runtime.InteropServices

Public Class frmMemMapStruc

    '簡単な構造体
    <StructLayout(LayoutKind.Sequential, Pack:=1)> _
    Public Structure StrucTest
        Public bytData As Byte      'Byte型データ
        Public intData As Integer   'Integer型データ
        Public lngData As Long      'Long型データ
        Public dblData As Double    'Double型データ
        Public decData As Decimal   'Decimal型データ
    End Structure

    'テキストボックスの内容をメモリマップドファイルに書込む
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        'メモリ上にメモリマップドファイルをオープンする
        Dim mmf = MemoryMappedFile.CreateFromFile("MemMapFileTest.dat", FileMode.OpenOrCreate, "MemMapFileTest", 1024)
        'メモリマップドファイルのビューに対応するアクセサ生成
        Dim acc As MemoryMappedViewAccessor = mmf.CreateViewAccessor()
        '構造体宣言と値設定
        Dim StrucT As StrucTest
        StrucT.bytData = &H55
        StrucT.intData = CInt(Me.TextBox1.Text)
        StrucT.lngData = 1000000L
        StrucT.dblData = 200.123
        StrucT.decData = 1000.456
        'アクセサで構造体をメモリマップドファイルへ書込み
        acc.Write(0, StrucT)
        'アクセサ、メモリマップドファイルの廃棄
        acc.Dispose()
        mmf.Dispose()
    End Sub

    'メモリマップドファイルの内容を読込んで表示する
    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        'メモリ上にメモリマップドファイルをオープンする
        Dim mmf = MemoryMappedFile.CreateFromFile("MemMapFileTest.dat", FileMode.OpenOrCreate, "MemMapFileTest", 1024)
        'メモリマップドファイルのビューに対応するアクセサ生成
        Dim acc As MemoryMappedViewAccessor = mmf.CreateViewAccessor()
        'アクセサで構造体にメモリマップドファイルから読込み
        Dim StrucT As StrucTest
        acc.Read(0, StrucT)
        'アクセサ、メモリマップドファイルの廃棄
        acc.Dispose()
        mmf.Dispose()
        '構造体の値を表示
        Dim strData As String = ""
        strData &= "bytData:" & StrucT.bytData.ToString("X2") & vbCrLf
        strData &= "intData:" & StrucT.intData.ToString & vbCrLf
        strData &= "lngData:" & StrucT.lngData.ToString & vbCrLf
        strData &= "dblData:" & StrucT.dblData.ToString & vbCrLf
        strData &= "decData:" & StrucT.decData.ToString & vbCrLf
        MsgBox("Read:" & strData)
    End Sub

End Class

MemMapFileTest.dat のファイルの内容をバイナリ表示で行うと以下の様になっています。 (「秀丸エディタ」で表示)

このソースで注意するのは、構造体のデータの読み書き処理が終わったところで、 アクセサ及び、メモリマップドファイルのインスタンスの廃棄を行っているところです。
この処理をしないと、各ボタンクリック処理でのプロセスがデータファイルを捕まえたままになって、 MemoryMappedFile.CreateFromFile のところでエラーが発生します。(ファイルのロックが掛かった様な状態)
以下がその様子を示す画像です。(ボタン1のクリック処理を行い、その後で、ボタン2のクリックを行った時の様子です)


書込み、及び読込みの処理を別々のプロセスに分けた場合に、書込み処理中に読込み処理が行われる可能性があります。 また、その逆も考えられますので、MemoryMappedFile.CreateFromFile でエラーが発生した場合には、その後の処理はしない方がいいと思います。

今回の構造体は単純なInteger型やLong型などの全て値型のデータ型ばかりなので、 配列データは出来ないものかと思って以下の様にソースを変更しました。 (Byte型配列データの部分を追加)

Imports System.IO
Imports System.IO.MemoryMappedFiles
Imports System.Runtime.InteropServices

Public Class frmMemMapStruc

    '簡単な構造体
    <StructLayout(LayoutKind.Sequential, Pack:=1)> _
    Public Structure StrucTest
        Public bytData As Byte      'Byte型データ
        Public intData As Integer   'Integer型データ
        Public lngData As Long      'Long型データ
        Public dblData As Double    'Double型データ
        Public decData As Decimal   'Decimal型データ
        Public arrData() As Byte    'Byte型配列データ
    End Structure

    'テキストボックスの内容をメモリマップドファイルに書込む
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        'メモリ上にメモリマップドファイルをオープンする
        Dim mmf = MemoryMappedFile.CreateFromFile("MemMapFileTest.dat", FileMode.OpenOrCreate, "MemMapFileTest", 1024)
        'メモリマップドファイルのビューに対応するアクセサ生成
        Dim acc As MemoryMappedViewAccessor = mmf.CreateViewAccessor()
        '構造体宣言と値設定
        Dim StrucT As StrucTest
        StrucT.bytData = &H55
        'StrucT.intData = 100
        StrucT.intData = CInt(Me.TextBox1.Text)
        StrucT.lngData = 1000000L
        StrucT.dblData = 200.123
        StrucT.decData = 1000.456
        StrucT.arrData = {&H0, &H11, &H55, &HAA}
        'アクセサで構造体をメモリマップドファイルへ書込み
        acc.Write(0, StrucT)
        'アクセサ、メモリマップドファイルの廃棄
        acc.Dispose()
        mmf.Dispose()
    End Sub

    'メモリマップドファイルの内容を読込んで表示する
    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        'メモリ上にメモリマップドファイルをオープンする
        Dim mmf = MemoryMappedFile.CreateFromFile("MemMapFileTest.dat", FileMode.OpenOrCreate, "MemMapFileTest", 1024)
        'メモリマップドファイルのビューに対応するアクセサ生成
        Dim acc As MemoryMappedViewAccessor = mmf.CreateViewAccessor()
        'アクセサで構造体にメモリマップドファイルから読込み
        Dim StrucT As StrucTest
        acc.Read(0, StrucT)
        'アクセサ、メモリマップドファイルの廃棄
        acc.Dispose()
        mmf.Dispose()
        '構造体の値を表示
        Dim strData As String = ""
        strData &= "bytData:" & StrucT.bytData.ToString("X2") & vbCrLf
        strData &= "intData:" & StrucT.intData.ToString & vbCrLf
        strData &= "lngData:" & StrucT.lngData.ToString & vbCrLf
        strData &= "dblData:" & StrucT.dblData.ToString & vbCrLf
        strData &= "decData:" & StrucT.decData.ToString & vbCrLf
        MsgBox("Read:" & vbCrLf & strData)
    End Sub

End Class


このソースを実行すると以下の様にVBから叱られてしまいました。


アクセサの構造体の書き込みは、構造体の中に参照データが存在する時にはできない様です。 配列データは構造体の arrData 変数は配列データの実体を持っているわけでは無く、 ポインタ的な参照を持っているだけなので、当然だとは思います。

しかし、参照データを含む構造体の場合にはマーシャルの考え方を使えばできる様ですので、 後日また公開したいと思います。

関連する記事

共有メモリとしてのメモリマップドファイルの使い方(MemoryMappedFile,CreateOrOpen,CreateViewAccessor)
共有メモリとしてのメモリマップドファイルの使い方3・配列を持つ構造体の書込と読込

おすすめ本

PR

コメント

コメントを書く