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