TN061: ON_NOTIFY 및 WM_NOTIFY 메시지

참고 항목

다음 기술 노트는 온라인 설명서에 먼저 포함되어 있었으므로 업데이트되지 않았습니다. 따라서 일부 절차 및 항목은 만료되거나 올바르지 않을 수 있습니다. 최신 정보를 보려면 온라인 설명서 색인에서 관심 있는 항목을 검색하는 것이 좋습니다.

이 기술 참고 사항은 새 WM_NOTIFY 메시지에 대한 배경 정보를 제공하고 MFC 애플리케이션에서 WM_NOTIFY 메시지를 처리하는 권장되는(그리고 가장 일반적인) 방법을 설명합니다.

Windows 3.x의 알림 메시지

Windows 3.x에서 컨트롤은 부모에게 마우스 클릭, 콘텐츠 및 선택 내용 변경, 부모에게 메시지를 전송하여 배경 그리기 제어와 같은 이벤트를 알립니다. 간단한 알림은 알림 코드(예: BN_CLICKED) 및 컨트롤 ID가 wParam으로 압축되고 lParam의 컨트롤 핸들이 포함된 특수 WM_COMMAND 메시지로 전송됩니다. wParamlParam이 가득 찼기 때문에 추가 데이터를 전달할 방법이 없습니다. 이러한 메시지는 간단한 알림일 수 있습니다. 예를 들어 BN_CLICKED 알림에서는 단추를 클릭할 때 마우스 커서의 위치에 대한 정보를 보낼 수 없습니다.

Windows 3.x의 컨트롤이 추가 데이터를 포함하는 알림 메시지를 보내야 하는 경우 WM_CTLCOLOR, WM_VSCROLL, WM_HSCROLL, WM_DRAWITEM, WM_MEASUREITEM, WM_COMPAREITEM, WM_DELETEITEM, WM_CHARTOITEM, WM_VKEYTOITEM 등 다양한 특수 목적 메시지를 사용합니다. 이러한 메시지는 메시지를 보낸 컨트롤에 다시 반영될 수 있습니다. 자세한 내용은 TN062: Windows 컨트롤에 대한 메시지 리플렉션을 참조하세요.

Win32의 알림 메시지

Windows 3.1에 있는 컨트롤의 경우 Win32 API는 Windows 3.x에서 사용된 대부분의 알림 메시지를 사용합니다. 그러나 Win32는 Windows 3.x에서 지원되는 복잡한 여러 컨트롤도 추가합니다. 이러한 컨트롤은 알림 메시지와 함께 추가 데이터를 보내야 하는 경우가 많습니다. Win32 API의 디자이너는 추가 데이터가 필요한 각 새 알림에 대해 새 WM_* 메시지를 추가하는 대신 표준화된 방식으로 모든 양의 추가 데이터를 전달할 수 있는 메시지 WM_NOTIFY 하나만 추가하도록 선택했습니다.

WM_NOTIFY 메시지에는 wParam에서 메시지를 보내는 컨트롤의 ID와 lParam의 구조체에 대한 포인터가 포함됩니다. 이 구조체는 NMHDR 구조체이거나 NMHDR 구조체를 첫 번째 멤버로 사용하는 더 큰 구조체입니다. NMHDR 멤버가 처음이므로 이 구조체에 대한 포인터를 NMHDR대한 포인터로 사용하거나 캐스팅 방법에 따라 더 큰 구조체에 대한 포인터로 사용할 수 있습니다.

대부분의 경우 포인터는 더 큰 구조를 가리키며 사용할 때 캐스팅해야 합니다. 일반 알림(이름이 NM_ 시작) 및 도구 설명 컨트롤의 TTN_SHOW 및 TTN_POP 알림과 같은 몇 가지 알림에서 실제로 사용되는 NMHDR 구조입니다.

NMHDR 구조체 또는 초기 멤버에는 메시지를 보내는 컨트롤의 핸들과 ID와 알림 코드(예: TTN_SHOW)가 포함됩니다. NMHDR 구조체의 형식은 다음과 같습니다.

typedef struct tagNMHDR {
    HWND hwndFrom;
    UINT idFrom;
    UINT code;
} NMHDR;

TTN_SHOW 메시지의 경우 코드 멤버가 TTN_SHOW 설정됩니다.

대부분의 알림은 NMHDR 구조체를 첫 번째 멤버로 포함하는 더 큰 구조체에 대한 포인터를 전달합니다. 예를 들어 목록 보기 컨트롤의 LVN_KEYDOWN 알림 메시지에서 사용되는 구조를 고려합니다. 이 메시지는 목록 보기 컨트롤에서 키를 누를 때 전송됩니다. 포인터는 아래와 같이 정의된 LV_KEYDOWN 구조를 가리킵니다.

typedef struct tagLV_KEYDOWN {
    NMHDR hdr;
    WORD wVKey;
    UINT flags;
} LV_KEYDOWN;

NMHDR 멤버가 이 구조에서 첫 번째이므로 알림 메시지에 전달된 포인터를 NMHDR에 대한 포인터 또는 LV_KEYDOWN 대한 포인터로 캐스팅할 수 있습니다.

모든 새 Windows 컨트롤에 공통된 알림

일부 알림은 모든 새 Windows 컨트롤에 공통적으로 적용됩니다. 이러한 알림은 NMHDR 구조에 대한 포인터를 전달합니다.

알림 코드 보낸 사람
NM_CLICK 사용자가 컨트롤에서 마우스 왼쪽 단추를 클릭했습니다.
NM_DBLCLK 컨트롤에서 마우스 왼쪽 단추를 두 번 클릭
NM_RCLICK 사용자가 컨트롤에서 마우스 오른쪽 단추 클릭
NM_RDBLCLK 컨트롤에서 마우스 오른쪽 단추를 두 번 클릭
NM_RETURN 컨트롤에 입력 포커스가 있는 동안 사용자가 ENTER 키를 눌렀습니다.
NM_SETFOCUS 컨트롤에 입력 포커스가 지정되었습니다.
NM_KILLFOCUS 컨트롤이 입력 포커스를 잃었습니다.
NM_OUTOFMEMORY 사용 가능한 메모리가 부족하여 컨트롤이 작업을 완료할 수 없습니다.

ON_NOTIFY: MFC 애플리케이션에서 WM_NOTIFY 메시지 처리

이 함수 CWnd::OnNotify 는 알림 메시지를 처리합니다. 기본 구현은 알림 처리기가 호출할 메시지 맵을 검사. 일반적으로 재정의하지 OnNotify않습니다. 대신 처리기 함수를 제공하고 해당 처리기의 메시지 맵 항목을 소유자 창 클래스의 메시지 맵에 추가합니다.

ClassWizard 속성 시트를 통해 ClassWizard는 ON_NOTIFY 메시지 맵 항목을 만들고 기본 처리기 함수를 제공할 수 있습니다. ClassWizard를 사용하여 이 작업을 더 쉽게 만드는 방법에 대한 자세한 내용은 함수에 메시지 매핑을 참조 하세요.

ON_NOTIFY 메시지 맵 매크로에는 다음 구문이 있습니다.

ON_NOTIFY(wNotifyCode, id, memberFxn)

여기서 매개 변수는 다음과 같습니다.

wNotifyCode
처리할 알림 메시지의 코드(예: LVN_KEYDOWN)입니다.

id
알림을 보낼 컨트롤의 자식 식별자입니다.

memberFxn
이 알림을 보낼 때 호출할 멤버 함수입니다.

멤버 함수는 다음 프로토타입을 사용하여 선언해야 합니다.

afx_msg void memberFxn(NMHDR* pNotifyStruct, LRESULT* result);

여기서 매개 변수는 다음과 같습니다.

pNotifyStruct
위의 섹션에 설명된 대로 알림 구조에 대한 포인터입니다.

result
반환하기 전에 설정할 결과 코드에 대한 포인터입니다.

예시

멤버 함수 OnKeydownList1 가 IDIDC_LIST1의 LVN_KEYDOWN 메시지를 CListCtrl 처리하도록 지정하려면 ClassWizard를 사용하여 메시지 맵에 다음을 추가합니다.

ON_NOTIFY(LVN_KEYDOWN, IDC_LIST1, OnKeydownList1)

위의 예제에서 ClassWizard에서 제공하는 함수는 다음과 같습니다.

void CMessageReflectionDlg::OnKeydownList1(NMHDR* pNMHDR, LRESULT* pResult)
{
    LV_KEYDOWN* pLVKeyDow = (LV_KEYDOWN*)pNMHDR;

    // TODO: Add your control notification handler
    //       code here

    *pResult = 0;
}

ClassWizard는 적절한 형식의 포인터를 자동으로 제공합니다. pNMHDR 또는 pLVKeyDow통해 알림 구조에 액세스할 수 있습니다.

ON_NOTIFY_RANGE

컨트롤 집합에 대해 동일한 WM_NOTIFY 메시지를 처리해야 하는 경우 ON_NOTIFY 대신 ON_NOTIFY_RANGE 사용할 수 있습니다. 예를 들어 특정 알림 메시지에 대해 동일한 작업을 수행하려는 단추 집합이 있을 수 있습니다.

ON_NOTIFY_RANGE 사용하는 경우 범위의 시작 및 끝 자식 식별자를 지정하여 알림 메시지를 처리할 인접한 자식 식별자 범위를 지정합니다.

ClassWizard는 ON_NOTIFY_RANGE 처리하지 않습니다. 이를 사용하려면 메시지 맵을 직접 편집해야 합니다.

ON_NOTIFY_RANGE 대한 메시지 맵 항목 및 함수 프로토타입은 다음과 같습니다.

ON_NOTIFY_RANGE(wNotifyCode, id, idLast, memberFxn)

여기서 매개 변수는 다음과 같습니다.

wNotifyCode
처리할 알림 메시지의 코드(예: LVN_KEYDOWN)입니다.

id
연속된 식별자 범위의 첫 번째 식별자입니다.

idLast
연속된 식별자 범위의 마지막 식별자입니다.

memberFxn
이 알림을 보낼 때 호출할 멤버 함수입니다.

멤버 함수는 다음 프로토타입을 사용하여 선언해야 합니다.

afx_msg void memberFxn(UINT id, NMHDR* pNotifyStruct, LRESULT* result);

여기서 매개 변수는 다음과 같습니다.

id
알림을 보낸 컨트롤의 자식 식별자입니다.

pNotifyStruct
위에서 설명한 대로 알림 구조에 대한 포인터입니다.

result
반환하기 전에 설정할 결과 코드에 대한 포인터입니다.

ON_NOTIFY_EX, ON_NOTIFY_EX_RANGE

알림 라우팅에서 둘 이상의 개체가 메시지를 처리하도록 하려면 ON_NOTIFY(또는 ON_NOTIFY_RANGE) 대신 ON_NOTIFY_EX(또는 ON_NOTIFY_EX_RANGE)를 사용할 수 있습니다. EX 버전과 일반 버전 간의 유일한 차이점은 EX 버전에 대해 호출된 멤버 함수가 메시지 처리를 계속할지 여부를 나타내는 BOOL을 반환한다는 것입니다. 이 함수에서 FALSE반환하면 둘 이상의 개체에서 동일한 메시지를 처리할 수 있습니다.

ClassWizard는 ON_NOTIFY_EX 또는 ON_NOTIFY_EX_RANGE 처리하지 않습니다. 둘 중 하나를 사용하려면 메시지 맵을 직접 편집해야 합니다.

ON_NOTIFY_EX 및 ON_NOTIFY_EX_RANGE 대한 메시지 맵 항목 및 함수 프로토타입은 다음과 같습니다. 매개 변수의 의미는 EX가 아닌 버전과 동일합니다.

ON_NOTIFY_EX(nCode, id, memberFxn)
ON_NOTIFY_EX_RANGE(wNotifyCode, id, idLast, memberFxn)

위의 두 프로토타입은 동일합니다.

afx_msg BOOL memberFxn(UINT id, NMHDR* pNotifyStruct, LRESULT* result);

두 경우 모두 ID알림을 보낸 컨트롤의 자식 식별자를 보유합니다.

알림 메시지가 완전히 처리된 경우 함수가 TRUE를 반환하거나 명령 라우팅의 다른 개체가 메시지를 처리할 기회가 있는 경우 FALSE를 반환해야 합니다.

참고 항목

번호별 기술 참고 사항
범주별 기술 참고 사항