0

我有一个窗口类,它在右键单击时创建一个弹出菜单。

MyWnd::OnRButtonDown(/* parameters*/)
{
    // do something
    VERIFY(m_RightClickMenu.CreatePopupMenu());
    MENUINFO MenuInfo;
    m_RightClickMenu.GetMenuInfo(&MenuInfo);
    MenuInfo.dwStyle = MNS_NOTIFYBYPOS;
    m_RightClickMenu.SetMenuInfo(&MenuInfo);
    HMENU hMenu = m_RightClickMenu.GetSafeHmenu();
    if (NULL != hMenu)
    {
        CString tempStr;
        // Add menu Items
        ClientToScreen(&ptMousePos);
        m_RightClickMenu.TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON | 
                         TPM_HORPOSANIMATION | TPM_VERPOSANIMATION ,
                         ptMousePos.x, ptMousePos.y, this);
        m_RightClickMenu.DestroyMenu();
    }
    CWnd::OnRButtonDown(nFlags, point);
}

问题是,当右键单击时,弹出菜单出现并且在用户单击任何菜单选项之前,需要关闭窗口,应用程序崩溃。

为了解决这个问题,我定义了一个函数 clear(),它发送消息以删除弹出菜单。

MyWnd::Clear()
{
    if (GetSafeHwnd())
    {
        SendMessage(WM_CANCELMODE);
    }
}

因此,首先调用 clear 然后销毁窗口。使用它,弹出菜单被删除,但应用程序仍然在 RButtonDown 函数中崩溃

m_RightClickMenu.DestroyMenu();

或者有时在

CWnd::OnRButtonDown(nFlags, point);

我认为,清除后,窗口在同一个线程中被破坏。但是 RButtonDown 中的调用被卡在单独的线程中。因此,当 RButtonDown 恢复执行时,MyWnd 类要么完全销毁,要么正在销毁。因此崩溃正在发生。

我正在考虑使用锁使其线程安全。但是如何知道我是否需要在 MyWnd 的析构函数中等待锁定尚不清楚。因为我不确定是否创建了弹出菜单。

请建议应该做什么。如何在调用 WM_CANCELMODE 或任何其他方式时停止执行 RButtonDown。

EIDT:我的 m_RightClickMenu 是 CMenu 类型

4

1 回答 1

2

问题接缝是,窗口对象已经被破坏了。所以访问这个指向 m_RightClickMenu 的指针会导致崩溃。

你为什么要破坏这个位置的菜单。我知道的所有菜单类都会在析构函数中自行销毁。所以从我的角度来看,这里没有必要调用 DestroyMenu。

也调用只是不调用基类 RButtonDown。为什么?您已经执行了不应导致进一步操作的操作。而且因为基类是 CWnd,所以甚至没有动作。更好的方法:先调用它,然后再调用它。

PS:你没有写 m_RightClickMenu 是什么类。

PS2:你知道MFC里面有一个特殊的CContextMenuManager吗?

于 2013-11-11T08:18:46.820 回答