mengineer's blog

ニッチなネタばかりですが。

C# MemoryMappedFilesを使ってみる

例えばアプリAからアプリBへデータを渡したい時の話。

これまでクリップボード経由で実現させていました、 こんな感じ。

1. アプリA データをクリップボードにコピー
2. アプリB ちょっとだけ待つ(200mS程度:おまじないですね)
3. アプリB クリップボードからデータを貼り付け

難点は、クリップボードってAB以外のアプリも使ってる訳なので、
想定外に思わぬところでデータが消えたり、化けてしまったり。

クリップボード以外で別の手法は無いものだろうか? ってことで、
MemoryMappedFileを使ってみたのが、今回のネタになります。

詳細は"C# MemoryMappedFiles" 等で検索してみて下さい、
今回も色々なサイトを参考にさせて頂きました、感謝。

データ送信側(アプリA)

button1を押すと現在の日時をMemoryMappedFileに書き込みます。

public partial class Form1 : Form
{
private MemoryMappedFile mmf;
public Form1()
{
InitializeComponent();
try
{
mmf = MemoryMappedFile.CreateNew("Test", 1024);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
this.Close();
}
}
private void button1_Click(object sender, EventArgs e)
{
try
{
using (var stream = mmf.CreateViewStream())
using (StreamWriter sw = new StreamWriter(stream))
{
DateTime dt = DateTime.Now;
sw.Write(dt.ToString());
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
mmf.Dispose();
}
}
view raw Form1.cs hosted with ❤ by GitHub

3行目でMemoryMappedFileとしてmmfを定義し、10行目でOpen。
TestがMemoryMappedFileの名称、1024がサイズです。(1024Byte)

22、23行目で、mmfStreamWriterとして使えるようにします、
これにより、普通のテキストファイルみたいに扱えるので簡単。

36行目、終了時にDisposeするのを忘れずに。

データ受信側(アプリB)

button1を押すと共有メモリを読み出し、textBox1に表示します。

public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
textBox1.Text = "";
try
{
using (var mmf = MemoryMappedFile.OpenExisting("Test"))
using (var stream = mmf.CreateViewStream())
using (StreamReader sr = new StreamReader(stream))
{
while (!sr.EndOfStream)
{
textBox1.Text = sr.ReadLine();
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
view raw Form1.cs hosted with ❤ by GitHub

13行目でMemoryMappedFile mmfをOpenします、
アプリAでOpen済みなので、MemoryMappedFile.OpenExistingを使用、
もちろんアプリAと同じ”Test"を指定することを忘れずに。

14、16行目で、mmfをStreamReaderとして使えるようにします、
これにより、受信側もテキストファイルを読む感覚で扱えます。

あと送信側との違いは、ボタンを押す毎にMemoryMappedFileをOpenし、
読み終わった時点で(usingで)閉じていることです。
(送信側は、Formを閉じるまではOpenしっぱなし)

アプリBの実行結果は、こんな感じ。

f:id:mengineer:20180217144201p:plain

もし送信側のアプリAが終了した状態でボタンを押すと、
MemoryMappedFileがOpen出来ないので、”ファイルが見つかりません”
みたいなエラーが表示されます。

ちなみに、上記はSystem.IO.MemoryMappedFiles.MemoryMappedFileという
クラスを使っていますが、.NET4.0から追加されたもののようです。

思ったより簡単にMemoryMappedFileが扱えることが判りました!