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

공유 메모리는 각 프로세스의 다른 주소에 매핑할 수 있습니다. 이러한 이유로 각 프로세스에는 모든 DLL 함수에서 사용할 수 있도록 전역 변수로 선언되는 lpvMem의 자체 instance 있습니다. 이 예제에서는 DLL 전역 데이터가 공유되지 않는다고 가정하므로 DLL을 로드하는 각 프로세스에는 고유한 lpvMem instance 있습니다.

공유 메모리는 파일 매핑 개체에 대한 마지막 핸들을 닫을 때 해제됩니다. 영구 공유 메모리를 만들려면 일부 프로세스에 항상 파일 매핑 개체에 대한 열린 핸들이 있는지 확인해야 합니다.

공유 메모리를 사용하는 프로세스

다음 프로세스는 위에 정의된 DLL에서 제공하는 공유 메모리를 사용합니다. 첫 번째 프로세스는 SetSharedMem을 호출하여 문자열을 작성하고 두 번째 프로세스는 GetSharedMem을 호출하여 이 문자열을 검색합니다.

이 프로세스는 DLL에서 구현한 SetSharedMem 함수를 사용하여 공유 메모리에 "테스트 문자열입니다"라는 문자열을 씁니다. 또한 공유 메모리에서 문자열을 읽는 자식 프로세스를 시작합니다.

// 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;
}

동적 링크 라이브러리 데이터