MS-DOS 기반 애플리케이션과 달리 Windows 기반 애플리케이션은 이벤트 기반입니다. 입력을 얻기 위해 명시적 함수 호출(예: C 런타임 라이브러리 호출)을 수행하지 않습니다. 대신 시스템이 입력을 전달할 때까지 기다립니다.
시스템은 애플리케이션의 모든 입력을 애플리케이션의 다양한 창에 전달합니다. 각 창에는 창에 대한 입력이 있을 때마다 시스템에서 호출하는 창 프로시저라는 함수가 있습니다. 창 프로시저는 입력을 처리하고 시스템에 컨트롤을 반환합니다. 창 프로시저에 대한 자세한 내용은 창 프로시저참조하세요.
최상위 창이 몇 초 이상 메시지에 응답하지 않는 경우 시스템은 창이 응답하지 않는 것으로 간주합니다. 이 경우 시스템은 창을 숨기고 Z 순서, 위치, 크기 및 시각적 특성이 동일한 고스트 창으로 바꿉니다. 이렇게 하면 사용자가 이동하거나 크기를 조정하거나 애플리케이션을 닫을 수 있습니다. 그러나 애플리케이션이 실제로 응답하지 않기 때문에 이러한 작업만 사용할 수 있습니다. 디버거 모드에서는 시스템에서 고스트 창을 생성하지 않습니다.
이 섹션에서는 다음 항목에 대해 설명합니다.
Windows 메시지
시스템은 메시지형식의 창 프로시저에 입력을 전달합니다. 메시지는 시스템과 애플리케이션 모두에서 생성됩니다. 시스템은 사용자가 입력하거나 마우스를 이동하거나 스크롤 막대와 같은 컨트롤을 클릭할 때와 같이 각 입력 이벤트에서 메시지를 생성합니다. 또한 시스템은 애플리케이션이 시스템 글꼴 리소스 풀을 변경하거나 창 중 하나의 크기를 조정하는 경우와 같이 애플리케이션에서 가져온 시스템의 변경에 대한 응답으로 메시지를 생성합니다. 애플리케이션은 작업을 수행하거나 다른 애플리케이션의 창과 통신하도록 자체 창을 지시하는 메시지를 생성할 수 있습니다.
시스템은 네 개의 매개 변수 집합, 즉 창 핸들, 메시지 식별자 및 두 개의 값 메시지 매개 변수를 사용하여 창 프로시저에 메시지를 보냅니다. 창 핸들 메시지가 의도된 창을 식별합니다. 시스템에서 이를 사용하여 메시지를 받아야 하는 창 프로시저를 결정합니다.
메시지 식별자 메시지의 용도를 식별하는 명명된 상수입니다. 창 프로시저는 메시지를 받으면 메시지 식별자를 사용하여 메시지를 처리하는 방법을 결정합니다. 예를 들어 메시지 식별자 WM_PAINT 창의 클라이언트 영역이 변경되었으며 다시 그려야 한다는 것을 창 프로시저에 알립니다.
메시지 매개 변수는 메시지를 처리할 때 창 프로시저에서 사용되는 데이터 또는 데이터의 위치를 지정합니다. 메시지 매개 변수의 의미와 값은 메시지에 따라 달라집니다. 메시지 매개 변수에는 정수, 압축된 비트 플래그, 추가 데이터가 포함된 구조체에 대한 포인터 등이 포함될 수 있습니다. 메시지가 메시지 매개 변수를 사용하지 않는 경우 일반적으로 NULL 설정됩니다. 창 프로시저는 메시지 식별자를 확인하여 메시지 매개 변수를 해석하는 방법을 결정해야 합니다.
메시지 유형
이 섹션에서는 두 가지 유형의 메시지에 대해 설명합니다.
System-Defined 메시지
시스템은 애플리케이션과 통신할 때 시스템 정의 메시지 보내거나 게시합니다. 이러한 메시지를 사용하여 애플리케이션의 작업을 제어하고 애플리케이션이 처리할 입력 및 기타 정보를 제공합니다. 애플리케이션은 시스템 정의 메시지를 보내거나 게시할 수도 있습니다. 애플리케이션은 일반적으로 이러한 메시지를 사용하여 미리 등록된 창 클래스를 사용하여 만든 제어 창의 작업을 제어합니다.
각 시스템 정의 메시지에는 고유한 메시지 식별자와 메시지의 용도를 나타내는 해당 기호 상수(SDK(소프트웨어 개발 키트) 헤더 파일에 정의됨)가 있습니다. 예를 들어 WM_PAINT 상수는 창이 내용을 그리는 것을 요청합니다.
기호 상수는 시스템 정의 메시지가 속한 범주를 지정합니다. 상수의 접두사는 메시지를 해석하고 처리할 수 있는 창 유형을 식별합니다. 접두사 및 관련 메시지 범주는 다음과 같습니다.
| 접두사 | 메시지 범주 | 문서 |
|---|---|---|
| ABM 및 ABN | 애플리케이션 데스크톱 도구 모음 | 셸 메시지 및 알림 |
| ACM 및 ACN | 애니메이션 컨트롤 | 애니메이션 컨트롤 메시지 및 애니메이션 컨트롤 알림 |
| BCM, BCN, BM및 BN | 버튼 컨트롤 | 단추 컨트롤 메시지 및 단추 컨트롤 알림 |
| CB 및 CBN | ComboBox 컨트롤 | ComboBox 컨트롤 메시지 및 ComboBox 컨트롤 알림 |
| CBEM 및 CBEN | ComboBoxEx 컨트롤 | ComboBoxEx 메시지 및 ComboBoxEx 알림 |
| CCM | 일반 제어 | 제어 메시지 |
| CDM | 일반 대화 상자 | 일반적인 대화 상자 메시지 |
| DFM | 기본 상황에 맞는 메뉴 | 셸 메시지 및 알림 |
| DL | 목록 상자 끌기 | 드래그 목록 상자 알림 |
| DM | 기본 푸시 단추 컨트롤 | 대화 상자 메시지 |
| DTM 및 DTN | 날짜 및 시간 선택 컨트롤 | 날짜 및 시간 선택기 메시지 및 날짜 및 시간 선택 알림 |
| EM 및 EN | 컨트롤 편집 | 편집 컨트롤 메시지, 편집 컨트롤 알림, 서식 있는 편집 메시지, 및 서식 있는 편집 알림 |
| HDM 및 HDN | 헤더 제어 | 헤더 컨트롤 메시지 및 헤더 컨트롤 알림 |
| HKM | 단축키 제어 | 핫 키 제어 메시지 |
| IPM 및 IPN | IP 주소 제어 | IP 주소 메시지 및 IP 주소 알림 |
| LB 및 LBN | 목록 상자 컨트롤 | 목록 상자 메시지 및 목록 상자 알림 |
| LM | SysLink 컨트롤 | SysLink 제어 메시지 |
| LVM 및 LVN | 목록 보기 컨트롤 | 목록 보기 메시지 및 목록 보기 알림 |
| MCM 및 MCN | 월별 달력 기능 | 월 일정 메시지 및 월 달력 알림 |
| PBM | 진행률 표시줄 | 진행률 표시줄 메시지 |
| PGM 및 PGN | 페이지 네비게이션 컨트롤 | 호출기 제어 메시지 및 호출기 제어 알림 |
| PSM 및 PSN | 속성 시트 | 속성 시트 메시지 및 속성 시트 알림 |
| RB 및 RBN | 철근 관리 | Rebar 제어 메시지 및 Rebar 제어 알림 |
| SB 및 SBN | 상태 표시줄 창 | 상태 표시줄 메시지 및 상태 표시줄 알림 |
| SBM | 스크롤 막대 컨트롤 | 스크롤 막대 메시지 |
| SMC | 셸 메뉴 | 셸 메시지 및 알림 |
| STM 및 STN | 정적 컨트롤 | 정적 제어 메시지 및 정적 제어 알림 |
| TB 및 TBN | 도구 모음 | 도구 모음 컨트롤 메시지 및 도구 모음 컨트롤 알림 |
| TBM 및 TRBN | 트랙바 컨트롤 | 트랙바 컨트롤 메시지 및 트랙바 컨트롤 알림 |
| TCMTCN | 탭 컨트롤 | 탭 제어 메시지 및 탭 제어 알림 |
| TDM 및 TDN | 작업 대화 상자 | 작업 대화 상자 메시지 및 작업 대화 상자 알림 |
| TTM 및 TTN | 툴팁 제어 | 도구 설명 컨트롤 메시지 및 도구 설명 컨트롤 알림 |
| TVM 및 TVN | 트리 뷰 컨트롤 | 트리 뷰 메시지 및 트리 뷰 알림 |
| UDM 및 UDN | 상하 제어 | Up-Down 메시지 및 Up-Down 알림 |
| WM | 일반 |
|
일반 창 메시지는 마우스 및 키보드 입력, 메뉴 및 대화 상자 입력, 창 만들기 및 관리, DDE(동적 데이터 교환)에 대한 메시지를 포함하여 다양한 정보와 요청을 다룹니다.
Application-Defined 메시지
애플리케이션은 자체 창에서 사용하거나 다른 프로세스의 창과 통신하는 데 사용할 메시지를 만들 수 있습니다. 애플리케이션에서 자체 메시지를 만드는 경우 메시지를 수신하는 창 프로시저는 메시지를 해석하고 적절한 처리를 제공해야 합니다.
메시지 식별자 값은 다음과 같이 사용됩니다.
- 시스템은 시스템 정의 메시지에 대해 0x0000부터 0x03FF(WM_USER – 1의 값까지) 범위의 메시지 식별자 값을 예약합니다. 애플리케이션은 프라이빗 메시지에 이러한 값을 사용할 수 없습니다.
- 0x0400부터 0x7FFF까지의 범위 내 값(WM_USER값)은 프라이빗 창 클래스의 메시지 식별자로 사용할 수 있습니다.
- 애플리케이션이 버전 4.0으로 표시된 경우 개인 메시지에 대한 0xBFFF 통해 범위 0x8000(WM_APP)의 메시지 식별자 값을 사용할 수 있습니다.
- 시스템에서는 애플리케이션이 RegisterWindowMessage 함수를 호출하여 메시지를 등록할 때 0xFFFF 0xC000 범위의 메시지 식별자를 반환합니다. 이 함수에서 반환된 메시지 식별자는 시스템 전체에서 고유하도록 보장됩니다. 이 함수를 사용하면 다른 애플리케이션에서 다른 용도로 동일한 메시지 식별자를 사용하는 경우 발생할 수 있는 충돌을 방지할 수 있습니다.
메시지 라우팅
시스템은 메시지를 창 프로시저로 라우팅하는 두 가지 방법을 사용합니다. 즉, 메시지를 일시적으로 저장하는 시스템 정의 메모리 개체인 메시지 큐라고 하는 선입선출 큐에 메시지를 게시하고 창 프로시저에 직접 메시지를 보냅니다.
메시지 큐에 게시되는 메시지를 큐에 대기된 메시지라고 합니다. 이는 주로 마우스 또는 키보드를 통해 입력된 사용자 입력(예: WM_MOUSEMOVE, WM_LBUTTONDOWN, WM_KEYDOWN및 WM_CHAR 메시지)의 결과입니다. 대기하는 다른 메시지에는 타이머, 페인트 및 종료 메시지(WM_TIMER, WM_PAINT및 WM_QUIT포함)가 있습니다. 창 프로시저로 직접 전송되는, 큐에 추가되지 않은 메시지는 대부분의 다른 메시지로 불립니다 .
큐에 대기 중인 메시지
시스템은 한 번에 임의의 수의 창을 표시할 수 있습니다. 마우스 및 키보드 입력을 적절한 창으로 라우팅하기 위해 시스템은 메시지 큐를 사용합니다.
시스템은 각 GUI 스레드에 대해 단일 시스템 메시지 큐와 하나의 스레드별 메시지 큐를 유지 관리합니다. GUI가 아닌 스레드에 대한 메시지 큐를 만드는 오버헤드를 방지하기 위해 모든 스레드는 처음에 메시지 큐 없이 만들어집니다. 시스템은 스레드가 특정 사용자 함수 중 하나에 대한 첫 번째 호출을 할 때만 스레드별 메시지 큐를 만듭니다. GUI 함수 호출이 없을 경우 메시지 큐가 생성됩니다.
사용자가 마우스를 이동하거나 마우스 단추를 클릭하거나 키보드에서 유형을 입력할 때마다 마우스 또는 키보드의 디바이스 드라이버는 입력을 메시지로 변환하고 시스템 메시지 큐에 배치합니다. 시스템은 시스템 메시지 큐에서 메시지를 한 번에 하나씩 제거하고, 메시지를 검사하여 대상 창을 확인한 다음, 대상 창을 만든 스레드의 메시지 큐에 게시합니다. 스레드의 메시지 큐는 스레드에서 만든 창에 대한 모든 마우스 및 키보드 메시지를 받습니다. 스레드는 큐에서 메시지를 제거하고 시스템에서 처리를 위한 적절한 창 프로시저로 보내도록 지시합니다.
WM_PAINT 메시지, WM_TIMER 메시지 및 WM_QUIT 메시지를 제외하고 시스템은 항상 메시지 큐의 끝에 메시지를 게시합니다. 이렇게 하면 창이 적절한 FIFO(첫 번째 입력, 선입선출) 시퀀스로 입력 메시지를 받습니다. 그러나 WM_PAINT 메시지, WM_TIMER 메시지 및 WM_QUIT 메시지는 큐에 유지되며 큐에 다른 메시지가 없는 경우에만 창 프로시저로 전달됩니다. 또한 동일한 창에 대한 여러 WM_PAINT 메시지가 단일 WM_PAINT 메시지로 결합되어 클라이언트 영역의 모든 잘못된 부분을 단일 영역으로 통합합니다. WM_PAINT 메시지를 결합하면 창이 클라이언트 영역의 내용을 다시 그려야 하는 횟수가 줄어듭니다.
시스템은 MSG 구조를 채운 다음 메시지 큐에 복사하여 스레드의 메시지 큐에 메시지를 게시합니다. MSG 정보에는 메시지가 의도된 창 핸들, 메시지 식별자, 두 개의 메시지 매개 변수, 메시지가 게시된 시간 및 마우스 커서 위치가 포함됩니다. 스레드는 PostMessage 또는 PostThreadMessage 함수를 사용하여 메시지를 자체 메시지 큐 또는 다른 스레드의 큐에 게시할 수 있습니다.
애플리케이션은 GetMessage 함수를 사용하여 큐에서 메시지를 제거할 수 있습니다. 큐에서 메시지를 제거하지 않고 메시지를 검사하기 위해 애플리케이션은 PeekMessage 함수를 사용할 수 있습니다. 이 함수는 MSG 메시지에 대한 정보로 채웁니다.
큐에서 메시지를 제거한 후 애플리케이션은 DispatchMessage 함수를 사용하여 시스템에서 처리용 창 프로시저로 메시지를 보내도록 지시할 수 있습니다. DispatchMessage는 이전에 GetMessage 또는 PeekMessage 함수를 호출하여 채워진 MSG의 포인터를 사용합니다. DispatchMessage 창 핸들, 메시지 식별자 및 두 메시지 매개 변수를 창 프로시저에 전달하지만 메시지가 게시된 시간이나 마우스 커서 위치를 전달하지는 않습니다. 애플리케이션은 메시지를 처리하는 동안 GetMessageTime 및 GetMessagePos 함수를 호출하여 이 정보를 검색할 수 있습니다.
스레드는 메시지 큐에 메시지가 없는 경우 WaitMessage 함수를 사용하여 다른 스레드에 대한 제어를 생성할 수 있습니다. 이 함수는 스레드를 일시 중단하고 새 메시지가 스레드의 메시지 큐에 배치될 때까지 반환되지 않습니다.
SetMessageExtraInfo 함수를 호출하여 현재 스레드의 메시지 큐와 값을 연결할 수 있습니다. 그런 다음 GetMessageExtraInfo 함수를 호출하여 GetMessage 또는 PeekMessage 함수에서 검색한 마지막 메시지와 연결된 값을 가져옵니다.
큐에 없는 메시지
큐에 추가되지 않은 메시지는 시스템 메시지 큐 및 스레드 메시지 큐를 우회하여 대상 창 프로시저로 즉시 전송됩니다. 시스템은 일반적으로 큐에 추가되지 않은 메시지를 전송하여 영향을 주는 이벤트 창에 알립니다. 예를 들어 사용자가 새 애플리케이션 창을 활성화하면 시스템에서 WM_ACTIVATE, WM_SETFOCUS및 WM_SETCURSOR포함한 일련의 메시지를 창에 보냅니다. 이러한 메시지는 창이 활성화되고, 키보드 입력이 창으로 전달되고 있으며, 마우스 커서가 창의 테두리 내에서 이동되었음을 창에 알립니다. 큐에 추가되지 않은 메시지는 애플리케이션이 특정 시스템 함수를 호출할 때 발생할 수도 있습니다. 예를 들어 애플리케이션이 SetWindowPos 함수를 사용하여 창을 이동한 후 시스템에서 WM_WINDOWPOSCHANGED 메시지를 보냅니다.
큐에 추가되지 않은 메시지를 보내는 일부 함수는 BroadcastSystemMessage, BroadcastSystemMessageEx, SendMessage, SendMessageTimeout및 SendNotifyMessage입니다.
메시지 처리
애플리케이션은 스레드의 메시지 큐에 게시된 메시지를 제거하고 처리해야 합니다. 단일 스레드 애플리케이션은 일반적으로 WinMain 함수의 메시지 루프 사용하여 메시지를 제거하고 처리를 위한 적절한 창 프로시저로 보냅니다. 스레드가 여러 개 있는 애플리케이션은 창을 만드는 각 스레드에 메시지 루프를 포함할 수 있습니다. 다음 섹션에서는 메시지 루프의 작동 방식을 설명하고 창 프로시저의 역할을 설명합니다.
메시지 루프
간단한 메시지 루프는 GetMessage, TranslateMessage및 DispatchMessage세 가지 함수 각각에 대한 하나의 함수 호출로 구성됩니다. 오류가 있는 경우 GetMessage –1을 반환하므로 특수 테스트가 필요합니다.
MSG msg;
BOOL bRet;
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
GetMessage 함수는 큐에서 메시지를 검색하여 MSG형식의 구조로 복사합니다. WM_QUIT 메시지가 발생하지 않는 한 0이 아닌 값을 반환합니다. 이 경우 FALSE 반환하고 루프를 종료합니다. 단일 스레드 애플리케이션에서 메시지 루프를 종료하는 것이 애플리케이션을 닫는 첫 번째 단계인 경우가 많습니다. 애플리케이션은 PostQuitMessage 함수를 사용하여 자체 루프를 종료할 수 있으며, 일반적으로 애플리케이션 주 창의 창 프로시저에서 WM_DESTROY 메시지에 응답합니다.
창 핸들을 GetMessage두 번째 매개 변수로 지정하면 지정된 창에 대한 메시지만 큐에서 검색됩니다. GetMessage 지정된 범위 내에 있는 메시지만 검색하여 큐의 메시지를 필터링할 수도 있습니다. 메시지 필터링에 대한 자세한 내용은 메시지 필터링참조하세요.
스레드의 메시지 루프는 스레드가 키보드에서 문자 입력을 수신하는 경우 TranslateMessage 포함해야 합니다. 시스템은 사용자가 키를 누를 때마다 가상 키 메시지(WM_KEYDOWN 및 WM_KEYUP)를 생성합니다. 가상 키 메시지에는 누른 키를 식별하는 가상 키 코드가 포함되어 있지만 문자 값은 식별하지 않습니다. 이 값을 검색하려면 메시지 루프에 가상 키 메시지를 문자 메시지(WM_CHAR)로 변환하고 애플리케이션 메시지 큐에 다시 배치하는 TranslateMessage포함되어야 합니다. 그런 다음 메시지 루프의 후속 반복 시 문자 메시지를 제거하고 창 프로시저로 디스패치할 수 있습니다.
DispatchMessage 함수는 MSG 구조에 지정된 창 핸들과 연결된 창 프로시저에 메시지를 보냅니다. 창 핸들이 HWND_TOPMOST경우 DispatchMessage 메시지를 시스템의 모든 최상위 창의 창 프로시저로 보냅니다. 창 핸들이 NULL 경우 DispatchMessage 메시지와 아무 작업도 수행하지 않습니다.
애플리케이션의 주 스레드는 애플리케이션을 초기화하고 하나 이상의 창을 만든 후 메시지 루프를 시작합니다. 시작되면 메시지 루프는 스레드의 메시지 큐에서 메시지를 계속 검색하고 적절한 창으로 디스패치합니다. 메시지 루프는 GetMessage 함수가 메시지 큐에서 WM_QUIT 메시지를 제거하면 종료됩니다.
애플리케이션에 많은 창이 포함되어 있더라도 메시지 큐에는 하나의 메시지 루프만 필요합니다. DispatchMessage 항상 메시지를 적절한 창으로 디스패치합니다. 큐의 각 메시지는 메시지가 속한 창의 핸들을 포함하는 MSG 구조이기 때문입니다.
다양한 방법으로 메시지 루프를 수정할 수 있습니다. 예를 들어 창에 메시지를 디스패치하지 않고 큐에서 메시지를 검색할 수 있습니다. 이 기능은 창을 지정하지 않는 메시지를 게시하는 애플리케이션에 유용합니다. 또한 GetMessage특정 메시지를 검색하도록 지시하여 다른 메시지를 큐에 남길 수도 있습니다. 이는 메시지 큐의 일반적인 FIFO 순서를 일시적으로 무시해야 하는 경우에 유용합니다.
가속기 키를 사용하는 애플리케이션은 키보드 메시지를 명령 메시지로 변환할 수 있어야 합니다. 이렇게 하려면 애플리케이션의 메시지 루프에 TranslateAccelerator 함수에 대한 호출이 포함되어야 합니다. 가속기 키에 대한 자세한 내용은 키보드 가속기참조하세요.
스레드에서 모덜리스 대화 상자를 사용하는 경우 대화 상자가 키보드 입력을 받을 수 있도록 메시지 루프에 IsDialogMessage 함수가 포함되어야 합니다.
창 프로시저
창 프로시저는 창에 전송된 모든 메시지를 수신하고 처리하는 함수입니다. 모든 창 클래스에는 창 프로시저가 있으며, 해당 클래스로 만든 모든 창은 동일한 창 프로시저를 사용하여 메시지에 응답합니다.
시스템은 메시지 데이터를 프로시저에 인수로 전달하여 창 프로시저에 메시지를 보냅니다. 창 프로시저는 메시지에 대해 적절한 작업을 수행합니다. 메시지 식별자를 확인하고 메시지를 처리하는 동안 메시지 매개 변수에 지정된 정보를 사용합니다.
창 프로시저는 일반적으로 메시지를 무시하지 않습니다. 메시지를 처리하지 않는 경우 기본 처리를 위해 메시지를 시스템으로 다시 보내야 합니다. 창 프로시저는 기본 작업을 수행하고 메시지 결과를 반환하는 DefWindowProc 함수를 호출하여 이 작업을 수행합니다. 창 프로시저는 이 값을 자체 메시지 결과로 반환해야 합니다. 대부분의 창 프로시저는 몇 개의 메시지만 처리하고 DefWindowProc호출하여 다른 메시지를 시스템에 전달합니다.
창 프로시저는 동일한 클래스에 속하는 모든 창에서 공유되므로 여러 창에 대한 메시지를 처리할 수 있습니다. 메시지의 영향을 받는 특정 창을 식별하기 위해 창 프로시저는 메시지와 함께 전달된 창 핸들을 검사할 수 있습니다. 창 프로시저에 대한 자세한 내용은 창 프로시저참조하세요.
메시지 필터링
애플리케이션은 GetMessage 사용하거나 PeekMessage함수를메시지 필터를 지정하여 메시지 큐에서 검색할 특정 메시지를 선택할 수 있습니다(다른 메시지를 무시). 필터는 메시지 식별자 범위(첫 번째 및 마지막 식별자), 창 핸들 또는 둘 다로 지정됩니다. GetMessage 및 PeekMessage 메시지 필터를 사용하여 큐에서 검색할 메시지를 선택합니다. 메시지 필터링은 애플리케이션이 나중에 큐에 도착한 메시지를 메시지 큐에서 검색해야 하는 경우에 유용합니다. 또한 애플리케이션이 게시된 메시지를 처리하기 전에 입력(하드웨어) 메시지를 처리해야 하는 경우에도 유용합니다.
WM_KEYFIRST 및 WM_KEYLAST 상수는 필터 값으로 사용하여 모든 키보드 메시지를 검색할 수 있습니다. WM_MOUSEFIRST 및 WM_MOUSELAST 상수는 모든 마우스 메시지를 검색하는 데 사용할 수 있습니다.
메시지를 필터링하는 모든 애플리케이션은 메시지 필터를 충족하는 메시지를 게시할 수 있는지 확인해야 합니다. 예를 들어 애플리케이션이 키보드 입력을 받지 않는 창에서 WM_CHAR 메시지를 필터링하는 경우 GetMessage 함수는 반환되지 않습니다. 이렇게 하면 애플리케이션이 효과적으로 "중단"됩니다.
메시지 게시 및 보내기
모든 애플리케이션은 메시지를 게시하고 보낼 수 있습니다. 시스템과 마찬가지로 애플리케이션은 메시지를 메시지 큐에 복사하여 게시하고 메시지 데이터를 창 프로시저에 인수로 전달하여 메시지를 보냅니다. 메시지를 게시하기 위해 애플리케이션은 PostMessage 함수를 사용합니다. 애플리케이션은 SendMessage, BroadcastSystemMessage, SendMessageCallback, SendMessageTimeout, SendNotifyMessage또는 SendDlgItemMessage 함수를 호출하여 메시지를 보낼 수 있습니다.
메시지 게시
애플리케이션은 일반적으로 특정 창에 작업을 수행하도록 알리는 메시지를 게시합니다. PostMessage 메시지에 대한 MSG 구조를 만들고 메시지를 메시지 큐에 복사합니다. 애플리케이션의 메시지 루프는 결국 메시지를 검색하고 적절한 창 프로시저로 디스패치합니다.
애플리케이션은 창을 지정하지 않고 메시지를 게시할 수 있습니다. PostMessage호출할 때 애플리케이션이 NULL 창 핸들을 제공하는 경우 메시지는 현재 스레드와 연결된 큐에 게시됩니다. 창 핸들이 지정되지 않으므로 애플리케이션은 메시지 루프에서 메시지를 처리해야 합니다. 이는 특정 창 대신 전체 애플리케이션에 적용되는 메시지를 만드는 한 가지 방법입니다.
경우에 따라 시스템의 모든 최상위 창에 메시지를 게시할 수 있습니다. 애플리케이션은 PostMessage 호출하고 hwnd 매개 변수에 HWND_TOPMOST 지정하여 모든 최상위 창에 메시지를 게시할 수 있습니다.
일반적인 프로그래밍 오류는 PostMessage 함수가 항상 메시지를 게시한다고 가정하는 것입니다. 메시지 큐가 가득 찼을 때는 그렇지 않습니다. 애플리케이션은 PostMessage 함수의 반환 값을 확인하여 메시지가 게시되었는지 여부를 확인하고, 그렇지 않은 경우 다시 게시해야 합니다.
메시지 보내기
애플리케이션은 일반적으로 즉시 작업을 수행하기 위해 창 프로시저에 알리는 메시지를 보냅니다. SendMessage 함수는 지정된 창에 해당하는 창 프로시저로 메시지를 보냅니다. 함수는 창 프로시저가 처리를 완료할 때까지 기다린 다음 메시지 결과를 반환합니다. 부모 창과 자식 창은 종종 서로 메시지를 전송하여 통신합니다. 예를 들어, 편집 컨트롤을 자식 창으로 하는 부모 창은 메시지를 보내어 컨트롤의 텍스트를 설정할 수 있습니다. 컨트롤은 부모 창에 메시지를 다시 부모로 전송하여 사용자가 수행하는 텍스트에 대한 변경 내용을 알릴 수 있습니다.
SendMessageCallback 함수는 지정된 창에 해당하는 창 프로시저에 메시지를 보냅니다. 그러나 이 함수는 즉시 반환됩니다. 창 프로시저가 메시지를 처리한 후 시스템은 지정된 콜백 함수를 호출합니다. 콜백 함수에 대한 자세한 내용은 SendAsyncProc 함수를 참조하세요.
경우에 따라 시스템의 모든 최상위 창에 메시지를 보낼 수 있습니다. 예를 들어 애플리케이션이 시스템 시간을 변경하는 경우 WM_TIMECHANGE 메시지를 전송하여 모든 최상위 창에 변경 내용을 알려야 합니다. 애플리케이션은 SendMessage 호출하고 hwnd 매개 변수에 HWND_TOPMOST 지정하여 모든 최상위 창에 메시지를 보낼 수 있습니다. BroadcastSystemMessage 함수를 호출하고 lpdwRecipients 매개 변수에 BSM_APPLICATIONS 지정하여 모든 애플리케이션에 메시지를 브로드캐스트할 수도 있습니다.
InSendMessage 또는 InSendMessageEx 함수를 사용하면 창 프로시저가 다른 스레드에서 보낸 메시지를 처리하고 있는지 여부를 확인할 수 있습니다. 이 기능은 메시지 처리가 메시지의 원본에 따라 달라지는 경우에 유용합니다.
메시지 교착 상태
메시지를 다른 스레드로 보내기 위해 SendMessage 함수를 호출하는 스레드는 메시지를 받는 창 프로시저가 반환될 때까지 계속 실행할 수 없습니다. 메시지를 처리하는 동안 수신 스레드가 제어를 생성하는 경우 송신 스레드는 SendMessage 반환되기를 기다리고 있으므로 계속 실행할 수 없습니다. 수신 스레드가 발신자와 동일한 큐에 연결된 경우 애플리케이션 교착 상태가 발생할 수 있습니다. (저널 후크는 스레드를 동일한 큐에 연결합니다.)
수신 스레드는 명시적으로 제어를 생성할 필요가 없습니다. 다음 함수를 호출하면 스레드가 암시적으로 제어를 생성할 수 있습니다.
- 대화 상자
- DialogBoxIndirect
- DialogBoxIndirectParam
- DialogBoxParam
- GetMessage
- MessageBox
- PeekMessage
- SendMessage
애플리케이션에서 잠재적인 교착 상태를 방지하기 위해 SendNotifyMessage 또는 SendMessageTimeout 함수를 사용하는 것을 고려하십시오. 그렇지 않으면 창 프로시저는 InSendMessage 호출하여 받은 메시지가 다른 스레드에서 전송되었는지 또는 InSendMessageEx함수를확인할 수 있습니다. 메시지를 처리하는 동안 이전 목록의 함수를 호출하기 전에 창 프로시저는 먼저 InSendMessage 호출하거나 InSendMessageEx 합니다. 이 함수가 TRUE반환하는 경우 창 프로시저는 스레드가 제어를 생성하는 함수 앞에 ReplyMessage 함수를 호출해야 합니다.
브로드캐스트 메시지
각 메시지는 메시지 식별자와 wParam 및 lParam 두 개의 매개 변수로 구성됩니다. 메시지 식별자는 메시지 용도를 지정하는 고유한 값입니다. 매개 변수는 메시지별 추가 정보를 제공하지만 wParam 매개 변수는 일반적으로 메시지에 대한 자세한 정보를 제공하는 형식 값입니다.
메시지 브로드캐스트는 단순히 시스템의 여러 받는 사람에게 메시지를 보내는 것을 의미합니다. 애플리케이션에서 메시지를 브로드캐스트하려면 BroadcastSystemMessage 함수를 사용하여 메시지 수신자를 지정합니다. 개별 받는 사람을 지정하는 대신 하나 이상의 받는 사람 유형을 지정해야 합니다. 이러한 유형은 애플리케이션, 설치 가능한 드라이버, 네트워크 드라이버 및 시스템 수준 디바이스 드라이버입니다. 시스템은 지정된 각 형식의 모든 멤버에게 브로드캐스트 메시지를 보냅니다.
시스템은 일반적으로 시스템 수준 디바이스 드라이버 또는 관련 구성 요소 내에서 발생하는 변경 내용에 대한 응답으로 메시지를 브로드캐스트합니다. 드라이버 또는 관련 구성 요소는 애플리케이션 및 기타 구성 요소에 메시지를 브로드캐스트하여 변경 사항을 알립니다. 예를 들어 디스크 드라이브를 담당하는 구성 요소는 플로피 디스크 드라이브의 디바이스 드라이버가 사용자가 드라이브에 디스크를 삽입하는 경우와 같은 미디어 변경을 감지할 때마다 메시지를 브로드캐스트합니다.
시스템은 시스템 수준 디바이스 드라이버, 네트워크 드라이버, 설치 가능한 드라이버 및 애플리케이션 순서대로 받는 사람에게 메시지를 브로드캐스트합니다. 즉, 시스템 수준 디바이스 드라이버(받는 사람으로 선택되는 경우)는 항상 메시지에 응답할 수 있는 첫 번째 기회를 얻습니다. 지정된 받는 사람 유형 내에서 다른 드라이버 앞에 지정된 메시지를 받는 드라이버는 보장되지 않습니다. 즉, 특정 드라이버용 메시지에는 전역적으로 고유한 메시지 식별자가 있어야 다른 드라이버가 의도치 않게 처리하지 않습니다.
SendMessage, SendMessageCallback,SendMessageTimeout또는 SendNotifyMessage함수에HWND_BROADCAST 지정하여 모든 최상위 창에 메시지를 브로드캐스트할 수도 있습니다.
애플리케이션은 최상위 창의 창 프로시저를 통해 메시지를 받습니다. 메시지는 자식 창으로 전송되지 않습니다. 서비스는 창 프로시저 또는 해당 서비스 제어 처리기를 통해 메시지를 받을 수 있습니다.
메모
시스템 수준 디바이스 드라이버는 관련 시스템 수준 함수를 사용하여 시스템 메시지를 브로드캐스트합니다.
쿼리 메시지
사용자 고유의 사용자 지정 메시지를 만들고 이를 사용하여 애플리케이션과 시스템의 다른 구성 요소 간에 작업을 조정할 수 있습니다. 이는 설치 가능한 드라이버 또는 시스템 수준 디바이스 드라이버를 직접 만든 경우에 특히 유용합니다. 사용자 지정 메시지는 드라이버와 해당 드라이버를 사용하는 애플리케이션 간에 정보를 전달할 수 있습니다.
지정된 작업을 수행할 수 있는 권한을 받는 사람을 폴링하려면 쿼리 메시지사용합니다. BroadcastSystemMessage호출할 때 dwFlags 매개 변수에서 BSF_QUERY 값을 설정하여 고유한 쿼리 메시지를 생성할 수 있습니다. 쿼리 메시지의 각 수신자는 함수가 메시지를 다음 받는 사람에게 보내려면 TRUE 반환해야 합니다. 받는 사람이 BROADCAST_QUERY_DENY반환하면 브로드캐스트가 즉시 종료되고 함수는 0을 반환합니다.