🪟 WinAPI로 윈도우 간 데이터를 안전하게 주고받는 법, WM_COPYDATA로 해결!
📌 윈도우 프로그래밍에서 프로세스 간 통신을 안전하고 간단하게 구현하는 비결
윈도우 프로그래밍을 하다 보면 서로 다른 프로세스 간에 데이터를 주고받아야 할 일이 자주 생깁니다.
예를 들어 A 프로그램에서 입력한 내용을 B 프로그램에 전달하거나, 한 쪽에서 처리한 결과를 다른 쪽에서 받아서 보여줘야 할 수도 있죠.
이럴 때 사용하는 것이 바로 IPC(Inter-Process Communication, 프로세스 간 통신)입니다.
하지만 IPC는 종류도 많고 복잡하게 느껴질 수 있어 많은 개발자들이 부담을 느끼는 분야이기도 해요.
다행히 윈도우 환경에서는 WM_COPYDATA라는 메시지를 통해 비교적 간단하면서도 안전하게 데이터를 주고받을 수 있는 방법이 마련되어 있습니다.
메시지 기반 구조로 동작하기 때문에 구현도 어렵지 않고, 윈도우 핸들만 알고 있다면 다른 프로세스의 창에도 데이터를 보낼 수 있죠.
이번 글에서는 WM_COPYDATA의 기본 개념부터 실제 구현 방법, 사용할 때 주의할 점까지 차근차근 정리해드릴게요.
📋 목차
📡 WM_COPYDATA란 무엇인가요?
WM_COPYDATA는 윈도우 운영체제에서 제공하는 메시지 기반의 IPC(Inter-Process Communication) 방식 중 하나입니다.
쉽게 말해, 하나의 프로세스에서 다른 프로세스로 문자열, 숫자, 구조체 등의 데이터를 전달할 수 있도록 도와주는 기능이에요.
이 방식은 SendMessage 함수를 통해 특정 윈도우 핸들(HWND)에 직접 메시지를 보내는 구조로 동작하며, 데이터는 COPYDATASTRUCT 구조체 안에 담겨 전달됩니다.
이 구조체에는 전송할 데이터의 포인터와 크기 정보가 포함되어 있어서, 수신 측에서는 정확하게 필요한 만큼만 받아 처리할 수 있죠.
다른 IPC 방식들에 비해 설정이 간단하고 별도의 서버 프로세스나 공유 메모리 없이도 사용할 수 있다는 장점이 있어요.
특히 GUI 기반 응용 프로그램 간의 통신이 필요한 경우에 매우 유용하게 쓰입니다.
- ✅Win32 API의 SendMessage 함수를 사용
- 📦데이터는 COPYDATASTRUCT에 담아 전달
- 🔒직접적인 메모리 공유가 없어 안전한 통신 가능
- 🚫수신 측이 반드시 메시지 핸들러를 구현해야 함
이 방식은 단순 문자열뿐 아니라 구조체나 바이너리 데이터도 전달할 수 있어 활용도가 꽤 높습니다.
다만 복잡한 구조체를 전달할 경우에는 직렬화 및 해석 과정에서 데이터 정합성 문제가 생기지 않도록 주의해야 합니다.
🔍 어떤 상황에서 사용하면 좋을까요?
WM_COPYDATA는 윈도우 메시지 기반 구조라는 점에서 다른 IPC 방식들과는 조금 다른 특징을 갖고 있습니다.
그렇기 때문에 아래와 같은 상황에서 매우 유용하게 활용될 수 있어요.
가장 흔한 예는 두 개의 독립된 응용 프로그램이 간단한 데이터를 교환해야 할 때입니다.
예를 들어, 클립보드 관리 프로그램이 현재 선택된 텍스트를 다른 편집기에 전달하거나, 실행 중인 소프트웨어에 명령어를 전달해야 하는 경우가 있죠.
이런 요구는 복잡한 공유 메모리나 파이프를 사용하지 않고도 WM_COPYDATA 하나로 처리할 수 있습니다.
- 📤명령어 또는 문자열을 다른 앱에 전달할 때
- 🪟수신 프로그램의 윈도우 핸들을 알고 있는 경우
- 💬간단한 구조체나 텍스트 기반 상태 정보 전달
- 🔁다른 앱과의 1:1 실시간 통신이 필요한 경우
또한 WM_COPYDATA는 크로스 프로세스 환경에서도 안정적으로 작동하므로, 런처(launcher)에서 메인 프로그램으로 매개변수를 전달하거나, 플러그인처럼 외부 프로그램이 본체에 데이터를 넘길 때도 자주 사용됩니다.
다만 한 번에 많은 양의 데이터를 주고받기에는 적합하지 않기 때문에, 대량의 바이너리 전송에는 다른 IPC 방식(예: 파이프, 소켓 등)을 고려하는 것이 좋아요.
🛠️ WM_COPYDATA 사용 방법
WM_COPYDATA를 사용하기 위해서는 데이터를 보낼 프로세스(sender)와 받을 프로세스(receiver) 모두 특정한 조건을 갖춰야 합니다.
특히 수신 측은 WM_COPYDATA 메시지를 처리할 수 있는 메시지 루프와 윈도우 핸들(HWND)이 있어야 하며, 구조체 포인터를 올바르게 해석해야 합니다.
📤 데이터를 보내는 쪽 (Sender)
먼저 수신할 윈도우의 핸들(HWND)을 얻은 후, COPYDATASTRUCT 구조체를 만들어 SendMessage를 호출합니다.
데이터는 반드시 메모리 접근이 가능한 포인터로 전달되어야 하며, 포인터를 넘길 때는 유효 범위를 벗어나지 않도록 주의가 필요해요.
COPYDATASTRUCT cds;
cds.dwData = 1; // 사용자 정의 식별자
cds.cbData = strlen("Hello") + 1;
cds.lpData = (PVOID)"Hello";
HWND hReceiver = FindWindow(NULL, L"ReceiverWindowClass");
SendMessage(hReceiver, WM_COPYDATA, (WPARAM)hWnd, (LPARAM)&cds);
📥 데이터를 받는 쪽 (Receiver)
수신 측에서는 메시지 핸들러 함수에서 WM_COPYDATA 메시지를 받아 처리해야 합니다.
LPARAM으로 전달된 COPYDATASTRUCT 포인터를 통해 데이터의 내용과 크기를 읽을 수 있으며, 이때 메모리 복사나 문자열 처리 등을 직접 구현할 수 있어요.
case WM_COPYDATA:
{
PCOPYDATASTRUCT pCDS = (PCOPYDATASTRUCT)lParam;
char* received = (char*)(pCDS->lpData);
MessageBoxA(NULL, received, "수신된 메시지", MB_OK);
return TRUE;
}
break;
구현이 어렵지는 않지만, 포인터와 메시지 전달 순서, 윈도우 핸들 검색 등에서 실수가 생기기 쉬우므로 충분한 테스트가 필요합니다.
🚧 사용할 때 주의할 점
WM_COPYDATA는 간단하고 직관적인 방식이지만, 몇 가지 주의해야 할 점도 있습니다.
특히 보안 문제나 데이터 안정성에 취약할 수 있으므로 실무에서는 신중하게 사용해야 해요.
⚠️ 주의: 수신 측에서 신뢰할 수 없는 데이터가 전달되면, 악성코드나 비정상 동작의 원인이 될 수 있습니다.
- 🔐수신된 데이터를 사용할 때는 반드시 내용 검증 후 처리
- 📏데이터 크기(cbData)는 버퍼 크기보다 초과되지 않도록 체크
- 💥비정상적인 포인터 접근 방지를 위해 memcpy 등은 주의
- 🚫SendMessage는 동기 호출이므로 응답 지연 시 전체 블로킹 발생
또한 WM_COPYDATA는 윈도우 핸들을 기반으로 작동하므로, 수신 프로세스가 반드시 존재하고 정상 동작 중이어야 합니다.
잘못된 HWND를 참조하거나, 수신 프로세스가 메시지를 처리할 준비가 되지 않은 상태라면 오류가 발생하거나 무시될 수 있어요.
복잡한 구조체나 다국어 문자열 등 인코딩 문제가 발생할 수 있는 데이터는 사전에 직렬화하거나 바이트 정렬에 유의하는 것도 중요합니다.
💡 실전 예제로 이해하기
이번에는 실제 응용 프로그램 간에 텍스트 명령어를 전달하는 예제로 WM_COPYDATA의 동작 흐름을 정리해볼게요.
예제 시나리오는 다음과 같습니다.
💡 TIP: 실행기(Launcher) 프로그램에서 “시작” 명령어를 메인 응용프로그램(MainApp)에 전달하는 구조입니다.
- 🔍Launcher에서 MainApp의 HWND를 FindWindow로 검색
- 📤“시작”이라는 문자열을 COPYDATASTRUCT에 담아 전송
- 📥MainApp은 WM_COPYDATA 메시지를 수신 후 “시작” 명령 처리
// Launcher.cpp
COPYDATASTRUCT cds;
cds.dwData = 100; // 명령 구분 코드
cds.cbData = strlen("시작") + 1;
cds.lpData = (PVOID)"시작";
HWND hMain = FindWindow(NULL, L"MainAppWindow");
if (hMain) {
SendMessage(hMain, WM_COPYDATA, (WPARAM)hWnd, (LPARAM)&cds);
}
// MainApp.cpp
case WM_COPYDATA:
{
PCOPYDATASTRUCT pCDS = (PCOPYDATASTRUCT)lParam;
char* cmd = (char*)pCDS->lpData;
if (strcmp(cmd, "시작") == 0) {
DoStartAction(); // 명령 실행 함수
}
return TRUE;
}
break;
이처럼 WM_COPYDATA는 간단한 문자열 기반 명령 처리를 구현할 때 매우 효과적이며, 프로그램 간 연동이나 런처 기능 구현 시에도 널리 활용됩니다.
다만 실제 서비스 환경에서는 보안 검증 및 예외 처리를 충분히 설계하여, 오작동이나 악의적인 데이터 입력에 대비해야 해요.
❓ 자주 묻는 질문 (FAQ)
WM_COPYDATA로 이미지나 파일도 전송할 수 있나요?
대용량 파일 전송에는 적합하지 않으니 별도의 IPC 방식(예: 파이프, 소켓 등)을 고려하는 것이 좋습니다.
메시지를 수신할 윈도우 핸들은 어떻게 찾나요?
정확한 문자열이 일치해야 하므로 주의가 필요합니다.
수신 측에서 메시지를 받지 못하는 경우는 왜 그런가요?
HWND가 올바르게 전달되었는지도 확인해보세요.
보낸 쪽과 받는 쪽이 서로 다른 언어(C++, C# 등)여도 WM_COPYDATA를 사용할 수 있나요?
다만 바이트 정렬(struct packing)과 문자열 인코딩(CP949, UTF-8 등)은 반드시 맞춰야 합니다.
데이터 전송 중 충돌이나 블루스크린이 발생할 수 있나요?
따라서 항상 데이터 유효성 검사를 철저히 해야 합니다.
SendMessage 대신 PostMessage로 WM_COPYDATA를 보낼 수 있나요?
비동기 전송을 원한다면 다른 IPC 방식을 고려해야 합니다.
보낸 메시지의 수신 여부를 확인할 수 있나요?
단, 반환값만으로 모든 수신 상태를 판단하기엔 한계가 있어 명시적인 응답 메시지를 사용하는 것이 더 안전합니다.
보안적으로 안전한 방식인가요?
전달받은 데이터에 대한 검증 로직을 반드시 구현하고, 필요 시 프로세스 간 인증 절차를 도입하는 것이 좋습니다.
🧩 메시지 기반 IPC, WM_COPYDATA로 윈도우 프로세스 연결하기
이번 글에서는 윈도우에서 제공하는 메시지 기반 IPC 방식인 WM_COPYDATA에 대해 살펴봤습니다.
이 메시지는 별도의 복잡한 설정 없이도 프로세스 간 간단한 데이터 전송이 가능하며, 구조체나 문자열을 안정적으로 주고받을 수 있는 장점이 있습니다.
실제 사용 예제와 함께 송수신 구조를 설명하면서, 어떤 상황에서 쓰면 좋은지, 사용할 때 주의할 점도 함께 다뤘죠.
간단한 명령어 전달이나 앱 간 연동 기능이 필요할 때, WM_COPYDATA는 가장 손쉬운 해결책이 될 수 있습니다.
하지만 잘못 사용하면 보안상 취약해질 수 있으므로 반드시 데이터 유효성 검사와 구조 설계를 함께 고려해야 해요.
앞으로 WinAPI 기반 개발을 하실 때 이 메시지를 효과적으로 활용해보시길 바랍니다.
🏷️ 관련 태그 : WinAPI, IPC, WM_COPYDATA, 프로세스간통신, 윈도우개발, 메시지통신, C언어, SendMessage, HWND, 구조체전달