메뉴 닫기

WinAPI로 윈도우 간 데이터를 안전하게 주고받는 법, WM_COPYDATA로 해결!

🪟 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를 호출합니다.
데이터는 반드시 메모리 접근이 가능한 포인터로 전달되어야 하며, 포인터를 넘길 때는 유효 범위를 벗어나지 않도록 주의가 필요해요.

CODE BLOCK
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 포인터를 통해 데이터의 내용과 크기를 읽을 수 있으며, 이때 메모리 복사나 문자열 처리 등을 직접 구현할 수 있어요.

CODE BLOCK
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 메시지를 수신 후 “시작” 명령 처리
CODE BLOCK
// 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);
}

CODE BLOCK
// 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 방식(예: 파이프, 소켓 등)을 고려하는 것이 좋습니다.
메시지를 수신할 윈도우 핸들은 어떻게 찾나요?
일반적으로 FindWindow 함수에 클래스 이름이나 캡션(타이틀)을 인자로 넘겨 윈도우 핸들을 검색합니다.
정확한 문자열이 일치해야 하므로 주의가 필요합니다.
수신 측에서 메시지를 받지 못하는 경우는 왜 그런가요?
수신 윈도우가 아직 생성되지 않았거나, WM_COPYDATA 메시지를 처리하는 코드가 없을 경우 메시지를 무시할 수 있습니다.
HWND가 올바르게 전달되었는지도 확인해보세요.
보낸 쪽과 받는 쪽이 서로 다른 언어(C++, C# 등)여도 WM_COPYDATA를 사용할 수 있나요?
가능합니다. 언어가 다르더라도 구조체 포맷과 메시지 처리 방식이 동일하면 WM_COPYDATA로 통신이 가능합니다.
다만 바이트 정렬(struct packing)과 문자열 인코딩(CP949, UTF-8 등)은 반드시 맞춰야 합니다.
데이터 전송 중 충돌이나 블루스크린이 발생할 수 있나요?
일반적인 경우에는 드물지만, 잘못된 포인터 접근이나 크기 오류가 있으면 프로그램이 강제 종료될 수 있습니다.
따라서 항상 데이터 유효성 검사를 철저히 해야 합니다.
SendMessage 대신 PostMessage로 WM_COPYDATA를 보낼 수 있나요?
아닙니다. WM_COPYDATA는 동기 방식이기 때문에 반드시 SendMessage를 사용해야 하며, PostMessage로는 동작하지 않습니다.
비동기 전송을 원한다면 다른 IPC 방식을 고려해야 합니다.
보낸 메시지의 수신 여부를 확인할 수 있나요?
SendMessage는 수신 측 메시지 핸들러가 TRUE를 반환하면 성공으로 간주할 수 있습니다.
단, 반환값만으로 모든 수신 상태를 판단하기엔 한계가 있어 명시적인 응답 메시지를 사용하는 것이 더 안전합니다.
보안적으로 안전한 방식인가요?
기본적으로 신뢰할 수 있는 애플리케이션 간 통신을 전제로 만들어진 방식이기 때문에, 외부 공격에 취약할 수 있습니다.
전달받은 데이터에 대한 검증 로직을 반드시 구현하고, 필요 시 프로세스 간 인증 절차를 도입하는 것이 좋습니다.

🧩 메시지 기반 IPC, WM_COPYDATA로 윈도우 프로세스 연결하기

이번 글에서는 윈도우에서 제공하는 메시지 기반 IPC 방식인 WM_COPYDATA에 대해 살펴봤습니다.
이 메시지는 별도의 복잡한 설정 없이도 프로세스 간 간단한 데이터 전송이 가능하며, 구조체나 문자열을 안정적으로 주고받을 수 있는 장점이 있습니다.
실제 사용 예제와 함께 송수신 구조를 설명하면서, 어떤 상황에서 쓰면 좋은지, 사용할 때 주의할 점도 함께 다뤘죠.

간단한 명령어 전달이나 앱 간 연동 기능이 필요할 때, WM_COPYDATA는 가장 손쉬운 해결책이 될 수 있습니다.
하지만 잘못 사용하면 보안상 취약해질 수 있으므로 반드시 데이터 유효성 검사와 구조 설계를 함께 고려해야 해요.
앞으로 WinAPI 기반 개발을 하실 때 이 메시지를 효과적으로 활용해보시길 바랍니다.


🏷️ 관련 태그 : WinAPI, IPC, WM_COPYDATA, 프로세스간통신, 윈도우개발, 메시지통신, C언어, SendMessage, HWND, 구조체전달