共有メモリ・クラス
とりあえず、ざっと作ってみました。
かなり手抜きですが、自分用のライブラリを作るときの参考にでもどうぞ。
// ShareInfoService.h #pragma once using namespace System; using namespace System::Collections::Generic; using namespace System::IO; using namespace System::Threading; using namespace Microsoft::Win32::SafeHandles; ////// 共有メモリ・サービスクラス /// public ref class ShareInfoService { private: // 共有メモリのシステム名称 static String^ _share_name; // 排他用のシステム名称 static String^ _access_lock; // データ・サイズ initonly DWORD _lower_size; initonly DWORD _upper_size; // アンマネージド・リソース //@{ // ファイル・ハンドル SafeFileHandle^ _mapped_handle; // 共有メモリのポインタ IntPtr _mapped_area; //@} public: ////// コンストラクタ /// ShareInfoService() { this->_lower_size = 1024 * 1024; this->_upper_size = 0; this->_mapped_area = IntPtr::Zero; this->_mapped_handle = nullptr; } ////// メモリ・サイズを指定したコンストラクタ /// /// メモリ・サイズ(Byte単位) ShareInfoService(long long int mem_size) { this->_lower_size = mem_size; this->_upper_size = mem_size >> 32; this->_mapped_area = IntPtr::Zero; this->_mapped_handle = nullptr; } ////// デストラクタ /// ~ShareInfoService() { // Console::WriteLine("ShareInfoService::Destructor"); ShareInfoService::!ShareInfoService(); } ////// ファイナライザ /// !ShareInfoService() { // Console::WriteLine("ShareInfoService::Finalizer"); this->Release(); } ////// 静的コンストラクタ /// static ShareInfoService() { ShareInfoService::_share_name = "Sharable Information Service"; ShareInfoService::_access_lock = "Mutex Write Data to Sharable Information"; } ////// アンマネージド・リソースを解放するメソッド /// ファイナライザから呼ばれます。 /// void Release() { // Console::WriteLine("ShareInfoService::Release"); if ( this->_mapped_area != IntPtr::Zero ) { Console::WriteLine("ShareInfoService::Release : release memory."); ::UnmapViewOfFile( this->_mapped_area.ToPointer() ); this->_mapped_area = IntPtr::Zero; } } ////// 共有メモリを作成する /// ////// 真偽値 : メモリ作成結果を返す。 /// true : エラー発生 /// false : 正常終了 /// bool Create() { this->Release(); array^ arr = ShareInfoService::_share_name->ToCharArray(); pin_ptr ptr = &arr[0]; bool is_created = false; HANDLE hMap = ::OpenFileMapping( FILE_MAP_ALL_ACCESS, FALSE, ptr); if ( hMap == NULL ) { Console::WriteLine("ShareInfoService::Create : failed to open Mapping file."); String^ mut_name = "Mutex Sharable Information Service"; Mutex^ mutex = nullptr; try { mutex = gcnew Mutex(false, mut_name); } catch ( UnauthorizedAccessException^ e ) { Console::WriteLine("ShareInfoService::Create : no acceptant for user to create system mutex."); } catch ( IO::IOException^ e ) { Console::WriteLine("ShareInfoService::Create : Win32 error."); } catch ( ApplicationException^ e ) { Console::WriteLine("ShareInfoService::Create : failed to create named mutex."); } catch ( ArgumentException^ e ) { Console::WriteLine("ShareInfoService::Create : Mapping Name is over 260 character."); } if ( mutex != nullptr ) { if ( mutex->WaitOne(0, false) ) { // Console::WriteLine("ShareInfoService::Create : create file map."); hMap = ::CreateFileMapping( (HANDLE)0xFFFFFFFF, NULL, PAGE_READWRITE, this->_upper_size, this->_lower_size, ptr); if ( hMap == NULL ) { // Console::WriteLine("ShareInfoService::Create : failed to create file map."); return true; } is_created = true; mutex->ReleaseMutex(); } mutex->Close(); } } if ( hMap != NULL ) { // Console::WriteLine("ShareInfoService::Create : mapping files to memory."); LPVOID mem = ::MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0); if ( mem != NULL ) { this->_mapped_area = IntPtr(mem); this->_mapped_handle = gcnew SafeFileHandle(IntPtr(hMap), true); if ( is_created ) this->Erase(); } else { // Console::WriteLine("ShareInfoService::Create : failed to map file."); return true; } } return false; } /// /// 文字列データを追加する /// /// キー文字列 /// 値 ///登録データ数 int Append(String^ key, String^ val) { int count = 0; try { Mutex^ mutex = gcnew Mutex(false, ShareInfoService::_access_lock); if ( mutex != nullptr ) { if ( mutex->WaitOne(0, false) ) { Dictionary^ param = this->Params; param[key] = val; MemoryStream^ mstream = gcnew MemoryStream(this->GetData()); BinaryWriter bwriter(mstream); bwriter.Write(param->Count); for each ( String^ key in param->Keys ) { bwriter.Write(key); bwriter.Write(param[key]); } array ^ arr = mstream->ToArray(); pin_ptr ptr = &arr[0]; memcpy(this->_mapped_area.ToPointer(), ptr, this->Size); mutex->ReleaseMutex(); count = param->Count; } mutex->Close(); } } catch ( ApplicationException^ e ) { Console::WriteLine("ShareInfoService::Create : failed to get named mutex."); } return count; } #pragma region プロパティ /// /// 共有メモリのデータサイズ /// property long long int Size { long long int get() { if ( this->_mapped_area == IntPtr::Zero ) return 0; long long int size = this->_upper_size; size <<= 32; size += this->_lower_size; return size; } } ////// 実データへのアクセサ /// property IntPtr Data { IntPtr get() { return this->_mapped_area; } } ////// 登録キー /// property array^ Keys { array ^ get() { MemoryStream^ mstr = gcnew MemoryStream(this->GetData()); BinaryReader breader(mstr); int count = breader.ReadInt32(); List list; for ( int i=0; i /// 登録データ /// property Dictionary ^ Params { Dictionary ^ get() { MemoryStream^ mstream = gcnew MemoryStream(this->GetData()); BinaryReader breader(mstream); int count = breader.ReadInt32(); Dictionary ^ data = gcnew Dictionary ; for ( int i=0; i /// メモリ初期化メソッド /// void Erase() { if ( this->_mapped_area != IntPtr::Zero ) { ::memset( this->_mapped_area.ToPointer(), 0, this->Size ); } } private: /// /// 共有メモリ上のデータをマネージドのバイト配列に変換する。 /// ///データのマネージド配列 array^ GetData() { if ( this->_mapped_area == IntPtr::Zero ) return nullptr; array ^ arr = gcnew array (this->Size); pin_ptr ptr = &arr[0]; memcpy(ptr, this->_mapped_area.ToPointer(), this->Size); return arr; } /// /// マネージドなバイト配列を共有メモリに書き込む。 /// ////// 真偽値 : 処理の結果を返す。 /// true : エラー発生 /// false : 正常終了 /// bool PutData(array^ data) { bool result = false; try { Mutex^ mutex = gcnew Mutex(false, ShareInfoService::_access_lock); if ( mutex != nullptr ) { if ( mutex->WaitOne(0, false) ) { pin_ptr ptr = &data[0]; memcpy(this->_mapped_area.ToPointer(), ptr, data->Length); mutex->ReleaseMutex(); } else { result = true; } mutex->Close(); } } catch ( ApplicationException^ e ) { // Console::WriteLine("ShareInfoService::Create : failed to get named mutex."); result = true; } return result; } };
この程度なら問題ないんだけどなぁ。
サービス化を考えると難しい。