共有メモリ・クラス 修正版
ということで、SafeHandle を使った共有メモリ・クラスです。
よく考えると、C++/CLI では普通にクラスにマップするなり、CMemFile 使うなりで、あまり需要はなかったりするんですよね(w
// 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; ////// メモリ・マップド・ファイルのリソース管理ハンドル・クラス /// ///SafeHandle ///SafeFileHandle ref class MemoryMappedFileSafeHandle : public SafeHandleZeroOrMinusOneIsInvalid { private: ////// ファイル・ハンドルを管理するSafeHandle /// ///Microsoft::Win32::SafeHandles SafeFileHandle^ _mapped_file; public: ////// デフォルト・コンストラクタ /// MemoryMappedFileSafeHandle() : SafeHandleZeroOrMinusOneIsInvalid(true) { this->handle = IntPtr::Zero; this->_mapped_file = nullptr; } ////// ハンドルを与えるコンストラクタ /// /// マップされたメモリ /// マップ・ファイルへのファイル・ハンドル MemoryMappedFileSafeHandle(LPVOID mem_map, HANDLE file_handle) : SafeHandleZeroOrMinusOneIsInvalid(true) { this->handle = IntPtr(mem_map); this->_mapped_file = gcnew SafeFileHandle(IntPtr(file_handle), true); } ////// マップされたメモリ /// property IntPtr MappedPointer { ////// マップされたメモリを設定する /// /// マップされたメモリへのIntPtr void set(IntPtr mapped_ptr) { if ( this->handle != IntPtr::Zero ) { this->ReleaseHandle(); } this->handle = mapped_ptr; } } ////// マップされたメモリへのファイル・ハンドル /// property SafeFileHandle^ MappedFile { ////// ファイル・ハンドルを設定する。 /// /// ファイル・ハンドルを管理するSafeHandle void set(SafeFileHandle^ file_handle) { this->_mapped_file = file_handle; } } protected: ////// 保持するアンマネージド・リソースを解放する。 /// ///アンマップの結果 virtual bool ReleaseHandle() override { BOOL bRes = FALSE; if ( this->handle != IntPtr::Zero ) { Console::WriteLine("MemoryMapSafeHandle::ReleaseHandle : release memory."); bRes = ::UnmapViewOfFile( this->handle.ToPointer() ); this->handle = IntPtr::Zero; } if ( this->_mapped_file != nullptr ) { Console::WriteLine("MemoryMapSafeHandle::ReleaseHandle : close file handle."); this->_mapped_file->Close(); } return ( bRes ) ? true : false; } }; ////// 共有メモリ・サービスクラス /// public ref class ShareInfoService { private: // 共有メモリのシステム名称 static String^ _share_name; // 排他用のシステム名称 static String^ _access_lock; // データ・サイズ initonly DWORD _lower_size; initonly DWORD _upper_size; // アンマネージド・リソース //@{ // 共有メモリのポインタとハンドル MemoryMappedFileSafeHandle^ _mapped_area; //@} public: ////// コンストラクタ /// ShareInfoService() { this->_lower_size = 1024 * 1024; this->_upper_size = 0; this->_mapped_area = nullptr; } ////// メモリ・サイズを指定したコンストラクタ /// /// メモリ・サイズ(Byte単位) ShareInfoService(long long int mem_size) { this->_lower_size = mem_size; this->_upper_size = mem_size >> 32; this->_mapped_area = 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 != nullptr ) this->_mapped_area->Close(); } ////// 共有メモリを作成する /// ////// 真偽値 : メモリ作成結果を返す。 /// 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 = gcnew MemoryMappedFileSafeHandle(mem, hMap); 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->DangerousGetHandle().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->IsInvalid ) 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->DangerousGetHandle(); } } ////// 登録キー /// 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->IsInvalid ) { ::memset( this->_mapped_area->DangerousGetHandle().ToPointer(), 0, this->Size ); } } private: /// /// 共有メモリ上のデータをマネージドのバイト配列に変換する。 /// ///データのマネージド配列 array^ GetData() { if ( this->_mapped_area->IsInvalid ) return nullptr; array ^ arr = gcnew array (this->Size); pin_ptr ptr = &arr[0]; memcpy(ptr, this->_mapped_area->DangerousGetHandle().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->DangerousGetHandle().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; } };