为什么DestroyWindow()函数失败并且为什么我的ActiveX控件的PreTranslateMessage()函数没有被调用?

时间:2016-07-21 20:49:06

标签: c++ visual-c++ mfc activex

问题

为什么pWnd = (CWnd*)pMap->LookupPermanent(m_hWnd);偶尔会在CWnd :: DestroyWindow()函数中返回NULL,导致ASSERT语句在尝试销毁模式对话框时失败?

此外,在导致问题和尝试销毁窗口之间,为什么PreTranslateMessage()函数停止被调用?

初始信息

我有一个实现屏幕键盘的ActiveX控件。 此键盘接受来自连接的硬件键盘的触摸/单击事件和击键事件。 使用由创建键盘的模块定义的算法验证对控件的输入。

触摸屏幕上的按钮会生成

之后的输入
OnButtonUP()->AddCharacter()->ValidateText()

在物理键盘上键入会生成

之后的输入
PreTranslateMessage()->AddCharacter()->ValidateText()

ValidateText()函数触发由创建键盘的模块处理的事件。

我在事件触发周围添加了一个try-catch块来处理事件处理过程中发生的任何错误。

令人困惑的行为

我发现如果使用USB键盘导致错误,当用户尝试关闭键盘时,CWnd :: DestroyWindow()中的调试断言语句将失败。 如果使用触摸屏界面导致相同的错误,则断言语句成功。

我还发现,如果使用USB键盘导致错误,则ActiveX控件的PreTranslateMessage()函数将停止调用。我通过在函数的第一行设置断点并监视发送到窗口的消息来确认这一点。导致错误后仍然有大量消息(主要是wm_mousemoves),但断点不再导致程序中断。

源代码段摘要

触发事件的代码如下:

try
{
    m_control->OnValidate(&text, &isValid);
}
catch (...)
{
    LOG_CRITICAL_ERROR(/*Format(*/L"Keyboard::ValidateText: Error occured while validating"/*, badText.c_str()).c_str()*/);
}

OnValidate()函数定义为:

void OnValidate(BSTR* text, LONG* isValid)
{
    FireEvent(eventidOnValidate, EVENT_PARAM(VTS_PBSTR VTS_PI4), text, isValid);
}

CWnd :: DestroyWindow()函数是(删除了一些位预处理器位):

BOOL CWnd::DestroyWindow()
{
    CWnd* pWnd;
    CHandleMap* pMap;
    HWND hWndOrig;
    BOOL bResult;

    if ((m_hWnd == NULL) && (m_pCtrlSite == NULL))
        return FALSE;

    bResult = FALSE;
    pMap = NULL;
    pWnd = NULL;
    hWndOrig = NULL;
    if (m_hWnd != NULL)
    {
        pMap = afxMapHWND();
        ENSURE(pMap != NULL);
        pWnd = (CWnd*)pMap->LookupPermanent(m_hWnd); //<- This returns NULL before the Assert fails
        hWndOrig = m_hWnd;
    }

    if ((m_hWnd != NULL) || (m_pCtrlSite != NULL))
    {
        if (m_pCtrlSite == NULL)
            bResult = ::DestroyWindow(m_hWnd);
        else
            bResult = m_pCtrlSite->DestroyControl();
    }

    if (hWndOrig != NULL)
    {
        // Note that 'this' may have been deleted at this point,
        //  (but only if pWnd != NULL)
        if (pWnd != NULL)
        {
            // Should have been detached by OnNcDestroy
            ASSERT(pMap->LookupPermanent(hWndOrig) == NULL);
        }
        else
        {
            ASSERT(m_hWnd == hWndOrig); //<-This is the ASSERT that fails!
        // Detach after DestroyWindow called just in case
            Detach();
        }
    }

    return bResult;
}

从我通过跟踪点获得的,当断言失败时,pWnd = (CWnd*)pMap->LookupPermanent(m_hWnd);返回NULL。

使用来自跟踪点的信息,键盘控件的DestroyWindow()调用似乎如下:

何时起作用(由触摸输入处理引起的错误)

  • 开始销毁键盘:m_hWnd = NON-NULL,hWndOrig = NON-Null,pWnd = NON-NULL
  • 进入破坏键盘按钮:m_hWnd = NON-NULL,hWndOrig = NON-Null,pWnd = NON-NULL
  • 从销毁所有按钮返回:m_hWnd = NULL,hWndOrig = NON-Null,pWnd = NON-NULL
  • ASSERT(pMap->LookupPermanent(hWndOrig) == NULL);被调用并成功。

何时中断(处理硬件输入引起的错误)

  • 开始销毁键盘:m_hWnd = NON-NULL,hWndOrig = NON-Null,pWnd = NULL
  • 进入破坏键盘按钮:m_hWnd = NON-NULL,hWndOrig = NON-Null,pWnd = NON-NULL
  • 从销毁所有按钮返回:m_hWnd = NULL,hWndOrig = NON-Null,pWnd = NULL
  • ASSERT(m_hWnd == hWndOrig);被调用并失败。

0 个答案:

没有答案