・File Mapping でプロセス間通信(99/12/9)

昔、名前無しパイプでプロセス間通信をする方法を書きましたが今回は File Mapping Object でデータをやり取りする方法を書きましょう。

詳しくは MSDN をみてもらうとして、 File Mapping Object というのは要するに複数のプロセス間でメモリの内容を 共有するというものなのですが、これには名前あり File Mapping Object と名前無し File Mapping Object の二種類あります。名前ありの方は 簡単でつまらないので(^^;、ここでは名前無しの方を使ってみます。

名前無し File Mapping Object でデータをやりとりするには まず親プロセス側で CreateFileMapping() を使って File Mapping Object を作成する際に lpFileMappingAttributes の所でハンドルを継承する 様に指定しなければなりません。また CreateProcess() で子プロセスを 起動するときにも bInheritHandles を TRUE にする必要があります。 そして子プロセスを起動する時の引数に File Mapping Object のハンドルを 入れて子プロセスにハンドルを渡します。後は子プロセス側で MapViewOfFileEx() を使ってアドレスをマップしてデータを読み書きする だけです。まあ、口で言うよりサンプルを見てもらった方が良いですね。 なお、親の方の実行ファイルの名前は何でも良いのですが、子供の方は filemap_c.exe と して下さい。

// CreateFileMapping のサンプル 99/12/9
// (c)1999 tokai@fides.dti.ne.jp

#include <windows.h>
#include <stdio.h>

#define CHR_BUF 256


#ifndef FMAPCHILD
//--------------------------------------------------------
// コマンドライン起動関数
BOOL ExecCommand(LPSTR lpszCommandLine,
				 	PROCESS_INFORMATION* pProInfo,
					BOOL bInheritHandles // ハンドル継承するか
					){
	
	BOOL bReturn;
	STARTUPINFO startInfo;

	memset(&startInfo,0,sizeof(STARTUPINFO));
	startInfo.cb = sizeof(STARTUPINFO);
	bReturn = CreateProcess(NULL,lpszCommandLine,NULL,NULL,bInheritHandles,
		0,NULL,NULL,&startInfo,pProInfo);

	return bReturn;
}



//---------------------------------------------------------------------
// 他のプロセスを起動して 名前無し File Mapping Object でデータを渡す関数
// 引数の最後に File Mapping Object のハンドルを付ける
BOOL ExecCommandFileMapping(LPSTR lpszCommandLine, 
							LPSTR lpszWriteData,   // 書き込むデータ
							PROCESS_INFORMATION* pProInfo,
							HINSTANCE hInst,
							LPSTR lpszErr // エラーメッセージ
							){

	HANDLE hFileMap = NULL; // File Mapping Object のハンドル
	HANDLE hMapAddress = NULL; // Mapped View のアドレス
	SECURITY_ATTRIBUTES secAtt;
	CHAR szCommand[CHR_BUF];
	BOOL bReturn = TRUE;

	// 名前無し file-mapping object の作成
	secAtt.nLength = sizeof(SECURITY_ATTRIBUTES);
	secAtt.lpSecurityDescriptor = NULL;
	secAtt.bInheritHandle = TRUE; // ハンドル継承
	if((hFileMap = CreateFileMapping((HANDLE)0xFFFFFFFF,&secAtt,PAGE_READWRITE,0,1024,NULL))==NULL){
		wsprintf(lpszErr,"CreateFileMapping に失敗しました\n");
		bReturn = FALSE;
		goto L_ERR;
	}

	// file-mapping object のアドレス空間へのマッピング
	if((hMapAddress = MapViewOfFileEx(hFileMap,FILE_MAP_ALL_ACCESS,0,0,0,NULL))==NULL){
		wsprintf(lpszErr,"MapViewOfFileEx に失敗しました\n");
		bReturn = FALSE;
		goto L_ERR;
	}

	// データ書き込み
	strcpy((LPSTR)hMapAddress,lpszWriteData);
	UnmapViewOfFile(hMapAddress);

	// 子プロセス起動(引数の最後に hFileMap のハンドルを付ける)
	wsprintf(szCommand,"%s %d",lpszCommandLine,(DWORD)hFileMap);
	if(!ExecCommand(szCommand,pProInfo,TRUE)){
		wsprintf(lpszErr,"プロセスの起動に失敗しました\n");
		bReturn = FALSE;
	}
	else Sleep(500); // 子供が MapViewOfFileEx するまでちょっと待つ

L_ERR:

	if(hFileMap != NULL) CloseHandle(hFileMap);

	return bReturn;
}



// 親 メイン
int main(int argc, char *argv[ ]){


	PROCESS_INFORMATION	proInfo;
	HINSTANCE hInst;
	CHAR szErr[CHR_BUF];

	proInfo.hProcess = NULL;
	hInst = GetModuleHandle(NULL);

	fprintf(stderr,"\n-- 親 --\n");

	if(!ExecCommandFileMapping("filemap_c.exe","テストです",&proInfo,hInst,szErr)){
		fprintf(stderr,szErr);
		exit(1);
	}

	// 子プロセスが終るまで停止
	WaitForSingleObject(proInfo.hProcess,INFINITE);
	
	fprintf(stderr,"\n-- 親終わり --\n");

	exit(0);
}


#else // ここから 子プロセス -------------------------------------------


//---------------------------------------------------------------------
// 親プロセスから名前無し File Mapping Object でデータをもらう関数
// 引数の最後に File Mapping Object のハンドルが付いていると仮定する
BOOL GetFileMappingData(int argc, char *argv[ ],LPSTR lpszData,LPSTR lpszErr){

	HANDLE hFileMap; // 継承された File Mapping Object のハンドル
	HANDLE hMapAddress; // Mapped View のアドレス

	if(argc == 1){
		wsprintf(lpszErr,"引数が足りません\n");
		return FALSE;
	}
	
	hFileMap = (HANDLE)strtoul(argv[argc-1],NULL,10);
	
	// file-mapping object のアドレス空間へのマッピング
	if((hMapAddress = MapViewOfFileEx(hFileMap,FILE_MAP_ALL_ACCESS,0,0,0,NULL))==NULL){
		wsprintf(lpszErr,"MapViewOfFileEx に失敗しました(継承ハンドル = %d)\n",(DWORD)hFileMap);
		return FALSE;
	}
	else{
		// データの取得
		strcpy(lpszData,(LPSTR)hMapAddress);

		UnmapViewOfFile(hMapAddress);
		CloseHandle(hFileMap);
	}

	return TRUE;
}



// 子 メイン
int main(int argc, char *argv[ ]){

	CHAR szErr[CHR_BUF],szData[CHR_BUF];

	fprintf(stderr,"\n-- 子供 --\n");

	if(!GetFileMappingData(argc,argv,szData,szErr)){
		fprintf(stderr,"%s",szErr);
		exit(1);
	}

	fprintf(stderr,"%s",szData);
	
	fprintf(stderr,"\n-- 子供終わり --\n");

	exit(0);
}

#endif