次の方法で共有


Dynamic-Link ライブラリでの共有メモリの使用

次の例では、DLL エントリ ポイント関数でファイル マッピング オブジェクトを使用して、DLL を読み込むプロセスで共有できるメモリを設定する方法を示します。 共有 DLL メモリは、DLL が読み込まれている限り保持されます。 アプリケーションでは、SetSharedMem 関数と GetSharedMem 関数を使用して共有メモリにアクセスできます。

共有メモリを実装する DLL

この例では、ファイル マッピングを使用して、DLL を読み込む各プロセスの仮想アドレス空間に名前付き共有メモリのブロックをマップします。 これを行うには、エントリ ポイント関数で次の操作を行う必要があります。

  1. CreateFileMapping 関数を呼び出して、ファイル マッピング オブジェクトへのハンドルを取得します。 DLL を読み込む最初のプロセスでは、ファイル マッピング オブジェクトが作成されます。 後続のプロセスでは、既存のオブジェクトへのハンドルが開きます。 詳細については、「 File-Mapping オブジェクトの作成」を参照してください。
  2. MapViewOfFile 関数を呼び出して、ビューを仮想アドレス空間にマップします。 これにより、プロセスは共有メモリにアクセスできます。 詳細については、「 ファイル ビューの作成」を参照してください。

CreateFileMappinglpAttributes パラメーターに NULL 値を渡すことで、既定のセキュリティ属性を指定できますが、SECURITY_ATTRIBUTES構造を使用してセキュリティを強化することもできます。

// The DLL code

#include <windows.h> 
#include <memory.h> 
 
#define SHMEMSIZE 4096 
 
static LPVOID lpvMem = NULL;      // pointer to shared memory
static HANDLE hMapObject = NULL;  // handle to file mapping

// The DLL entry-point function sets up shared memory using a 
// named file-mapping object. 
 
BOOL WINAPI DllMain(HINSTANCE hinstDLL,  // DLL module handle
    DWORD fdwReason,              // reason called 
    LPVOID lpvReserved)           // reserved 
{ 
    BOOL fInit, fIgnore; 
 
    switch (fdwReason) 
    { 
        // DLL load due to process initialization or LoadLibrary
 
          case DLL_PROCESS_ATTACH: 
 
            // Create a named file mapping object
 
            hMapObject = CreateFileMapping( 
                INVALID_HANDLE_VALUE,   // use paging file
                NULL,                   // default security attributes
                PAGE_READWRITE,         // read/write access
                0,                      // size: high 32-bits
                SHMEMSIZE,              // size: low 32-bits
                TEXT("dllmemfilemap")); // name of map object
            if (hMapObject == NULL) 
                return FALSE; 
 
            // The first process to attach initializes memory
 
            fInit = (GetLastError() != ERROR_ALREADY_EXISTS); 
 
            // Get a pointer to the file-mapped shared memory
 
            lpvMem = MapViewOfFile( 
                hMapObject,     // object to map view of
                FILE_MAP_WRITE, // read/write access
                0,              // high offset:  map from
                0,              // low offset:   beginning
                0);             // default: map entire file
            if (lpvMem == NULL) 
                return FALSE; 
 
            // Initialize memory if this is the first process
 
            if (fInit) 
                memset(lpvMem, '\0', SHMEMSIZE); 
 
            break; 
 
        // The attached process creates a new thread
 
        case DLL_THREAD_ATTACH: 
            break; 
 
        // The thread of the attached process terminates
 
        case DLL_THREAD_DETACH: 
            break; 
 
        // DLL unload due to process termination or FreeLibrary
 
        case DLL_PROCESS_DETACH: 
 
            // Unmap shared memory from the process's address space
 
            fIgnore = UnmapViewOfFile(lpvMem); 
 
            // Close the process's handle to the file-mapping object
 
            fIgnore = CloseHandle(hMapObject); 
 
            break; 
 
        default: 
          break; 
     } 
 
    return TRUE; 
    UNREFERENCED_PARAMETER(hinstDLL); 
    UNREFERENCED_PARAMETER(lpvReserved); 
} 

// The export mechanism used here is the __declspec(export)
// method supported by Microsoft Visual Studio, but any
// other export method supported by your development
// environment may be substituted.

#ifdef __cplusplus    // If used by C++ code, 
extern "C" {          // we need to export the C interface
#endif
 
// SetSharedMem sets the contents of the shared memory 
 
__declspec(dllexport) VOID __cdecl SetSharedMem(LPWSTR lpszBuf) 
{ 
    LPWSTR lpszTmp; 
    DWORD dwCount=1;
 
    // Get the address of the shared memory block
 
    lpszTmp = (LPWSTR) lpvMem; 
 
    // Copy the null-terminated string into shared memory
 
    while (*lpszBuf && dwCount<SHMEMSIZE) 
    {
        *lpszTmp++ = *lpszBuf++; 
        dwCount++;
    }
    *lpszTmp = '\0'; 
} 
 
// GetSharedMem gets the contents of the shared memory
 
__declspec(dllexport) VOID __cdecl GetSharedMem(LPWSTR lpszBuf, DWORD cchSize) 
{ 
    LPWSTR lpszTmp; 
 
    // Get the address of the shared memory block
 
    lpszTmp = (LPWSTR) lpvMem; 
 
    // Copy from shared memory into the caller's buffer
 
    while (*lpszTmp && --cchSize) 
        *lpszBuf++ = *lpszTmp++; 
    *lpszBuf = '\0'; 
}
#ifdef __cplusplus
}
#endif

共有メモリは、各プロセスで異なるアドレスにマップできます。 このため、各プロセスには lpvMem の独自のインスタンスがあり、すべての DLL 関数で使用できるようにグローバル変数として宣言されています。 この例では、DLL グローバル データが共有されていないことを前提としているため、DLL を読み込む各プロセスには lpvMem の独自のインスタンスがあります。

共有メモリは、ファイル マッピング オブジェクトへの最後のハンドルが閉じられると解放されることに注意してください。 永続的な共有メモリを作成するには、一部のプロセスが常にファイル マッピング オブジェクトへのオープン ハンドルを持っていることを確認する必要があります。

共有メモリを使用するプロセス

次のプロセスでは、上記で定義した DLL によって提供される共有メモリが使用されます。 最初のプロセスは SetSharedMem を呼び出して文字列を書き込み、2 番目のプロセスは GetSharedMem を呼び出してこの文字列を取得します。

このプロセスでは、DLL によって実装された SetSharedMem 関数を使用して、"This is a test string" という文字列を共有メモリに書き込みます。 また、共有メモリから文字列を読み取る子プロセスも開始します。

// Parent process

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

extern "C" VOID __cdecl SetSharedMem(LPWSTR lpszBuf);

HANDLE CreateChildProcess(LPTSTR szCmdline) 
{ 
   PROCESS_INFORMATION piProcInfo; 
   STARTUPINFO siStartInfo;
   BOOL bFuncRetn = FALSE; 
 
// Set up members of the PROCESS_INFORMATION structure. 
 
   ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
 
// Set up members of the STARTUPINFO structure. 
 
   ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
   siStartInfo.cb = sizeof(STARTUPINFO); 
 
// Create the child process. 
    
   bFuncRetn = CreateProcess(NULL, 
      szCmdline,     // command line 
      NULL,          // process security attributes 
      NULL,          // primary thread security attributes 
      TRUE,          // handles are inherited 
      0,             // creation flags 
      NULL,          // use parent's environment 
      NULL,          // use parent's current directory 
      &siStartInfo,  // STARTUPINFO pointer 
      &piProcInfo);  // receives PROCESS_INFORMATION 
   
   if (bFuncRetn == 0) 
   {
      printf("CreateProcess failed (%)\n", GetLastError());
      return INVALID_HANDLE_VALUE;
   }
   else 
   {
      CloseHandle(piProcInfo.hThread);
      return piProcInfo.hProcess;
   }
}

int _tmain(int argc, TCHAR *argv[])
{
   HANDLE hProcess;

   if (argc == 1) 
   {
      printf("Please specify an input file");
      ExitProcess(0);
   }

   // Call the DLL function
   printf("\nProcess is writing to shared memory...\n\n");
   SetSharedMem(L"This is a test string");

   // Start the child process that will read the memory
   hProcess = CreateChildProcess(argv[1]);

   // Ensure this process is around until the child process terminates
   if (INVALID_HANDLE_VALUE != hProcess) 
   {
      WaitForSingleObject(hProcess, INFINITE);
      CloseHandle(hProcess);
   }
   return 0;
}

このプロセスでは、DLL によって実装された GetSharedMem 関数を使用して、共有メモリから文字列を読み取ります。 これは、上記の親プロセスによって開始されます。

// Child process

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

extern "C" VOID __cdecl GetSharedMem(LPWSTR lpszBuf, DWORD cchSize);

int _tmain( void )
{
    WCHAR cBuf[MAX_PATH];

    GetSharedMem(cBuf, MAX_PATH);
 
    printf("Child process read from shared memory: %S\n", cBuf);
    
    return 0;
}

ダイナミック リンク ライブラリ データ