FAQ12-3

Q. 複数のアプリケーション間で同じデータを共有するには

 Windows95で,複数のアプリケーション間で同じデータを共有するにはどうしたらいいのでしょうか.
 Windows3.1の頃は,グローバルメモリ・ハンドルを共有すれば,同じメモリ領域を参照することができたのですが,Windows95用に32ビットアプリケーションにすると,プロセスごとに固有のアドレス空間になってしまったためか,今までのようなメモリ共有は,できなくなってしまいました.どうすればよいのでしょうか.教えてください.


A. 共有メモリを使う

共有メモリ

 32ビットアプリケーションでは,GlobalAlloc()はGlobalでなくなってしまいましたが,それに代わって,「共有メモリ」というメモリの使い方が用意されています.
 共有メモリは,CreateFileMapping()というAPIを使ってメモリを確保します.CreateFileMapping()は,ファイルをメモリにマップしてファイルの読み書きを高速に行うためのAPIですが,共有メモリの確保としても使うことができるAPIです.
 なんかもう,本当に"Global"なのはCreateFileMapping()だけで,GlobalAlloc()が"Global"ではなく,LocalAlloc()とGlobalAlloc()が全く同じで,HeapAlloc()という存在意義不明のものがあったりと,関数名がぐちゃぐちゃですね.えへん...
 CreateFileMapping()関連は,GlobalAlloc()と対比すると,だいたい表12-1のようにして使います.


[表12-1]
GlobalAlloc() handle = CreateFileMapping((HANDLE)0xFFFFFFFF, NULL, PAGE_READWRITE, 0, dwSize, NULL);
GlobalLock() ptr = MapViewOfFile( handle, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
GlobalUnlock() UnmapViewOfFile( ptr );
GlbalFree() CloseHandle( handle );


 この後が最も重要で,CreateFileMapping()が返すハンドルは,そのままでは他のプロセスでは使用不可能です.
 それじゃあどうすればよいのかというと,DuplicateHandle()というAPIを使って,ハンドルを変換すればできるようになります.具体的には,リスト12-7のようにします.
 これで変換されたハンドルをメッセージなどを介して送ってやれば,メモリを使うことができるようになります.

[リスト12-7] :

//hwnd	: 送り先プロセスの持つウィンドウ
//handle	: 変換前のハンドル
//戻り値	: 変換後のハンドル

HANDLE DuplicateHandleWindow( HWND hwnd, HANDLE handle ) {
	HANDLE	hdup;
	DWORD	dwProcessId;
	HANDLE	hProcess;
	GetWindowThreadProcessId( hwnd, &dwProcessId );
	hProcess = OpenProcess( PROCESS_DUP_HANDLE, TRUE, dwProcessId );
	DuplicateHandle( GetCurrentProcess(), handle, hProcess,
				&hdup, 0, TRUE, DUPLICATE_SAME_ACCESS );
	CloseHandle( hProcess );
	return hdup;
}

名前付き共有メモリ

 DuplicateHandle()を使っていちいちハンドルを渡さなくても,「名前付き共有メモリ」という技を使えば,もっと簡単に共有メモリを扱うことができます.
 CreateFileMapping()の最後の引数に共有名を指定してやると,「共有メモリ」は「名前付き共有メモリ」になります.
 一度メモリを確保すると,他のプロセスではOpenFileMapping()を呼ぶことで同じメモリ領域にアクセスできるようになります.
 リスト12-8のような使い方をすると,最初のプロセスか2番目のプロセスかを気にせずに使えるので便利です.

[リスト12-8] :

LPSTR		szShareName = "MYAPP_SHAREMEM";

HANDLE GetShareHandle( void ) {
	HANDLE hShare =
		OpenFileMapping( FILE_MAP_ALL_ACCESS,FALSE, szShareName );
	if( hShare == NULL ) {
		hShare = CreateFileMapping( (HANDLE)0xFFFFFFFF, NULL, PAGE_READWRITE, 0, dwSize, szShareName );
	}
	return hShare;
}

WM_COPYDATA〜データ渡す〜

 WM_COPYDATAという新しいメッセージを使って他のプロセスへデータを渡すという方法もあります.
 しかしこれは「データ渡す」だけのために用意されているもので,「共有」とは少し違います.共有するにはCreateFileMapping()を使うのがよいでしょう.

DLLのDATAのSHARED

 Windows3.1のときは,DLLを使ってメモリを共有するというテクニックもありました.
 Windows3.1のDLLは,コードもデータも常に一つしかないようにできているので,複数のEXEからDLLのデータ(=静的変数)にアクセスすればメモリの共有ができるようになる,というテクニックです.
 32ビットアプリケーションになると,当然この技は使えません.
 と,思いきや,.DEFファイル(モジュール定義ファイル)に以下の記述をするだけで,全く同じことができてしまいます.
CODE READ SHARED EXECUTE
DATA READ WRITE SHARED
SECTIONS
	.bss	READ WRITE SHARED
	.data	READ WRITE SHARED
 これだけのことをするだけで,DLLの静的変数は,DLLをロードしたどのプロセスからでもアクセスできるようになります.
 異なるプロセス間でのアドレス空間など全く気にせず使えるので,これが一番楽な方法であると言えます.

Back to FAQ main page