본문 바로가기
프로그래밍/MFC (C++)

MFC ] 사용자 지정 메시지와 메시지 처리기 만들기, SendMessage, PostMessage

by eteo 2023. 9. 15.

 

 

메뉴에서 프로젝트 - 클래스 마법사 - -Dlg클래스 선택 - 사용자 지정 메시지 추가로 추가하는 방법도 있다.

 

방법

 

먼저 사용자 지정 메시지를 정의한다.

 

#define MY_MSG1				(WM_USER + 1)
#define MY_MSG2				(WM_USER + 2)

 

Windows API에는 미리 정의된 메시지 상수가 많이 있지만, 애플리케이션의 필요에 따라 추가적인 사용자 지정 메시지를 정의할 수 있는데, 이때 WM_USER를 사용하여 사용자 지정 메시지의 베이스 값을 설정한다. WM_USER의 값은 0x0400으로 (WM_USER + n) 이런식으로 정의하면 다른 시스템 또는 프레임워크 메시지와 충돌하지 않도록 할 수 있다.

 

 

 

다음은 다이얼로그 헤더에 메시지 처리기를 추가한다.

 

afx_msg LRESULT MyMessageHandler(WPARAM wParam, LPARAM lParam);

 

다이얼로그 cpp 파일에서 메시지 맵에 메시지와 처리기를 연결시키고 처리기 함수를 구현한다.

BEGIN_MESSAGE_MAP(CRwrTesterDlg, CDialogEx)
	// ...
	ON_MESSAGE(MY_MSG, MyMessageHandler)
	// ...
END_MESSAGE_MAP()

 

 

afx_msg LRESULT AppDlg::MyMessageHandler(WPARAM wParam, LPARAM lParam)
{
	CString* pStr = (CString*)lParam;

	m_listBox.InsertString(m_listBox.GetCount(), *pStr);
    
	delete pStr;
	return NULL;
}

 

 

어플리케이션에서 아래와 같이 메시지를 전송한다.

CString* pStr = new CString(_T("Hello World!"));

HWND hWnd = AfxGetApp()->m_pMainWnd->m_hWnd;
PostMessage(hWnd, MY_MSG, NULL, (LPARAM)pStr);
// 혹은 this->PostMessage(MY_MSG, NULL, (LPARAM)pStr);

 

PostMessage 방식을 썼기 때문에 메시지 처리기에서 데이터를 처리한 후 메모리를 해제할 수 있도록 신경써야 한다. 메시지를 보내는 쪽에서 new 로 메모리를 할당하고 처리기에서 delete로 메모리를 해제한다. 처리기에서는 값 멤버변수가 아니라 컨트롤을 직접 조작하기 때문에 데이터와 컨트롤을 동기화 하는 UpdateData는 호출하지 않았다.

 

 

 

WPARAM과 LPARAM

 

WPARAM과 LPARAM은 Windows 프로그래밍에서 메시지 처리시 사용되는 두 개의 데이터 형식이다.

 

1. WPARAM : Word Parameter의 약자로, 16비트 부호 없는 정수(unsigned short)이다. WPARAM은 일반적으로 메시지와 관련된 추가 정보를 전달하기 위해 사용된다. 예를 들면, 버튼 클릭과 같은 이벤트에서 어떤 버튼이 클릭되었는지를 식별하는 데 사용될 수 있다.

 

2. LPARAM : Long Parameter의 약자로, 32비트 부호 있는 정수(int)이다. LPARAM은 주로 메시지와 연결된 데이터나 포인터를 전달하는 데 사용된다. 예를 들어, 텍스트 입력 필드에서 텍스트를 전달하거나, 객체에 대한 포인터를 전달할 때 사용될 수 있다.

 

 

위 사례에서는 문자열 데이터에 대한 포인터를 전달하기에 LPARAM을 사용하였고 WPARAM은 NULL 값을 넘겼다.

 

 

 

SendMessage와 PostMessage

 

SendMessage와 PostMessage 함수는 위와 같이 사용자 정의 메시지를 트리거하기 위해 사용할 수 도 있고, 스레드간 메시지를 전달해야 할 경우 사용할 수 있다. 

 

예를 들면 윈도우와 컨트롤에 접근하는 건 UI 스레드에서 독점적으로 해야 안전하므로 다른 스레드에서 UI 관련 작업이 필요하면 UI 스레드에 메시지를 보내(SendMessage, PostMessage) UI 스레드에서 처리하도록 할 수 있다.

 

SendMessage와 PostMessage의 차이

 

1. SendMessage : 메시지를 동기적으로 보낸다. 이 함수는 호출한 스레드에서 대상 윈도우의 메시지 처리기(윈도우 프로시저)를 직접 호출하고 메시지 처리가 완료된 후 결과를 반환한다. 즉., 메시지 처리가 완료될 때까지 호출 스레드는 블록될 수 있다.

 

2. PostMessage : 메시지를 비동기적으로 보낸다. 이 함수는 호출되자마자 메시지를 핸들의 메시지 큐에 삽입한 뒤 제어를 반환하며, 대상 윈도우의 메시지 처리기(윈도우 프로시저)는 나중에 이벤트 큐에서 메시지를 처리한다. 즉, 호출 스레드는 대기하지 않고 다른 작업을 수행할 수 있다.

 

  • hWnd: 메시지를 수신할 대상 윈도우의 핸들. 
  • Msg: 보낼 메시지 ID. 
  • wParam과 lParam: 메시지와 관련된 추가 데이터.