Как определить, что SendMessage () был успешным (сообщение было доставлено)? - PullRequest
0 голосов
/ 22 апреля 2019

можно ли определить, был ли вызов SendMessage () успешным и доставил ли мое сообщение целевому окну?

Описание SendMessage () в Windows API кажется тихим и говорит только следующее:

Возвращаемое значение указывает результат обработки сообщения;это зависит от отправленного сообщения.

Это, очевидно, относится к тому факту, что код возврата отражает значение, возвращаемое wndproc целевого окна.

Но каким будет код возврата, если сообщение не было доставлено вообще (например, из-за контроля доступа или из-за того, что окно было удалено за это время)?Как я могу обнаружить такие ситуации?

Ответы [ 2 ]

2 голосов
/ 02 мая 2019

Нет способа достоверно определить, был ли вызов на SendMessage успешным или неудачным. В конце концов, он имеет только одно возвращаемое значение, и используется весь диапазон значений. Нет обозначенного значения ошибки.

Воспроизведение трюков с последним кодом ошибки вызывающего потока также не будет работать. Схема, предложенная в этом ответе (очистка последнего кода ошибки до вызова и оценка его после вызова), является хрупкой. Легко видеть, что это может привести к сбою при отправке сообщения в окно, принадлежащее вызывающему потоку (поскольку оконная процедура этого окна может изменять последнюю ошибку любым способом, который сочтет нужным).

Не так хорошо известно, что это также может произойти сбой при отправке сообщения в окно, принадлежащее другому потоку. Код предполагает, что в вызывающем потоке не может произойти промежуточный вызов API. Однако в этом сценарии SendMessage также будет отправлять входящие сообщения между потоками (см. Когда поток может получать оконные сообщения? ), позволяя изменить последний код ошибки потока.

Единственный вариант - использовать SendMessageTimeoutW, поскольку этот API сообщает как о результате вызова, так и об ошибке / индикаторе успеха. Передача флага SMTO_NOTIMEOUTIFNOTHUNG гарантирует, что произвольно выбранный тайм-аут не повлияет отрицательно на результат.

0 голосов
/ 22 апреля 2019

если SendMessage не удалось, он установил последний код ошибки win32, который мы можем получить по вызову GetLastError(). и возвращенный код ошибки, в случае сбоя, никогда не будет 0 (NOERROR), несмотря на то, что это ясно, не задокументировано. но как обнаружить, что SendMessage не удалось? здесь мы не можем основываться на возвращаемом значении. но мы можем SetLastError(NOERROR) до вызова SendMessage и проверить GetLastError() после:

  • если SendMessage fail - значение, возвращаемое GetLastError(), будет не 0. (чаще всего в этом случае ERROR_INVALID_WINDOW_HANDLE или ERROR_ACCESS_DENIED). * * Тысяча двадцать-одна
  • если мы все еще получили 0 как последнюю ошибку - это означает, что сообщение было доставлено без ошибок.
  • однако возможен случай, когда во время вызова SendMessage какая-то оконная процедура в текущем потоке будет называться и код внутри оконной процедуры, установите для последней ошибки значение, отличное от 0. поэтому мы получить, наконец, не 0 последнюю ошибку, но не потому, что SendMessage ошибка. различить эти два случая очень проблематично

-

    SetLastError(NOERROR);
    LRESULT lr = SendMessageW(hwnd, *, *, *);
    ULONG dwErrorCode = GetLastError();
    if (dwErrorCode == NOERROR)
    {
        DbgPrint("message was delivered (%p)\n", lr);
    }
    else
    {
        DbgPrint("fail with %u error\n", dwErrorCode);
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...