您如何判断SendMessage()是否成功(消息已传递)?

时间:2019-04-21 23:48:36

标签: winapi

是否可以确定SendMessage()调用是否成功并将我的消息传递到目标窗口?

Windows API中的SendMessage()描述对此似乎很安静,并且仅显示以下内容:

  

返回值指定消息处理的结果;这取决于发送的消息。

这显然是指返回代码反映了目标窗口的wndproc返回的值的事实。

但是,如果消息根本没有传递(例如,由于访问控制,或者由于同时窗口被扭曲),返回码将是什么?我该如何发现这种情况?

2 个答案:

答案 0 :(得分:2)

无法可靠地判断对SendMessage的调用是成功还是失败。毕竟,它只有一个返回值,并且使用了整个值范围。没有指定的错误值。

使用调用线程的最后一个错误代码来玩弄花招也不起作用。 this answer中提出的方案(在调用之前清除最后的错误代码并在调用之后进行评估)很脆弱。很容易看到,当向调用线程拥有的窗口发送消息时,它可能会失败(因为该窗口的窗口过程可以自由选择以其认为合适的方式更改最后一个错误)。

众所周知,当将消息发送到另一个线程拥有的窗口时,这也会失败。该代码表明,在调用线程中不会发生中间的API调用。但是在这种情况下,SendMessage还将分派传入的跨线程消息(请参阅When can a thread receive window messages?),从而允许更改线程的最后错误代码。

然后唯一的选择是使用SendMessageTimeoutW,因为该API会报告调用结果以及错误/成功指示符。传递SMTO_NOTIMEOUTIFNOTHUNG标志可确保任意选择的超时不会对结果产生不利影响。

答案 1 :(得分:1)

如果SendMessage失败,则会设置最后一个win32错误代码,我们可以通过调用GetLastError()来获取该错误代码。并且返回的错误代码(如果失败的话)永远不会为0(NOERROR),尽管这显然没有记录。但是如何检测SendMessage是否失败?这里我们不能基于返回值。但是我们可以在致电SendMessage之前SetLastError(NOERROR),并在之后致电GetLastError()

  • 如果SendMessage失败-GetLastError()返回的值将是 不是0。(在这种情况下,最常见的是ERROR_INVALID_WINDOW_HANDLEERROR_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);
    }