プロセス間で通信ができるといろいろ便利なことがあります。
簡単な方法としてメモリマップトファイルがあります。
SDK編ではすでに、第123章で紹介してあるのでそちらも参照してみてください。
プロセス1で見ているメモリは、仮想メモリであり、そのアドレスは
仮想メモリのアドレスです。従って、他のプロセスにとっては意味のない
アドレスなのです。
そこで、プロセス1が物理メモリに共有メモリとして、一定の場所を確保したとします。
この時プロセス1では、この物理メモリのアドレスをプロセス1の仮想メモリのアドレスにマッピングしてから、読み書きをしなくてはなりません。
具体的には、まずCreateFileMapping関数でファイルマッピングオブジェクトを作成します。
HANDLE CreateFileMapping( HANDLE hFile, // ファイルのハンドル LPSECURITY_ATTRIBUTES lpAttributes, // セキュリティ DWORD flProtect, // 保護 DWORD dwMaximumSizeHigh, // サイズを表す上位 DWORD DWORD dwMaximumSizeLow, // サイズを表す下位 DWORD LPCTSTR lpName // オブジェクト名 );hFileには、作成元ファイルのハンドルを指定しますが、実際にファイルを作らない場合は0xFFFFFFFFを指定します。
lpAttributesにNULLを指定するとデフォルトのセキュリティとなります。
flProtectには、保護を指定しますが、プロセス間級友メモリでは通常PAGE_READWRITEを 指定します。
dwMaximumSizeHighには、マッピングファイルの上位32ビットを指定します。 ファイルサイズが4Gバイト以下の場合は0にします。
dwMaximumSizeLowには、マップするファイルサイズの下位32ビットを指定します。
lpNameには、メモリ領域の名前を指定します。共有メモリを作成する場合は必ず指定します。
関数が成功するとハンドルが返されます。 失敗するとNULLが返されます。 すでに、ファイルマッピングの名前が存在していても成功します。
すでに、その名前のオブジェクトが存在する場合GetLastError関数は、ERROR_ALREADY_EXISTSを返します。
マッピングオブジェクトができたら、自分のプロセスで使用できるようにマッピングします。
LPVOID MapViewOfFile( HANDLE hFileMappingObject, // ファイルマッピングオブジェクトのハンドル DWORD dwDesiredAccess, // アクセスモード DWORD dwFileOffsetHigh, // オフセットの上位 DWORD DWORD dwFileOffsetLow, // オフセットの下位 DWORD SIZE_T dwNumberOfBytesToMap // マップ対象のバイト数 );hFileMappingObjectには、マッピングオブジェクトのハンドルを指定します。
dwDesiredAccessには、アクセスモードを指定しますが、共有メモリの場合は FILE_MAP_ALL_ACCESSを指定します。
dwFileOffsetHighには、マッピングファイルのオフセットの上位32ビットを指定します。
通常は0を指定します。
dwFileOffsetLowには、マッピングファイルのオフセットの下位32ビットを指定しますが、通常は共有領域全体をマッピングするため0を指定します。
dwNumberOfBytesToMapには、マップ対象のバイト数を指定しますが、共有領域全体をマップするときは0を指定します。
成功すると、開始アドレスが返されます。失敗するとNULLが返されます。
すでに存在するファイルマッピングオブジェクトを開くには、OpenFileMapping 関数を使います。
HANDLE OpenFileMapping( DWORD dwDesiredAccess, // アクセスモード BOOL bInheritHandle, // 継承フラグ LPCTSTR lpName // オブジェクト名 );dwDesiredAccessには、アクセスモードを指定しますが、共有メモリの場合は通常 FILE_MAP_ALL_ACCESSを使います。
bInheritHandleには、継承フラグを指定します。ハンドルを子プロセスに継承しない 場合はFALSEを指定します。
lpNameには、オープンするマッピングオブジェクトの名前を指定します。
成功すると、マッピングオブジェクトのハンドルが返されますので、MapViewOfFile関数でポインタを取得します。
さて、共有領域が不要になったら、アンマップします。そして、マップトオブジェクトハンドルをクローズします。
BOOL UnmapViewOfFile( LPCVOID lpBaseAddress // 開始アドレス );アンマップに成功したら0以外が、失敗すると0が返されます。
では、サンプルのプログラムを見てみましょう。
/* filemapping01.c */
#include <stdio.h>
#include <windows.h>
#include <conio.h>
int FRead(LPSTR);
int FWrite(LPSTR);
HANDLE hFMWrite;
int main()
{
static LPSTR lpAddress1, lpAddress2;
char szNo[8];
BOOL bEnd = FALSE;
while (1) {
printf("***************\n");
printf("1. Writre\n");
printf("2. Read\n");
printf("0. End\n");
printf("***************\n");
printf("No. = ");
gets(szNo);
switch (szNo[0]) {
case '1':
FWrite(lpAddress1);
break;
case '2':
FRead(lpAddress2);
break;
case '0':
bEnd = TRUE;
break;
default:
printf("正しくない番号です\n\n");
break;
}
if (bEnd)
break;
}
if (hFMWrite) {
if (CloseHandle(hFMWrite) == 0)
printf("書き込みハンドルクローズ失敗\n");
else
printf("書き込みハンドルクローズ成功\n");
}
return 0;
}
int FWrite(LPSTR lpStr)
{
char szStr[1024];
if (!hFMWrite)
CloseHandle(hFMWrite);
hFMWrite = CreateFileMapping(
(HANDLE)-1,
NULL,
PAGE_READWRITE,
0,
1024,
"NEKODEMOWAKARU");
if (hFMWrite == NULL)
return -1;
if (GetLastError() == ERROR_ALREADY_EXISTS)
printf("すでにマッピングオブジェクトが存在しました\n");
lpStr = (LPSTR)MapViewOfFile(hFMWrite,
FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (lpStr == NULL)
return -2;
printf("書き込み==");
gets(szStr);
strcpy(lpStr, szStr);
strcat(lpStr, "\n");
UnmapViewOfFile(lpStr);
printf("書き込みました\n");
return 0;
}
int FRead(LPSTR lpStr)
{
HANDLE hFM;
hFM = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, "NEKODEMOWAKARU");
lpStr = (LPSTR)MapViewOfFile(hFM,
FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (lpStr == NULL) {
printf("受信失敗\n");
CloseHandle(hFM);
return -1;
}
printf(lpStr);
if (UnmapViewOfFile(lpStr) == 0) {
printf("読み込み用アドレスアンマップ失敗\n");
} else {
printf("読み込み用アドレスアンマップ成功\n");
lpStr = NULL;
}
CloseHandle(hFM);
return 0;
}
では、実際にこのプログラムを動かしてみましょう。
メニューが出るので、書き込みか、読み出しか、終了かを選択します。
「1.Write」を選択して、実際に書き込みを行います。
今度は「2.Read」を選択して読み出してみます。
無事読み出すことに成功です。
一度書き込んで、再度書き込みをすると
「すでにマッピングオブジェクトが存在しました」と言われますが、
再度書き込みが行われます。
このプログラムを複数起動すると、一つのプログラムで書き込みが起ると、 他のプログラムでもその書き込みを読むことができます。
また、他のプログラムが書き込んだ内容を変更することも可能です。
Update Jun/19/2005 By Y.Kumei