0

SetTimer()私は元々、数秒ごとに起動する Windows タイマー ( を使用) を登録する ActiveX コントロールを持っていました。これまでのところうまくいきました。全画面表示モードを実装するために、コントロール自体がすべての 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++ ツールを使用して、ウィンドウや関心のあるスレッドに投稿されたメッセージをチェックし、本当にsがWM_TIMERないか、コードに到達していないかを調べます。また、他の興味深いメッセージが表示される場合があります
于 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 に答える