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 への this ポインターにアクセスすると、クラッシュが発生します。

なぜこの場所でメニューを破棄するのですか。私が知っているすべてのメニュークラスは、デストラクタで自分自身を破壊します。したがって、私の観点からは、ここで DestroyMenu を呼び出す必要はありません。

また、基本クラス RButtonDown を呼び出さないでください。なんで?それ以上のアクションを引き起こすべきではないアクションを既に実行しました。また、基本クラスが CWnd であるため、アクションもありません。より良い方法:最初に電話して、通常のことをするよりも。

PS: m_RightClickMenu がどのようなクラスかを書いていません。

PS2: MFC 内に特別な CContextMenuManager があることをご存知ですか?

于 2013-11-11T08:18:46.820 に答える