Top / Programming / C++Builder / メモリマップドファイルを使ってアプリケーション間でデータを共有する

メモリマップドファイルを使ってアプリケーション間でデータを共有する

メモリマップドファイルを使うと、アプリケーション間でデータを共有することができます。

データ送出の流れ

  1. CreateFileMappingで、メモリマップドファイルを作成する。
  2. MapViewOfFileで、メモリマップドファイルをアドレス空間にマップする。
  3. データを書き込む。
  4. UnmapViewOfFileで、メモリマップドファイルを解放する。
  5. CloseHandleで、ハンドルを解放する。

データ送出のサンプルプログラム

※サンプルプログラムでは、プロジェクトの設定で「_TCHARのマップ先」を「wchar_t」にしています。

データ送出プログラム

フォームに次のコントロールを配置します。

フォームのprivateに次の2つのメンバ変数を設定します。

ヘッダファイルは次のようになります。

class TForm1 : public TForm
{
__published:    // IDE 管理のコンポーネント
  TButton *Button1;
  TMemo *Memo1;
  TEdit *Edit1;
private:    // ユーザー宣言
  HANDLE FMapFile;
  LPTSTR FMapAdderss;
public:     // ユーザー宣言
  __fastcall TForm1(TComponent* Owner);
};

フォームのコンストラクタでメモリマップドファイルを作成します。

ファイルマッピングオブジェクトの最大サイズとオブジェクト名を設定します。

__fastcall TForm1::TForm1(TComponent* Owner)
  : TForm(Owner)
{
  //ファイルマッピングオブジェクトを作成する
  FMapFile = CreateFileMapping(
    (HANDLE)INVALID_HANDLE_VALUE,
    NULL,
    PAGE_READWRITE,
    0,    // サイズを表す上位 DWORD
    1024, // サイズを表す下位 DWORD
    L"FileMappingSample"); //ファイルマッピングオブジェクトの名前

  //ファイルマッピングオブジェクトの作成に失敗したとき
  if (FMapFile == NULL) {
    Memo1->Lines->Add(L"ファイルマッピングオブジェクトの作成に失敗しました。");
  }
}

フォーム破棄するときに使用しているメモリとハンドルを破棄します。

void __fastcall TForm1::FormDestroy(TObject *Sender)
{
  //ファイルのマップトビューをアンマップする
  UnmapViewOfFile(FMapAdderss);
  //ファイルマッピングオブジェクトのハンドルを解放する
  CloseHandle(FMapFile);
}

「送出」ボタンを押すと、メモリマップドファイルにデータを書き込みます。

void __fastcall TForm1::Button1Click(TObject *Sender)
{
  //ファイルマッピングオブジェクトに失敗したとき
  if (!FMapFile) return;

  //アドレス空間にファイルのビューをマップする
  FMapAdderss = (LPTSTR)MapViewOfFile(FMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
  if (FMapAdderss == NULL) {
    Memo1->Lines->Add(L"マップに失敗しました。");
    return;
  }

  //データを書き込む
  lstrcpyn(FMapAdderss, Edit1->Text.c_str(), 1024 / sizeof(TCHAR));

  //フラッシュして確実に更新する
  FlushViewOfFile(FMapAdderss, _tcslen(FMapAdderss));

  Memo1->Lines->Add(L"マップしました。");
}

データ受取の流れ

  1. OpenFileMappingで、名前付きのファイルマッピングオブジェクトを開く。
  2. MapViewOfFileで、メモリマップドファイルをアドレス空間にマップする。
  3. データを読み込む。
  4. UnmapViewOfFileで、メモリマップドファイルを解放する。
  5. CloseHandleで、ハンドルを解放する。

データ受取のサンプルプログラム

データ受取プログラム

フォームに次のコントロールを配置します。

「受取」ボタンを押すと、メモリマップドファイルからデータを読み込みます。

void __fastcall TForm2::Button1Click(TObject *Sender)
{
  //名前付きのファイルマッピングオブジェクトを開く
  HANDLE mapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, L"FileMappingSample");
  if (mapFile == NULL) {
    Memo1->Lines->Add(L"ファイルマッピングオブジェクトを開けません。");
    return;
  }

  //アドレス空間にファイルのビューをマップする
  LPTSTR mapAdderss = (LPTSTR)MapViewOfFile(mapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
  if (mapAdderss == NULL) {
    Memo1->Lines->Add(L"取得に失敗しました。");
    return;
  }

  //読み込み
  Memo1->Lines->Add(mapAdderss);

  //ファイルのマップトビューをアンマップする
  UnmapViewOfFile(mapAdderss);
  //ファイルマッピングオブジェクトのハンドルを解放する
  CloseHandle(FMapFile);
}

以上で、データの共有ができるようになりました。

同時アクセスの対策

メモリマップドファイルに対して同時に読み書きが行われると、データの状態が正しくなくなる可能性があります。

ミューテックスを使用して、同期をとるようにします。

  1. CreateMutexで、ミューテックスオブジェクトを作成する
  2. WaitForSingleObjectで、ミューテックスオブジェクトの状態をチェックする
  3. 読み書きを行う
  4. ReleaseMutexで、ミューテックスオブジェクトの所有権を解放する
  5. CloseHandleで、ハンドルを閉じる

ミューテックスを使用したデータ送出のサンプルプログラム

class TForm1 : public TForm
{
__published:    // IDE 管理のコンポーネント
  TButton *Button1;
  TLabeledEdit *Edit1;
  TMemo *Memo1;
  void __fastcall FormDestroy(TObject *Sender);
  void __fastcall Button1Click(TObject *Sender);
private:    // ユーザー宣言
  HANDLE FMapFile;
  HANDLE FMutex;
  LPTSTR FMapAdderss;
public:     // ユーザー宣言
  __fastcall TForm1(TComponent* Owner);
};
__fastcall TForm1::TForm1(TComponent* Owner)
  : TForm(Owner)
{
  //ファイルマッピングオブジェクトを作成する
  FMapFile = CreateFileMapping(
    (HANDLE)INVALID_HANDLE_VALUE,
    NULL,
    PAGE_READWRITE,
    0,    // サイズを表す上位 DWORD
    1024, // サイズを表す下位 DWORD
    L"FileMappingSample");  //ファイルマッピングオブジェクトの名前。

  //ファイルマッピングオブジェクトの作成に失敗したとき
  if (FMapFile == NULL) {
    Memo1->Lines->Add(L"ファイルマッピングオブジェクトの作成に失敗しました。");
  }

  //ミューテックスオブジェクトを作成する
  FMutex = CreateMutex(NULL, FALSE, L"MutexSample");

  //ミューテックスオブジェクトの作成に失敗したとき
  if (FMutex == NULL) {
    Memo1->Lines->Add(L"ミューテックスオブジェクトの作成に失敗しました。");
  }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
  //ファイルのマップトビューをアンマップする
  UnmapViewOfFile(FMapAdderss);
  //ファイルマッピングオブジェクトのハンドルを解放する
  CloseHandle(FMapFile);
  //ミューテックスオブジェクトのハンドルを解放する
  CloseHandle(FMutex);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  //ファイルマッピングオブジェクトに失敗したとき
  if (!FMapFile) return;

  //アドレス空間にファイルのビューをマップする
  FMapAdderss = (LPTSTR)MapViewOfFile(FMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
  if (FMapAdderss == NULL) {
    Memo1->Lines->Add(L"マップに失敗しました。");
    return;
  }

  //ミューテックスオブジェクトの状態をチェックする
  WaitForSingleObject(FMutex, INFINITE);

  //データを書き込む
  lstrcpyn(FMapAdderss, Edit1->Text.c_str(), 1024 / sizeof(TCHAR));

  //フラッシュして確実に更新する
  FlushViewOfFile(FMapAdderss, _tcslen(FMapAdderss));

  //ミューテックスオブジェクトの所有権を解放する
  ReleaseMutex(FMutex);

  Memo1->Lines->Add(L"マップしました。");
}

ミューテックスを使用したデータ受取のサンプルプログラム

void __fastcall TForm2::Button1Click(TObject *Sender)
{
  //名前付きのファイルマッピングオブジェクトを開く
  HANDLE mapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, L"FileMappingSample");
  if (mapFile == NULL) {
    Memo1->Lines->Add(L"ファイルマッピングオブジェクトを開けません。");
    return;
  }

  //ミューテックスオブジェクトを作成する
  HANDLE mutex = CreateMutex(NULL, FALSE, L"MutexSample");
  if (mutex == NULL) {
    Memo1->Lines->Add(L"ミューテックスオブジェクトの作成に失敗しました。");
  }

  //ミューテックスオブジェクトの状態をチェックする
  WaitForSingleObject(mutex, INFINITE);

  //アドレス空間にファイルのビューをマップする
  LPTSTR mapAdderss = (LPTSTR)MapViewOfFile(mapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
  if (mapAdderss == NULL) {
    Memo1->Lines->Add(L"取得に失敗しました。");
    return;
  }

  //読み込み
  Memo1->Lines->Add(mapAdderss);

  //ミューテックスオブジェクトの所有権を解放する
  ReleaseMutex(mutex);

  //ミューテックスオブジェクトのハンドルを解放する
  CloseHandle(mutex);

  //ファイルのマップトビューをアンマップする
  UnmapViewOfFile(mapAdderss);
  //ハンドルを解放する
  CloseHandle(mapFile);
}

更新履歴