Quantcast
Channel: C#タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9749

C#,C++ アプリケーション間で共有メモリに構造体を読み書きしてみる

$
0
0

前置き

当記事は、前回の記事「C++アプリケーションとC#アプリケーションで値をやり取りしてみる」の続編です。

前回の記事では、動的に確保した共有メモリで直接値を読み書きしましたが、
そのままではかなり不便です。

そこで今回は共有メモリに構造体を書き込み、そこから読み書きしてみたいと思います。

Untitled Diagram (4).png

実践 - C#側

まずは、C# .NET Framework WinForm 側で簡易的なフォームを作成し、単体で実践してみます。
ソースコードは以下の通りです。

Form1.cs
usingSystem;usingSystem.Collections.Generic;usingSystem.ComponentModel;usingSystem.Data;usingSystem.Drawing;usingSystem.IO;usingSystem.IO.MemoryMappedFiles;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;usingSystem.Windows.Forms;namespaceQuiitaShareMemoryStruct{publicpartialclassForm1:Form{////////////////////////////////////////////////////////////////////////// 必要なものを定義////////////////////////////////////////////////////////////////////////MemoryMappedFileshare_mem=null;MemoryMappedViewAccessoraccessor=null;////////////////////////////////////////////////////////////////////////// 共有メモリ名////////////////////////////////////////////////////////////////////////conststringsharedMemoryName="MySharedMemory";////////////////////////////////////////////////////////////////////////// 使用する構造体////////////////////////////////////////////////////////////////////////publicstruct_MY_DATA_STRUCT{publicintmyInt32;publicfloatmyFloat;publicboolmyBool;}////////////////////////////////////////////////////////////////////////// コンストラクタ////////////////////////////////////////////////////////////////////////publicForm1(){InitializeComponent();}privatevoidForm1_Load(objectsender,EventArgse){}////////////////////////////////////////////////////////////////////////// 「共有メモリを読む」ボタンをクリックしたときに発生するイベント////////////////////////////////////////////////////////////////////////privatevoidbtnRead_Click(objectsender,EventArgse){varresult=ReadSharedMemoryAsStruct<_MY_DATA_STRUCT>(sharedMemoryName);MessageBox.Show(string.Format("MyInt32: {0}\nMyFloat: {1}\nMyBool: {2}",result.myInt32,result.myFloat,result.myBool));}////////////////////////////////////////////////////////////////////////// 「共有メモリに書き込み」ボタンをクリックしたときに発生するイベント////////////////////////////////////////////////////////////////////////privatevoidbtnWrite_Click(objectsender,EventArgse){_MY_DATA_STRUCTmyStruct=new_MY_DATA_STRUCT();myStruct.myInt32=(int)numericUpDown1.Value;floatres;myStruct.myFloat=float.TryParse(textBox1.Text,outres)?res:999.0f;myStruct.myBool=checkBox1.Checked;if(!WriteSharedMemoryAsStruct<_MY_DATA_STRUCT>(sharedMemoryName,myStruct,true)){MessageBox.Show("書き込みに失敗しました。");}else{MessageBox.Show("書き込みに成功しました。");}}////////////////////////////////////////////////////////////////////////// 共有メモリを構造体として読み取るジェネリック関数////////////////////////////////////////////////////////////////////////privateTReadSharedMemoryAsStruct<T>(stringsharedMemoryName,boolcreateOrOpen=false)whereT:struct{//構造体を定義Tresult=newT();try{if(share_mem==null){if(createOrOpen){share_mem=MemoryMappedFile.CreateOrOpen(sharedMemoryName,1024*10);}else{share_mem=MemoryMappedFile.OpenExisting(sharedMemoryName);}}if(accessor==null){accessor=share_mem.CreateViewAccessor();}accessor?.Read(0,outresult);returnresult;}catch(FileNotFoundExceptionex){Console.WriteLine("共有メモリが見つかりませんでした");returnresult;}catch(Exceptionex){Console.WriteLine(ex.Message);returnresult;}}////////////////////////////////////////////////////////////////////////// 共有メモリに構造体として書き込むジェネリック関数////////////////////////////////////////////////////////////////////////privateboolWriteSharedMemoryAsStruct<T>(stringsharedMemoryName,TtargetStruct,boolcreateOrOpen=false)whereT:struct{try{if(createOrOpen){share_mem=MemoryMappedFile.CreateOrOpen(sharedMemoryName,1024*10);}else{share_mem=MemoryMappedFile.OpenExisting(sharedMemoryName);}if(accessor==null){accessor=share_mem.CreateViewAccessor();}accessor.Write(0,reftargetStruct);returntrue;}catch(FileNotFoundExceptionex){Console.WriteLine("共有メモリが見つかりませんでした");returnfalse;}catch(Exceptionex){Console.WriteLine(ex.Message);returnfalse;}}////////////////////////////////////////////////////////////////////////// リソースの破棄////////////////////////////////////////////////////////////////////////privatevoidForm1_FormClosing(objectsender,FormClosingEventArgse){accessor?.Dispose();share_mem?.Dispose();}}}

解説

ReadSharedMemoryAsStruct() 関数

こちらは、該当共有メモリに対して構造体として読み取る関数です。

まず初めに、関数の結果として出力する構造体メンバ変数を定義します。
今回はジェネリック関数として定義しましたので、ここでいうTは構造体であるということが保証されています。

where T : struct

Tresult=newT();

次に、MemoryMappedFileMemoryMappedViewAccessornullであれば新規生成し、
アクセサを使用して該当共有メモリに対して書き込みを行います。
第一引数はpositionつまりオフセットです。
今回は構造体のみを書き込むので、0とします。
第二引数で構造体を受け取ります。

accessor.Read(0,outres);

使用例:

varresult=ReadSharedMemoryAsStruct<_YOUR_STRUCT>("yourSharedMemoryName");

WriteSharedMemoryAsStruct() 関数

こちらは、該当共有メモリに対して構造体として書き込む関数です。

まず初めに、読み取りと同じようにヌルチェックを行います。

(省略)

アクセサを使用して該当共有メモリに対して書き込みを行います。
第一引数はpositionつまりオフセットです。
今回は構造体のみを書き込むので、0とします。
第二引数には、関数で受け取った構造体T targetStructの参照を渡します。

accessor.Write(0,reftargetStruct);

リソースの開放

使い終わったリソースはきちんと解放してあげます。

accessor?.Dispose();share_mem?.Dispose();

実行結果

fはパースしてくれないらしく、float.TryParse()に失敗して999が書き込まれちゃってますが、
無事成功しました。

eqhsn-z2z96.gif

実践 - C++側

C++側でも単体で実行してみます。

main.cpp
#include <iostream>
#include <Windows.h>
#define CONSOLE_PAUSE() system("pause")
#define VOID void
#define BOOLEAN bool
////////////////////////////////////////////////////////////////////////// 構造体////////////////////////////////////////////////////////////////////////typedefstruct_MY_DATA_STRUCT{intmyInt32;floatmyFloat;boolmyBool;}MY_DATA_STRUCT;////////////////////////////////////////////////////////////////////////// 必要なものを定義////////////////////////////////////////////////////////////////////////constexprautoSHARED_MEMORY_NAME=L"MySharedMemory";constexprautoSHARED_MEMORY_SIZE=1024*10;staticHANDLEhSharedMemory=NULL;MY_DATA_STRUCT*response;////////////////////////////////////////////////////////////////////////// 共有メモリを作成する関数////////////////////////////////////////////////////////////////////////BOOLEANCreateSharedMemory(constwchar_t*sharedMemoryName,DWORDsize){if(hSharedMemory){returnFALSE;}hSharedMemory=CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,size,sharedMemoryName);if(!hSharedMemory||hSharedMemory==INVALID_HANDLE_VALUE){returnFALSE;}returnTRUE;}////////////////////////////////////////////////////////////////////////// ハンドルの初期化////////////////////////////////////////////////////////////////////////BOOLEANInitializeSharedMemory(){hSharedMemory=OpenFileMapping(FILE_MAP_ALL_ACCESS,FALSE,SHARED_MEMORY_NAME);if(!hSharedMemory||hSharedMemory==INVALID_HANDLE_VALUE){returnFALSE;}returnTRUE;}////////////////////////////////////////////////////////////////////////// ハンドルの破棄////////////////////////////////////////////////////////////////////////VOIDUnInitializeSharedMemory(){if(hSharedMemory||hSharedMemory!=INVALID_HANDLE_VALUE){CloseHandle(hSharedMemory);}}////////////////////////////////////////////////////////////////////////// 共有メモリの読み取り////////////////////////////////////////////////////////////////////////BOOLEANReadSharedMemory(){if(!hSharedMemory){returnFALSE;}response=(MY_DATA_STRUCT*)MapViewOfFile(hSharedMemory,FILE_MAP_ALL_ACCESS,NULL,NULL,SHARED_MEMORY_SIZE);if(response==NULL||!response){returnFALSE;}returnTRUE;}////////////////////////////////////////////////////////////////////////// 共有メモリの書き込み////////////////////////////////////////////////////////////////////////BOOLEANWriteSharedMemory(_MY_DATA_STRUCTwriteit){if(!response||!hSharedMemory){returnFALSE;}*response=writeit;returnTRUE;}intmain(){SetConsoleTitleA("Title");std::cout<<"Hello SharedMemory!\nなにかキーを押してください。";std::cin.get();if(!CreateSharedMemory(SHARED_MEMORY_NAME,SHARED_MEMORY_SIZE)){std::cout<<"共有メモリの作成に失敗しました。\n";gotoFINISH;}if(!InitializeSharedMemory()){std::cout<<"共有メモリの初期化に失敗しました。\n";gotoFINISH;}if(!ReadSharedMemory()){std::cout<<"共有メモリの読み取りに失敗しました。\n";gotoFINISH;}_MY_DATA_STRUCTs;s.myInt32=333;s.myFloat=634.f;s.myBool=TRUE;if(!WriteSharedMemory(s)){std::cout<<"共有メモリの書き込みに失敗しました。\n";UnInitializeSharedMemory();CONSOLE_PAUSE();}printf("=== Read ===\nmyInt32: %u\nmyFloat: %f\nmyBool: %u\n",response->myInt32,response->myFloat,response->myBool);FINISH:UnInitializeSharedMemory();CONSOLE_PAUSE();}

解説

CreateSharedMemory() 関数

CreateFileMapping()でハンドルを生成します。

HANDLEhSharedMemory=CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,size,sharedMemoryName);

InitializeSharedMemory() 関数

OpenFileMapping()でハンドルを開きます。

HANDLEhSharedMemory=OpenFileMapping(FILE_MAP_ALL_ACCESS,FALSE,SHARED_MEMORY_NAME);

UnInitializeSharedMemory() 関数

リソースの開放です。

CloseHandle(hSharedMemory);

ReadSharedMemory() 関数

共有メモリから構造体を読み取ります。

autoresponse=(MY_DATA_STRUCT*)MapViewOfFile(hSharedMemory,FILE_MAP_ALL_ACCESS,NULL,NULL,SHARED_MEMORY_SIZE);

WriteSharedMemory() 関数

共有メモリに構造体を書き込みます。

_MY_DATA_STRUCTwriteit;*response=writeit;

実行結果

_MY_DATA_STRUCTs;s.myInt32=333;s.myFloat=634.f;s.myBool=TRUE;WriteSharedMemory(s);printf("=== Read ===\nmyInt32: %u\nmyFloat: %f\nmyBool: %u\n",response->myInt32,response->myFloat,response->myBool);

無事成功しました。

image.png

C#とC++クロスでやってみる

こちらも問題なく動作しました。

image.png

最後に

最後までご覧いただきありがとうございました。
コードミス/誤字・脱字や間違った情報がございましたら、お手数ですがコメント欄にてご指摘いただけますと幸いです。


Viewing all articles
Browse latest Browse all 9749

Trending Articles