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