c++ - 在线程之间发送窗口消息时出现 ESP 错误

标签 c++ multithreading mfc crash window-messages

我有一个观察者类和一个订阅者类。
出于测试目的,观察者创建了一个生成虚假消息并调用 CServerCommandObserver::NotifySubscribers() 的线程,如下所示:

void CServerCommandObserver::NotifySubscribers(const Command cmd, void const * const pData)
{
    // Executed in worker thread //

    for (Subscribers::const_iterator it = m_subscribers.begin(); it != m_subscribers.end(); ++it)
    {
        const CServerCommandSubscriber * pSubscriber = *it;

        const HWND hWnd = pSubscriber->GetWindowHandle();
        if (!IsWindow(hWnd)) { ASSERT(FALSE); continue; }

        SendMessage(hWnd, WM_SERVERCOMMAND, cmd, reinterpret_cast<LPARAM>(pData));
    }
}

订阅者是 CDialog 的派生类,它也继承自 CServerCommandSubscriber

在派生类中,我添加了一个消息映射条目,它将服务器命令路由到订阅者类处理程序。

// Derived dialog class .cpp
ON_REGISTERED_MESSAGE(CServerCommandObserver::WM_SERVERCOMMAND, HandleServerCommand)

// Subscriber base class .cpp
void CServerCommandSubscriber::HandleServerCommand(const WPARAM wParam, const LPARAM lParam)
{
    const Command cmd = static_cast<Command>(wParam);

    switch (cmd)
    {
    case something:
        OnSomething(SomethingData(lParam)); // Virtual method call
        break;
    case // ...
    };
}

问题是,我在 HandleServerCommand() 方法中看到奇怪的崩溃:

看起来像这样:

Debug Error!

Program: c:\myprogram.exe
Module:
File: i386\chkesp.c
Line: 42

The value of ESP was not properly saved across a function call. This is usually the result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.

我检查了 AfxBeginThread() 想要拥有的函数指针:

typedef UINT (AFX_CDECL *AFX_THREADPROC)(LPVOID); // AFXWIN.H

static UINT AFX_CDECL MessageGeneratorThread(LPVOID pParam); // My thread function

对我来说,这看起来兼容,不是吗?

我不知道,我还需要寻找什么。有什么想法吗?

我做了另一个奇怪的观察,这可能是相关的: 在 NotifySubscribers 方法中,我调用 IsWindow() 来检查句柄指向的窗口是否存在。显然是这样。但是调用 CWnd::FromHandlePermanent() 会返回 NULL 指针。

最佳答案

来自 afxmsg_.h:

// for Registered Windows messages
#define ON_REGISTERED_MESSAGE(nMessageVariable, memberFxn) \
    { 0xC000, 0, 0, 0, (UINT_PTR)(UINT*)(&nMessageVariable), \
        /*implied 'AfxSig_lwl'*/ \
        (AFX_PMSG)(AFX_PMSGW) \
        (static_cast< LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM) > \
        (memberFxn)) },

所以签名是 LRESULT ClassName::FunctionName(WPARAM, LPARAM),而你的是 void ClassName::FunctionName(const WPARAM, const LPARAM)。这不应该编译,至少在 VS2008 下它不会。

CServerCommandSubscriber 类(在头文件中)中的 HandleServerCommand 声明是什么?

关于c++ - 在线程之间发送窗口消息时出现 ESP 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3101771/

相关文章:

python:socket.sendall() 占用了 GIL?

c++ - 使用较新的 IDE 重新编译源代码的好处

c++ - 如何在 MFC 对话框中制作虚线分隔符?

c++ - 在 windows 上编译 MSVC 是绝对必要的吗?

c++ - 为什么不能在常量表达式中使用 reinterpret_cast?

java - Java 中的 Volatile 关键字

C# 4.0 - 间隔上的线程

c++ - 带有 std::vector 的模板 typedef 具有自定义分配器

c++访问 map 时发生访问冲突

c++ - 如何使用 GTest 测试严重依赖 MFC 的方法