【问题标题】:WM_TIMER stops suddenly in ATL ActiveX controlWM_TIMER 在 ATL ActiveX 控件中突然停止
【发布时间】:2012-09-23 08:13:13
【问题描述】:

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

我使用这种方法的问题是我的 WM_TIMER 在某个时间突然停止触发。我已经将其追溯到 UIDeactivate() 在我的控件上被调用,但我不知道为什么在之前未调用此方法时会调用此方法(我相信它与失去焦点有关)。

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

【问题讨论】:

  • 控制是如何实现的? ATL、MFC?
  • 它是用 ATL 实现的,但没有向导。

标签: c++ windows activex atl


【解决方案1】:

计时器停止是有原因的。可能是:

  1. 您确实可以通过KillTimer 调用停止计时器
  2. 您的窗口已重新创建,但计时器未重新启用
  3. 您的控件是无窗口的,实际上您没有HWND 句柄
  4. 定时器标识符有冲突,有其他东西(例如内部子类窗口)使用相同的标识符,它设置,终止定时器,你不再看到你之前启用的 WM_TIMER 消息
  5. 窗口线程忙(冻结)了一些不包括消息调度的活动,因此计时器本身存在,健康且有效,只是没有发送消息

要做的事情 - 没有关于手头问题的其他信息:

  1. 检查您的窗口线程和您的 Set/KillTimer 调用以确保它们都有意义
  2. 使用 Spy++ 工具检查为您的窗口和/或感兴趣的线程发布的消息,以了解您是否真的缺少WM_TIMERs,或者他们只是没有到达你的代码;您还可能会看到其他有趣的消息

【讨论】:

  • 我什至找不到带有 Spy++ 的 WM_TIMER 消息,即使我的应用程序的日志文件是这样说的。我试图在我的进程和我的主线程消息队列中找到它们。
  • 但我注意到了一些不同的东西。当我的计时器停止触发时,我的消息队列会收到WM_PAINT 消息的垃圾邮件。也许这两个问题是相关的?
  • 是的,它们可能是相关的。 WM_TIMER 是一条低优先级消息,如果您的消息队列几乎不能处理其他消息(与您原来的“其他一切似乎都正常工作”相反),则计时器消息可能不太准时。
  • 我在收到 WM_PAINT 消息时忘记验证我的客户区。添加ValidateRect() 解决了缺少计时器的问题。感谢您的帮助!
【解决方案2】:

这是CComControlBase 的ATL 实现的摘录(我猜您的控件继承自该)。检查标有<<<<<<<<<<<的部分:

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;
}

在停用时,控制窗口被破坏。因此它不能再处理 WM_TIMER。

【讨论】:

  • 未调用此 DestroyWindow()。问题是,我什至不知道为什么我的控件被停用了,因为在我引入子窗口之前它还没有被停用。
  • 即使控件被停用?你确定吗?当您注意到 WM_TIMER 不再被触发时,哪些窗口具有焦点?
  • 你能发布在你的控件中设置计时器的代码和处理它的代码吗?
  • 不幸的是我不能。 UIDeactivate() 似乎只有在我将另一个窗口放在我的应用程序前面时才会被调用。但只有当我使用子窗口时。以前在这种情况下不会调用它。
  • 好吧,如果没有看到任何代码就很难判断,尤其是定时器附加到哪个窗口以及它是如何处理的。到目前为止,我得到了这个:你说 DestroyWindow 没有被调用,尽管你确实被停用了——这看起来很奇怪,除非你有这个代码被覆盖或者你有你没有提到的无窗口控制。子窗口是如何创建的,有哪些样式?或多或少,我只能做一些猜测
猜你喜欢
  • 2011-02-04
  • 1970-01-01
  • 1970-01-01
  • 2011-04-04
  • 2014-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-03
相关资源
最近更新 更多