티스토리 뷰
메모리 맵 파일
하드디스크에 있는 파일을 가상 메모리 주소 공간에 직접 매핑하여 파일을 메모리처럼 사용하는 기법
실행파일(*.exe)과 DLL 등과 같이 무거운 실행파일을 메모리에 로드할 필요없이 바로 가상메모리로 매핑해서 실행하도록하면 유용하다. 그래서 대용량 가상메모리 할당 또는 대용량 파일처리에 적합하다.
또한, 동일한 메모리 맵 파일을 이용하여 프로세스간 데이타 공유 가능하다.
1. 파일 매핑 객체 생성
HANDLE CreateFileMapping(
HANDLE 메모리에 매핑할 대상 파일의 핸들,
LPSECURITY_ATTRIBUTES 보안속성, // 보통 NULL
DWORD 접근속성,
DWORD 파일 매핑에 사용할 메모리 길이 중 상위 32비트, // 0
DWORD 파일 매핑에 사용할 메모리 길이 중 하위 32비트,
LPCTSTR 파일 매핑 객체 이름); // 필요하지 않을 경우 NULL
<접근속성>
PAGE_READONLY
PAGE_READWRITE
PAGE_WRITECOPY 페이지에 쓸 경우 복사본을 만듬
PAGE_COMMIT 기본값으로 하드디스크 또는 메모리상의 모든 파일 영역을 할당
PAGE_IMAGE char* 형과 같다
PAGE_NOCACHE 실행 이미지 파일을 매핑하고 캐시를 사용하지 않음
PAGE_RESERVE 물리적 메모리를 직접 사용하지 않고 보류(Recerved) 상태로 설정할 수
실제 메모리를 사용하지 않으나 다른 응용 프로그램이 사용할 수 없다
32비트 체제에서는 상위 32비트는 참조되지 않기 때문에 이 값은 항상 0 이고
파일 매핑에 사용할 메모리 길이 중 하위 32비트만 사용한다.
<파일 매핑 객체 이름>
복수개의 프로세스가 하나의 파일 매핑 객체를 공동으로 사용할때 사용
서로 다른 프로세스에서 같은 파일 매핑 객체를 얻기 위한 이름을 약속할 때 사용한다.
2. 주소 공간에 매핑
LPVOID MapViewOfFile(
HANDLE 가상 주소공간에 매핑하려는 파일 매핑 객체의 핸들,
DWORD 접근속성,
DWORD 매핑을 시작할 오프셋 위치 상위32비트,
DWORD 매핑을 시작할 오프셋 위치 하위32비트, // 0 : 파일 전체 매핑, 일부만 매핑할 경우 값 지정
DWORD 매핑할 뷰의 크기);
<접근속성>
FILE_MAP_WRITE
FILE_MAP_READ
FILE_MAP_ALL_ACCESS 읽기/쓰기
FILE_MAP_COPY 읽기/쓰기, 쓸때 복사본을 만든 후 쓴다
3. 매핑 파일 닫기
UnmapViewOfFile(LPCVOID 매핑파일포인터);
CloseHandle(HANDLE 매핑파일핸들);
CloseHandle(HANDLE 파일핸들);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 |
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
TCHAR* pFile;
HANDLE hFile, hMapFile;
RECT rect;
TCHAR fileData[] = L"서시\r\n\r\n\r\n윤동주\r\n\r\n죽는날까지 하늘을 우러러\r\n한 점 부끄럼없기를\r\n잎새는 이는 바람에도";
DWORD numOfByteWritten = 0;
switch (message)
{
case WM_LBUTTONDOWN:
hdc = GetDC(hWnd);
hFile = CreateFile(L"overture.txt", GENERIC_ALL | FILE_MAP_ALL_ACCESS, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
WriteFile(hFile, fileData, sizeof(fileData), &numOfByteWritten, NULL);
if (hFile == INVALID_HANDLE_VALUE)
MessageBox(hWnd, L"파일이 없습니다.", L"에러", MB_OK);
else
{
hMapFile = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL);
pFile = (TCHAR*)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, NULL);
SetRect(&rect, 10, 10, 500, 400);
DrawText(hdc, pFile, GetFileSize(hFile, NULL), &rect, DT_EXPANDTABS);
UnmapViewOfFile(pFile);
CloseHandle(hMapFile);
CloseHandle(hFile);
}
ReleaseDC(hWnd, hdc);
break;
|
cs |
<프로세스간 통신(공유)>
두 프로그램간 통신을 위해 공유할 메모리 맵 객체 이름(SHAREDMAP)을 사용
파일을 공유하는것보다 페이징 파일을 이용하기 위해 INVALID_HANDLE_VALUE 를 사용
두 파일 소스는 동일하고, FindWindow()로 찾을 창의 제목(MemEx/MemSahred)만 다르다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 |
// MemShared
#define ID_EDIT 1000
#define WM_SHARED_MEM WM_USER+1
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND hEdit;
static TCHAR* pFile = NULL;
HANDLE hMapFile;
HWND hTarget;
switch (message)
{
case WM_CREATE:
hEdit = CreateWindow(L"edit", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | ES_MULTILINE, 10, 10, 500, 200, hWnd, (HMENU)ID_EDIT, hInst, NULL);
SendMessage(hEdit, EM_LIMITTEXT, 1024, 0);
hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 1024, L"SHAREDMEM");
pFile = (TCHAR*)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 1024);
break;
case WM_SHARED_MEM:
SetWindowText(hEdit, pFile);
break;
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// 메뉴 선택을 구문 분석합니다.
switch (wmId)
{
case ID_EDIT:
switch (HIWORD(wParam))
{
case EN_CHANGE:
GetWindowText(hEdit, pFile, 1024);
hTarget = FindWindow(NULL, L"MemEx"); // 윈도우 타이틀이 MemEx 인 창을 찾음
if (hTarget)
SendMessage(hTarget, WM_SHARED_MEM, 0, 0); // 사용자 정의 메시지 전달
break;
}
break;
case WM_DESTROY:
UnmapViewOfFile(pFile);
PostQuitMessage(0);
break;
|
cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 |
// MemEx
#define ID_EDIT 1000
#define WM_SHARED_MEM WM_USER+1
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND hEdit;
HDC hdc;
static TCHAR* pFile = NULL;
HANDLE hMapFile;
HWND hTarget;
switch (message)
{
case WM_CREATE:
hEdit = CreateWindow(L"edit", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | ES_MULTILINE, 10, 10, 500, 200, hWnd, (HMENU)ID_EDIT, hInst, NULL);
SendMessage(hEdit, EM_LIMITTEXT, 1024, 0);
hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 1024, L"SHAREDMEM");
pFile = (TCHAR*)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 1024);
break;
case WM_SHARED_MEM:
SetWindowText(hEdit, pFile);
break;
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// 메뉴 선택을 구문 분석합니다.
switch (wmId)
{
case ID_EDIT:
switch (HIWORD(wParam))
{
case EN_CHANGE:
GetWindowText(hEdit, pFile, 1024);
hTarget = FindWindow(NULL, L"MemShared");
if (hTarget)
SendMessage(hTarget, WM_SHARED_MEM, 0, 0);
break;
}
break;
case WM_DESTROY:
UnmapViewOfFile(pFile);
PostQuitMessage(0);
break;
|
cs |