0

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

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

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

4

2 回答 2

2

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

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

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

  1. 检查你的窗口线程和你的 Set/KillTimer 调用以确保它们都有意义
  2. 使用 Spy++ 工具检查为您的窗口和/或感兴趣的线程发布的消息,以确定您是否真的缺少WM_TIMERs,或者它们只是没有到达您的代码;你也可能会看到其他有趣的消息
于 2012-10-02T13:29:58.057 回答
0

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

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 了。

于 2012-10-02T13:29:48.777 回答