MFC에서 SendMessage와 PostMessage로 윈도우 메시지를 직접 전송하는 방법
📌 메시지 기반의 윈도우 프로그래밍 핵심, 직접 명령을 전달하는 기술을 배워보세요
MFC에서 윈도우 간 통신을 구현할 때 SendMessage와 PostMessage는 매우 중요한 역할을 합니다.
특정 윈도우에 명령을 직접 내리거나, 사용자 정의 메시지를 전달할 수 있는 강력한 도구이기 때문이죠.
초보 개발자일수록 메시지 기반 구조에 낯설 수 있지만, 이 두 함수를 제대로 이해하면 프로그램 흐름을 보다 자유롭게 제어할 수 있게 됩니다.
이번 글에서는 이 두 함수의 차이점과 사용법, 실전 예제까지 모두 정리해 드릴게요.
MFC로 윈도우 애플리케이션을 개발하신다면 반드시 알아두셔야 할 필수 개념이니 끝까지 집중해서 읽어보세요!
글에서는 윈도우 메시지 구조와 처리 흐름부터 시작해, SendMessage와 PostMessage의 동작 방식, 사용자 정의 메시지를 만드는 법, 그리고 실전 예제 코드까지 상세히 소개합니다.
또한 언제 어떤 함수를 선택해야 할지, 사용 시 주의할 점까지 함께 알려드릴게요.
📋 목차
🔗 윈도우 메시지 시스템이란?
Windows 운영체제는 사용자 입력, 시스템 이벤트, 프로그램 간의 통신을 메시지(Message)라는 구조로 처리합니다.
모든 윈도우 애플리케이션은 이 메시지를 받아 처리하는 메시지 루프(Message Loop)와 윈도우 프로시저(Window Procedure)를 기반으로 동작하죠.
사용자가 버튼을 클릭하거나, 타이핑을 하거나, 윈도우가 리사이즈되는 등 다양한 이벤트는 시스템 메시지로 생성되어 대상 윈도우로 전달됩니다.
이 메시지는 HWND (윈도우 핸들)을 기반으로 특정 윈도우에 전달되며, 해당 윈도우는 이를 처리해 적절한 반응을 하게 됩니다.
📌 메시지 루프와 윈도우 프로시저
MFC나 Win32 API 기반의 애플리케이션에서는 보통 다음과 같은 흐름으로 메시지를 처리합니다.
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
이 루프는 운영체제로부터 메시지를 받아 처리하며, DispatchMessage 함수는 실제로 메시지를 해당 윈도우 프로시저로 전달해 줍니다.
결국 메시지를 받아서 처리하는 핵심은 윈도우 프로시저에 있으며, 여기서 메시지의 종류에 따라 분기하여 필요한 동작을 수행하게 됩니다.
📌 시스템 메시지 vs 사용자 정의 메시지
Windows에는 WM_PAINT, WM_COMMAND, WM_CLOSE 같은 수많은 시스템 메시지가 정의되어 있습니다.
하지만 때로는 프로그램 내부적으로 자체 메시지를 정의해서 특정 동작을 수행해야 할 때도 있죠.
이때 사용할 수 있는 것이 WM_USER 이후의 메시지 번호를 활용한 사용자 정의 메시지입니다.
이 사용자 정의 메시지를 다른 윈도우로 보내기 위해 사용하는 함수가 바로 SendMessage와 PostMessage입니다.
이 두 함수는 메시지를 전송하는 방식에서 차이를 보이는데, 다음 STEP에서 그 차이를 자세히 알아보겠습니다.
🛠️ SendMessage와 PostMessage의 차이
SendMessage와 PostMessage는 둘 다 특정 윈도우에 메시지를 전달하는 함수입니다.
하지만 메시지를 처리하는 타이밍과 흐름 제어에 있어 중요한 차이가 있습니다.
📌 SendMessage
SendMessage는 메시지를 보낸 함수가 즉시 대상 윈도우로 메시지를 전달하고, 해당 메시지가 완전히 처리될 때까지 대기합니다.
즉, 동기(Synchronous) 방식입니다.
SendMessage(hWnd, WM_USER + 1, 0, 0);
이 방식은 메시지 처리 결과가 필요하거나, 순차적인 처리가 필요한 경우에 적합합니다.
하지만 처리 시간이 길 경우 호출한 쓰레드가 블로킹될 수 있으므로 주의가 필요합니다.
📌 PostMessage
PostMessage는 메시지를 윈도우의 메시지 큐에 넣기만 하고 즉시 반환합니다.
즉, 비동기(Asynchronous) 방식이며, 메시지는 나중에 메시지 루프에 의해 처리됩니다.
PostMessage(hWnd, WM_USER + 1, 0, 0);
호출한 쓰레드는 멈추지 않고 다음 코드로 즉시 넘어가기 때문에, 메시지 처리 순서를 보장할 필요가 없거나, 응답성이 중요한 작업에 적합합니다.
단, 메시지 처리 완료 여부는 알 수 없다는 점이 단점입니다.
- 📨SendMessage: 메시지 즉시 처리, 호출 쓰레드 대기
- 📬PostMessage: 메시지 큐에 등록만, 호출 쓰레드 즉시 반환
💎 핵심 포인트:
응답 대기 여부와 메시지 처리 타이밍이 중요하다면 SendMessage, 그렇지 않다면 PostMessage가 적합합니다.
⚙️ 사용자 정의 메시지 만들기
Windows에서는 기본 시스템 메시지 외에도 개발자가 직접 메시지를 정의하여 사용할 수 있습니다.
이런 메시지를 사용자 정의 메시지라고 부르며, WM_USER 이후의 값을 기반으로 정의합니다.
보통 헤더 파일이나 클래스 상단에서 다음과 같이 정의합니다.
#define WM_MY_MESSAGE (WM_USER + 100)
이제 해당 메시지를 처리할 핸들러를 윈도우 프로시저 또는 메시지 맵에 추가해야 합니다.
MFC에서는 ON_MESSAGE 매크로를 사용하여 사용자 정의 메시지를 등록합니다.
📌 MFC 메시지 맵에 등록
BEGIN_MESSAGE_MAP(CMyDialog, CDialogEx)
ON_MESSAGE(WM_MY_MESSAGE, OnMyMessage)
END_MESSAGE_MAP()
LRESULT CMyDialog::OnMyMessage(WPARAM wParam, LPARAM lParam)
{
AfxMessageBox(_T("사용자 정의 메시지 수신!"));
return 0;
}
이제 다른 클래스나 모듈에서 해당 다이얼로그로 메시지를 보낼 수 있습니다.
앞에서 배운 SendMessage 또는 PostMessage 함수를 활용해 아래처럼 호출할 수 있습니다.
::SendMessage(hWndTarget, WM_MY_MESSAGE, 0, 0);
// 또는
::PostMessage(hWndTarget, WM_MY_MESSAGE, 0, 0);
💡 TIP: 사용자 정의 메시지는 같은 애플리케이션 내에서 윈도우 간 통신을 구현할 때 매우 유용하며, 쓰레드 간 데이터 전달에도 활용됩니다.
🔌 실전 예제로 배우는 메시지 전송
MFC에서 SendMessage와 PostMessage를 실제로 어떻게 사용하는지 예제를 통해 알아보겠습니다.
아래는 두 개의 대화 상자(Dialog) 간에 메시지를 주고받는 구조입니다.
📌 시나리오
메인 다이얼로그(MainDlg)가 보조 다이얼로그(SubDlg)에 사용자 정의 메시지를 보내 특정 동작을 요청합니다.
예를 들어 SubDlg에 텍스트를 표시하라는 명령입니다.
📌 메시지 정의 및 처리
// 메시지 정의
#define WM_UPDATE_TEXT (WM_USER + 101)
// SubDlg 메시지 핸들러
LRESULT CSubDlg::OnUpdateText(WPARAM wParam, LPARAM lParam)
{
SetDlgItemText(IDC_STATIC_TEXT, _T("메시지를 수신했습니다!"));
return 0;
}
BEGIN_MESSAGE_MAP(CSubDlg, CDialogEx)
ON_MESSAGE(WM_UPDATE_TEXT, OnUpdateText)
END_MESSAGE_MAP()
📌 메시지 전송
// MainDlg에서 메시지 전송
subDlgPtr->SendMessage(WM_UPDATE_TEXT, 0, 0);
이와 같은 방식으로 다양한 동작을 원격으로 지시할 수 있으며, 특히 모듈 간 결합도를 낮추는 데 유리합니다.
메시지를 통해 요청을 전달하고, 수신 측에서 자유롭게 해석하고 처리하는 구조이기 때문에 유연성과 확장성을 동시에 얻을 수 있죠.
💎 핵심 포인트:
실제 UI 구성 요소나 쓰레드 간 데이터를 제어할 때 메시지 전송은 매우 강력한 도구가 됩니다. 단, HWND 관리에 유의하세요.
💡 Send와 Post 선택 기준 및 주의사항
SendMessage와 PostMessage는 모두 유용한 API지만, 무작정 사용하는 것은 오히려 프로그램의 안정성과 성능에 악영향을 줄 수 있습니다.
적절한 상황에서 올바르게 선택하는 것이 무엇보다 중요합니다.
📌 어떤 상황에서 SendMessage를 사용할까?
메시지를 보낸 쪽에서 결과 값을 즉시 받아야 하거나, 메시지 처리 순서가 중요한 경우 SendMessage가 적합합니다.
예를 들어 상태 동기화, 결과 반환이 필요한 경우에 효과적입니다.
📌 PostMessage가 유리한 경우는?
작업 처리를 요청만 하고 결과에 관심이 없는 경우, 또는 UI 응답성을 확보하고 싶을 때 PostMessage가 좋습니다.
예를 들어 다른 쓰레드에 작업을 요청하거나, 무거운 처리를 큐에 넘길 때 사용합니다.
- ✅즉시 응답 필요 시 → SendMessage
- 🚀비동기 처리 또는 멀티쓰레드 통신 시 → PostMessage
⚠️ 주의: PostMessage로 보낸 메시지는 대상 윈도우가 이미 파괴된 경우 무시되므로, HWND 유효성 검사가 반드시 필요합니다.
또한 사용자 정의 메시지를 설계할 때는 WM_USER 이상의 범위를 벗어나지 않도록 주의해야 하며, 메시지 번호 충돌이 발생하지 않도록 전역적인 설계 기준이 필요합니다.
💎 핵심 포인트:
SendMessage는 동기, PostMessage는 비동기 방식입니다. 목적에 따라 올바르게 선택하고, HWND와 메시지 정의를 신중히 관리하는 것이 안정적인 메시지 설계의 핵심입니다.
❓ 자주 묻는 질문 (FAQ)
SendMessage와 PostMessage 중 속도가 빠른 것은 무엇인가요?
사용자 정의 메시지는 어떤 번호를 써야 하나요?
다른 쓰레드에서 SendMessage를 사용해도 되나요?
PostMessage로 보낸 메시지는 반드시 처리되나요?
메시지 핸들러에서 반환값은 어떻게 쓰이나요?
메시지를 전역으로 처리하고 싶다면 어떻게 해야 하나요?
WM_COMMAND와 사용자 정의 메시지는 뭐가 다른가요?
메시지 처리 우선순위를 설정할 수 있나요?
📌 윈도우 메시지 전송 기술로 더 유연한 MFC 프로그램 만들기
MFC에서 SendMessage와 PostMessage는 윈도우 간 통신의 핵심 도구로, 적절히 활용하면 애플리케이션의 구조를 더 깔끔하고 유연하게 만들 수 있습니다.
동기와 비동기 메시지 전송의 차이를 이해하고, 사용자 정의 메시지를 통해 명확한 역할 분리와 이벤트 전달 구조를 설계하는 것이 중요합니다.
실전 예제와 함께 학습한 내용을 바탕으로, 이제는 여러분의 프로젝트에서도 직접 메시지를 설계하고 활용해 보시기 바랍니다.
단순한 명령 전송을 넘어, 다양한 UI 요소나 모듈 간 커뮤니케이션을 유기적으로 엮을 수 있는 메시지 시스템은 MFC 프로그래밍에서 꼭 익혀야 할 필수 기술입니다.
이번 글을 통해 그 핵심 원리와 실전 사용법까지 익히셨기를 바랍니다.
🏷️ 관련 태그 : MFC, SendMessage, PostMessage, 윈도우메시지, 사용자정의메시지, 메시지루프, 윈도우핸들, 동기처리, 비동기처리, 메시지통신