C++ ATL ActiveX控件中的WM_计时器突然停止

C++ ATL ActiveX控件中的WM_计时器突然停止,c++,windows,activex,atl,C++,Windows,Activex,Atl,我最初有一个ActiveX控件,它注册了一个每隔几秒钟启动一次的Windows计时器(使用SetTimer())。到目前为止效果不错。现在,为了实现全屏模式,我在控件中添加了一个子窗口,该窗口应该在控件本身管理所有ActiveX内容的同时显示内容 这种方法的问题是,我的WM_定时器在某个时间突然停止工作。我将其追溯到控件上被调用的UIDeactivate(),但我不知道以前没有调用该方法时为什么会调用它(我相信它与失去焦点有关) 我还想知道为什么我的WM_定时器事件突然停止,而其他一切似乎仍然正

我最初有一个ActiveX控件,它注册了一个每隔几秒钟启动一次的Windows计时器(使用
SetTimer()
)。到目前为止效果不错。现在,为了实现全屏模式,我在控件中添加了一个子窗口,该窗口应该在控件本身管理所有ActiveX内容的同时显示内容

这种方法的问题是,我的WM_定时器在某个时间突然停止工作。我将其追溯到控件上被调用的
UIDeactivate()
,但我不知道以前没有调用该方法时为什么会调用它(我相信它与失去焦点有关)


我还想知道为什么我的WM_定时器事件突然停止,而其他一切似乎仍然正常工作。它与在子窗口而不是ActiveX控件本身上显示内容有什么关系呢?

这里摘录自
CComControlBase
的ATL实现(我猜您的控件继承自此)。检查标有
定时器停止原因的零件。这可能是:

  • 您可以通过调用
    KillTimer
    来停止计时器
  • 您的窗口已重新创建,但计时器未重新启用
  • 控件是无窗口的,实际上没有
    HWND
    句柄
  • 计时器标识符中存在冲突,还有其他东西(例如内部子类窗口)使用相同的标识符,它设置、终止计时器,您将不再看到先前启用的
    WM_timer
    消息
  • 窗口线程正忙于(冻结)某些不包括消息调度的活动,因此计时器本身存在,运行正常且处于活动状态,只是没有发送消息
  • 要做的事情——手头上没有关于这个问题的更多信息:

  • 检查窗口的线程和Set/KillTimer调用,以确保它们一起有意义
  • 使用Spy++工具检查为您的窗口和/或感兴趣的线程发布的消息,以确定是否确实缺少
    WM_TIMER
    s,或者它们没有到达您的代码;此外,您可能还会看到其他有趣的消息

  • 如何实施控制?ATL,MFC?它是用ATL实现的,但没有向导。不调用此
    DestroyWindow()
    。问题是,我甚至不知道为什么我的控件被停用,因为在我引入子窗口之前它还没有被停用。即使控件被停用?你确定?当你注意到WM_定时器不再被触发时,哪个窗口有焦点?你能在控件中发布设置定时器的代码和处理定时器的代码吗?不幸的是,我不能
    UIDeactivate()
    似乎只有在我将另一个窗口放在应用程序前面时才会被调用。但前提是我要使用“儿童”窗口。以前在这种情况下它没有被调用。好吧,如果没有看到任何代码,很难判断,尤其是计时器连接到哪个窗口,以及它是如何处理的。到目前为止,我明白了这一点:你说DestroyWindow没有被调用,尽管你确实被停用了——这看起来很奇怪,除非你重写了这段代码,或者你有你没有提到的无窗口控件。子窗口是如何创建的,使用哪些样式?或多或少,我只能做一些猜测,我甚至找不到Spy++的
    WM_定时器
    消息,即使我的应用程序的日志文件这么说。我试图在进程和主线程消息队列中找到它们,但我发现了一些不同的东西。当我的计时器停止启动时,我的消息队列被垃圾发送
    WM_PAINT
    消息。也许这两个问题是相关的?是的,它们可能是相关的
    WM_TIMER
    是一条低优先级消息,如果您的消息队列对其他消息几乎不起作用(与您最初的“其他一切似乎都正常工作”),则计时器消息可能不太准时。收到WM_PAINT消息时,我忘了验证我的客户端区域。添加一个
    validated()
    解决了缺少计时器的问题。谢谢你的帮助!
    inline HRESULT CComControlBase::IOleInPlaceObject_InPlaceDeactivate(void)
    {
        if (!m_bInPlaceActive)
            return S_OK;
    
        if(m_bUIActive) {
            CComPtr<IOleInPlaceObject> pIPO;
            ControlQueryInterface(__uuidof(IOleInPlaceObject), (void**)&pIPO);
            ATLENSURE(pIPO != NULL);
            pIPO->UIDeactivate();
        }
    
        m_bInPlaceActive = FALSE;
    
        // if we have a window, tell it to go away.
        //
        if (m_hWndCD)
        {
            ATLTRACE(atlTraceControls,2,_T("Destroying Window\n"));
            if (::IsWindow(m_hWndCD))
                DestroyWindow(m_hWndCD);  <<<<<<<<<<<<<<<<<<<<<<<<<<<
            m_hWndCD = NULL;
        }
    
        if (m_spInPlaceSite)
            m_spInPlaceSite->OnInPlaceDeactivate();
    
        return S_OK;
    }