【问题标题】:How to send a string via PostMessage?如何通过 PostMessage 发送字符串?
【发布时间】:2010-11-22 10:54:45
【问题描述】:

在我的应用程序中,我想从不同的线程向对话框发送消息。 我想将 std::exception 派生类引用传递给对话框。

类似这样的:

try {
       //do stuff
}
catch (MyException& the_exception) {
    PostMessage(MyhWnd, CWM_SOME_ERROR, 0, 0); //send the_exception or the_exception.error_string() here
}

我想在我的对话框中接收消息并显示the_exception.error_string()中的错误

LPARAM CMyDlg::SomeError(WPARAM, LPARAM)
{
    show_error( ?????
    return 0;
}

我猜,使用 PostMessage 传递 std::string the_exception.error_string() 也可以。

【问题讨论】:

    标签: c++ multithreading mfc postmessage cdialog


    【解决方案1】:

    您不能在 PostMessage 中传递字符串的地址,因为该字符串可能在堆栈上是线程本地的。等到其他线程捡起它时,它可能已经被销毁了。

    相反,您应该通过 new 创建一个新的字符串或异常对象并将其地址传递给另一个线程(通过 PostMessage 中的 WPARAM 或 LPARAM 参数。)然后另一个线程拥有该对象并负责销毁它。

    下面是一些示例代码,展示了如何做到这一点:

    try
    {
        // do stuff
    }
    catch (const MyException& the_exception)
    {
        PostMessage(myhWnd, CWM_SOME_ERROR, 0, new std::string(the_exception.error_string));
    }
    
    
    LPARAM CMyDlg::SomeError(WPARAM, LPARAM lParam)
    {
        // Wrap in a unique_ptr so it is automatically destroyed.
        std::unique_ptr<std::string> msg = reinterpret_cast<std::string*>(lParam);
    
        // Do stuff with message
    
        return 0;
    }
    

    【讨论】:

    • 这里存在内存泄漏的潜在风险。例如,PostMessage 可能会因为消息队列已满而导致错误。或者,目标窗口可能已经被销毁(因此,delete 运算符将不会被调用)。您能否建议变体,我们如何才能安全地防止内存泄漏?
    【解决方案2】:

    只要您在一个进程中,只需传递一个 void* 指针并注意对象的生命周期就足够了。

    如果是 SendMessage,您可以将其作为 void* 强制转换在 LPARAM 中传递,然后客户端将其取消转换回您的字符串类型。因为 SendMessage 是synchronous,所以你是安全的:

    如果指定的窗口是由 调用线程,窗口 过程被立即调用为 子程序。如果指定的窗口 是由不同的线程创建的, 系统切换到该线程并 调用相应的窗口 程序。之间发送的消息 线程仅在 接收线程执行消息 检索代码。发送线程是 阻塞直到接收线程 处理消息

    如果您想使用 PostMessage,那么您必须进行显式切换,因为调用是异步的:在堆上复制字符串并通过调用 PostMessage,您已将删除责任传递给 calee (对话框)。

    如果您退出进程(MyhWnd 属于不同的进程),那么情况就完全不同了,您将不得不将您的消息编组为类似于全局原子的东西。

    【讨论】:

    • 好的,该回家了。我的回答好像 OP 在询问 SendMessage,而重点是 PostMessage...
    • 很高兴指出 SendMessage 是同步的,您不必担心所有权转移。但是,SendMessage 可以重入,即在调用 SendMessage 期间,您的线程可能正在发送消息,因此您必须小心在您的任何 wndprocs 中传递给另一个线程的状态不能被改变。
    • IMO 这是正确的答案:使用 SendMessage 并在收到消息后将消息复制到接收线程中。无需为简单的字符串传递(我认为字符串相当短)设置复杂的 PostMessage/同步问题。
    【解决方案3】:

    只要您知道您的窗口(或CMyDlg 的实例)在发布消息后仍然存在,您就可以简单地将错误字符串存储在成员变量中,然后在消息处理程序中从中读取。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-08-16
      • 1970-01-01
      • 2021-11-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多