0

ATL を使用してソフトウェアをビルドしています。複数の子ウィンドウを含むメイン フレーム ウィンドウを作成します。子ウィンドウの 1 つには、いくつかの沈殿ウィンドウも含まれています。

これで、私のアプリは常にアサートの失敗を取得します:

    virtual ~CWindowImplRoot()
    {
#ifdef _DEBUG
        if(m_hWnd != NULL)  // should be cleared in WindowProc
        {
            ATLTRACE(atlTraceWindowing, 0, _T("ERROR - Object deleted before window was destroyed\n"));
            ATLASSERT(FALSE);
        }
#endif //_DEBUG
    }

任意のウィンドウに対して WM_NCDESTROY ハンドラーを定義し、bHanded=FALSE を設定すると、コードはそこに到着します。

もう、OnFinalMessage オーバーライド関数を追加します。残念ながら、すべての関数を呼び出すことはできません。実際には、最上位ウィンドウの OnFinalMessage が呼び出されますが、中間レベル ウィンドウの OnFinalMessage は呼び出されず、最下位ウィンドウの OnFinalMessage は呼び出されません。

ATL のソース コードを確認します。

template <class TBase, class TWinTraits>
LRESULT CALLBACK CWindowImplBaseT< TBase, TWinTraits >::WindowProc(
    _In_ HWND hWnd,
    _In_ UINT uMsg,
    _In_ WPARAM wParam,
    _In_ LPARAM lParam)
{
    CWindowImplBaseT< TBase, TWinTraits >* pThis = (CWindowImplBaseT< TBase, TWinTraits >*)hWnd;
    // set a ptr to this message and save the old value
    _ATL_MSG msg(pThis->m_hWnd, uMsg, wParam, lParam);
    const _ATL_MSG* pOldMsg = pThis->m_pCurrentMsg;
    pThis->m_pCurrentMsg = &msg;
    // pass to the message map to process
    LRESULT lRes = 0;
    BOOL bRet = pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam, lRes, 0);
    // restore saved value for the current message
    ATLASSERT(pThis->m_pCurrentMsg == &msg);

    // do the default processing if message was not handled
    if(!bRet)
    {
        if(uMsg != WM_NCDESTROY)
            lRes = pThis->DefWindowProc(uMsg, wParam, lParam);
        else
        {
            // unsubclass, if needed
            LONG_PTR pfnWndProc = ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC);
            lRes = pThis->DefWindowProc(uMsg, wParam, lParam);
            if(pThis->m_pfnSuperWindowProc != ::DefWindowProc && ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC) == pfnWndProc)
                ::SetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC, (LONG_PTR)pThis->m_pfnSuperWindowProc);
            // mark window as destryed
            pThis->m_dwState |= WINSTATE_DESTROYED;
        }
    }
    if((pThis->m_dwState & WINSTATE_DESTROYED) && pOldMsg== NULL)
    {
        // clear out window handle
        HWND hWndThis = pThis->m_hWnd;
        pThis->m_hWnd = NULL;
        pThis->m_dwState &= ~WINSTATE_DESTROYED;
        // clean up after window is destroyed
        pThis->m_pCurrentMsg = pOldMsg;
        pThis->OnFinalMessage(hWndThis);
    }else {
        pThis->m_pCurrentMsg = pOldMsg;
    }
    return lRes;
}

上記のコードで、変数「pOldMsg」の目的は、コール スタック レベルを示すことです。"pOldMsg" が NULL に等しくない場合、コール スタックが返されないことを意味します。NULL の場合は、コール スタックが最も外側のレベルであることを意味します。この瞬間、OnFinalMessage 関数を呼び出すことができます。

私の場合、「pOldMsg」が NULL に等しくならない場合があるようです。

チャット:

   MainFrame                         V
     |----- ViewDevices              V
     |----- ViewContainer            X
              |----- ViewBooks       X
              |----- ViewFiles       V

何度もテストした結果、ViewBooks(ListView) ウィンドウにコンテンツを追加しなければ、すべて問題ないことがわかりました。1行だけ追加すると、この問題が再現されます。クロススレッドによるメッセージの送信が問題を引き起こしているかどうかはわかりません。

誰か私にいくつかの提案をしてもらえますか?

4

0 に答える 0