GetMessage는 WinEvent 콜백을 실행하는 동안 받은 게시된 메시지를 무시합니다.

  • 아티클
  • 2023. 07. 17.
  •  

이 문서의 내용

  1. 증상
  2. 원인
  3. 해결 방법
  4. 추가 정보

이 문서는 콜백 함수가 GetMessage 실행되는 동안 WinEvent API가 게시된 메시지를 받지 못하는 문제를 해결하는 데 도움이 됩니다.

원래 제품 버전: Windows Server 2008, Windows 7, Windows Server 2003 R2, Windows Vista
원래 KB 번호: 2682659

증상

GetMessage 는 콜백 함수가 실행되는 동안 WinEvent 게시된 메시지를 수신하지 않는 것으로 나타납니다. 다른 메시지가 큐에 들어가면 두 메시지가 모두 수신되고 처리됩니다.

원인

알려진 문제 GetMessage 및 자체에서 Windows 메시지를 사용하는 콜백의 사용 WinEvent 이 있습니다. GetMessage 는 콜백을 실행하는 동안 수신되는 메시지를 무시합니다. 따라서 특히 콜백 함수가 호출 PostThreadMessage하는 경우 다른 메시지가 큐에 들어갈 때까지(예: 마우스 이동으로 인해) 해당 메시지가 등록되지 않습니다. 이 시점에서는 이전에 게시된 메시지와 새 메시지가 모두 등록되고 처리됩니다.

해결 방법

이 블록을 해결하려면 대신 사용하는 MsgWaitForMultipleObjectsPeekMessageGetMessage것이 좋습니다. 또한 WinEvent 처리기에서 보낼 수 있는 새 이벤트를 만들어 메시지 루프를 해제해야 합니다.

추가 정보

다음은 제네릭 메시지 루프 및 처리기를 포함하는 코드 조각입니다.WinEvent

C++
// Main message loop of thread that called SetWinEventHook while(GetMessage(&msg, NULL, 0, 0))
{
    ... process message here ...
}

void CALLBACK WinEventProc(HWINEVENTHOOK hWinEventHook, DWORD eventId,
HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread,
DWORD dwmsEventTime)
{
    ... process winevent here ...
}

GetMessage 에서 보낸 메시지를 등록하지 못한 후 위의 조각에서 WinEventProc차단할 수 있습니다. 대신 이 조각과 PeekMessage 같이 처리기에서 메시지 루프로 다시 특별한 절전 모드 해제 이벤트를 선언하고 사용하는 것과 함께 사용합니다MsgWaitForMultipleObjects.

C++
HANDLE ghMessageReadyEvent = NULL; // Event used to wake up the main thread

ghMessageReadyEvent = CreateEvent(NULL, FALSE/*bManualReset*/,
FALSE/*bIntialState*/, NULL);

// Main message loop of thread that called SetWinEventHook
// We can't reliably use GetMessage here. If a posted message is received
// while we're in a reentrant call to WinEventProc, when the WinEventProc
// returns, GetMessage does not recognize that a message has been
// received and just blocks. To avoid this we use
// MsgWaitForMultipleObjects + PeekMessage. Code at the end of the
// WinEventProc checks if a posted message was received during the
// callback using PeekMessage; if so, it sets the event which causes
// MsgWaitForMultipleObjects to wake up.
// Note that MsgWaitForMultipleObjects usually only wakes up if a message
// is received during it. Even with QS_ALLPOSTMESSAGE, it only wakes up
// if a message is received between it and the most recent PeekMessage,
// so we have to call PeekMessage *before* calling it in case there are
// multiple queued-up messages.

for(;;)
{
    BOOL fGot = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);

    if(!fGot)
    {
        MsgWaitForMultipleObjects(1, &ghMessageReadyEvent,
        FALSE/*bWaitAll*/, INFINITE,
        QS_ALLEVENTS | QS_ALLPOSTMESSAGE);

        fGot = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
    }

    if(!fGot)
    {
        continue;
    }
    ... process message here ...
}

void CALLBACK WinEventProc(HWINEVENTHOOK hWinEventHook, DWORD eventId, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime)
{
    ... process winevent here ...
    // Before we return, check if posted messages were received during this
    // callback. If so, fire the event to ensure that we do process them.
    MSG msg;

    if(PeekMessage(&msg, (HWND)-1, WM_USER + 1, WM_USER + 2, PM_NOREMOVE | PM_QS_POSTMESSAGE))
    {
        SetEvent(ghMessageReadyEvent);
    }
}
Posted by gurupia
,