티스토리 뷰
Win32 환경은 프로세스간 메모리 공간이 격리되어 사용자 정의 메시지 전달로는 안되고
WM_COPYDATA 메시지를 이용한다.
wParam |
정보를 보내는 윈도우의 핸들 지정 |
lParam |
COPYDATA 구조체의 포인터 지정 |
1
2
3
4
5 |
typedef struct tagCOPYDATASTRUCT {
ULONG_PTR dwData;
DWORD cbData;
_Field_size_bytes_(cbData) PVOID lpData;
} COPYDATASTRUCT, *PCOPYDATASTRUCT; |
cs |
dwData : 교환하고자 하는 정수값, WM_COPYDATA 메시지가 다른 여러곳에서 오는 경우 구분자로 이용 가능할듯
lpData : 교환하고자 하는 문자열(또는 이진 데이터)
cdData : lpData의 크기
정수 하나와 포인터 하나를 보낼 수 있다.
이 구조체에 값을 채운 후 WM_COPYDATA 메시지를 보내면 OS가 tagCopyDataSTRUCT 구조체에 보관된 값을 해당 윈도우로 전달한다.
구조체나 배열도 보낼 수 있는데 이 포인터를 전달 받는 프로세스가 참조할 수 있게 변환하는 것은 OS가 대신 하는데 내부적으로 복잡한 처리를 하고 있음을 쉽게 상상이 갈 것이다. 전달할 데이터의 크기만큼 파일 맵핑을 생성하고 통신 대상 프로세스들의 주소 공간에 동시에 맵해 놓고 맵된 번지를 lParam으로 전달한다. 이 메시지는 무척 편리하게 사용할 수 있는 반면 그다지 효율이 좋지는 못하며 다음 사항에 주의해서 사용해야 한다.
1. lpData에는 받는 쪽에서 읽을 수 있는 값만 전달해야 한다. 단순한 문자열이라면 간단하겠지만 복잡한 이진 포맷의 데이터라면 통신하는 양쪽이 포맷을 알고 있어야만 한다.
2. 받은 쪽에서 데이터를 다 사용하기 전에 전달된 값이 바뀌지 않도록 해야 하낟. SendMessage는 메시지가 완전히 처리되기 전에 리턴하지 않으므로 자신이 직접 변경할 수는 없지만 멀티 스레드를 쓸 경우 다른 스레드에서 값을 변경할 여지를 차단해야 한다.
3. 받는 데이터는 읽기 전용이므로 변경해서는 안된다. 만약, 꼭 변경하고자 한다면 로컬 메모리에 복사한 후 사본을 변경해야 한다.
4. WM_COPYDATA 메시지는 SendMessage로 보내야 하며 PostMessage로 부쳐서는 안된다. 임시적인 처리를 통해 데이터를 전달하는 것이므로 메시지를 큐에 붙이는 것은 의미가 없다.
cbData 에 직접 문자열을 보내는 경우 오래된 책을 갖고 연습하니 유니코드랑 충돌 나는건지 결과 화면이 다르다. 프로젝트를 유니코드로 하고 실행하면 위 그림처럼 문자열이 잘린다. 그래서, 보내는 쪽에서는 문자열 길이를 2배로 하고, 받는 쪽에서 반으로 줄인다. 그러나 cbData에 사용자 정의 구조체를 넣고 전송하는 경우 사용자 정의 구조체 안에 있는 문자열은 잘리지 않는다.
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 |
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
COPYDATASTRUCT cds;
TCHAR* str = L"WM_DATACOPY 메시지를 위한 테스트 스트링";
TCHAR* pMsg = L"마우스 왼쪽 버튼을 누르면 다른 프로세스로 메시지를 보냅니다.";
HWND hWnd1 = NULL;
switch (message)
{
case WM_LBUTTONDOWN:
cds.dwData = 0;
cds.cbData = lstrlen(str)*2; // 유니코드로 할때 문자열 잘림으로 인해 2배로 함
cds.lpData = str;
hWnd1 = FindWindow(NULL, L"Win32Project1");
if (hWnd1 != NULL)
SendMessage(hWnd1, WM_COPYDATA, (WPARAM)hWnd, (LPARAM)&cds);
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: 여기에 hdc를 사용하는 그리기 코드를 추가합니다.
TextOut(hdc, 10, 50, pMsg, lstrlen(pMsg));
EndPaint(hWnd, &ps);
}
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 |
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
COPYDATASTRUCT* pcds;
HDC hdc;
TCHAR* pMsg = L"다른 프로그램으로 부터 메시지를 전달 받는다.";
static int n = 90;
switch (message)
{
case WM_COPYDATA:
pcds = (PCOPYDATASTRUCT)lParam;
hdc = GetDC(hWnd);
TextOut(hdc, 10, n=(n+12+5), (LPCTSTR)pcds->lpData, pcds->cbData/2);
ReleaseDC(hWnd, hdc);
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: 여기에 hdc를 사용하는 그리기 코드를 추가합니다.
TextOut(hdc, 10, 50, pMsg, lstrlen(pMsg));
EndPaint(hWnd, &ps);
}
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 |
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
struct _Nation {
TCHAR name[60];
int Population;
TCHAR Code[3];
} Nation[]{
L"WM_COPYDATA 메시지를 위한 테스트 스트링", 123456789, L"1",
L"대한민국", 50000000, L"82",
L"중국", 1000000000, L"86"
};
COPYDATASTRUCT cds;
TCHAR* pMsg = L"마우스 왼쪽 버튼을 누르면 다른 프로세스로 메시지를 보냅니다.";
HWND hWnd1 = NULL;
switch (message)
{
case WM_LBUTTONDOWN:
cds.dwData = 0;
cds.cbData = sizeof(Nation);
cds.lpData = Nation;
hWnd1 = FindWindow(NULL, L"Win32Project1");
if (hWnd1 != NULL)
SendMessage(hWnd1, WM_COPYDATA, (WPARAM)hWnd, (LPARAM)&cds);
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: 여기에 hdc를 사용하는 그리기 코드를 추가합니다.
TextOut(hdc, 10, 50, pMsg, lstrlen(pMsg));
EndPaint(hWnd, &ps);
}
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 |
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
struct _Nation{
TCHAR name[60];
int Population;
TCHAR Code[3];
} *pNation;
TCHAR str[60];
COPYDATASTRUCT* pcds;
HDC hdc;
int i;
TCHAR* pMsg = L"다른 프로그램으로 부터 메시지를 전달 받는다.";
static int n = 90;
switch (message)
{
case WM_COPYDATA:
pcds = (PCOPYDATASTRUCT)lParam;
hdc = GetDC(hWnd);
pNation = (_Nation*)pcds->lpData;
for (i = 0; i < 3; i++)
{
lstrcpy(str, pNation[i].Code);
TextOut(hdc, 10, n = (n + 12 + 5), str, lstrlen(str));
lstrcpy(str, pNation[i].name);
TextOut(hdc, 10, n = (n + 12 + 5), str, lstrlen(str));
wsprintf(str, L"%d", pNation[i].Population);
TextOut(hdc, 10, n = (n + 12 + 5), str, lstrlen(str));
}
ReleaseDC(hWnd, hdc);
break;
...
} |
cs |