2016-04-15 8 views
-1

私は自分のコードに問題があり、数時間後、私はそれを把握するように見えることはできません...は削除できないWM_TIMERメッセージ

問題:私はへの接続を試行しようとしていますサーバーを10秒ごとに起動します。タイマーが最初に経過すると、コールバック関数はちょうどいいと呼ばれますが、すぐに(10秒待たずに)再び呼び出され、タイマーメッセージが取り除かれないかのように何度も繰り返し呼び出され続けます待ち行列。誰も助けることができますか?

タイマーがここで設定されています

SConnect::SConnect() 
{ 
    hSimConnect = NULL; 
    Attempt(); 
    SetTimer(hMainWindow, reinterpret_cast<UINT_PTR>(this), 10000, (TIMERPROC)TimerProc); 
} 

(のみ)アプリケーションのメッセージループはここにある:

while (true) 
    { 
     PeekMessage(&msg, NULL, 0, 0, PM_REMOVE); 
     if (msg.message == WM_QUIT) 
      break; 

     if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 
     { 
      TranslateMessage(&msg); 
      DispatchMessage(&msg); 
     } 

     //UPDATES 
     pSCObj->Update(); 
     manager.Update(); 
     Sleep(50); 
    } 

とタイマコールバック関数はここにある:

void CALLBACK SConnect::TimerProc(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime){ 
    SConnect *pSC = reinterpret_cast<SConnect *>(idEvent); 
    MSG wMsg; 

    if (!pSC->connected) 
    pSC->Attempt(); 
    else{ 
     pSC->connected = false; 
    } 
} 

I本当に助けていただきありがとうございます...詳細情報が必要な場合はお知らせください...

あなたが不要になった

敬具、 ファーリー

+3

これらのタイマは周期的である:のPeekMessage()がtrueの修正に問題を返すときにだけメッセージを派遣

。あなたはそれらを止めるために 'KillTimer()'を呼び出す必要があります。 –

+0

ああ申し訳ありませんが、私の質問は不明でした。私はコールバックが何度も繰り返し呼び出されていることを意味しました。(10秒ごとではありません) – lequinne

+0

[mcve]を入力してください。混乱の恐れはありません –

答えて

2

GetMessage()ではなく、メッセージループでPeekMessage()を呼び出しているため、これが起こっていると思います。

PeekMessage()は、キューにメッセージがない場合はFALSEを返します。 PeekMessage()の実装が何であるかはわかりませんが、キューにメッセージがない場合は、msgパラメータの内容だけを残しています。つまり、PeekMessage()FALSEを返すと、msgにはキューに前のメッセージが含まれます。 msgは、次に盲目的にDispatchMessage()に渡されます。これは、それを忠実にウィンドウのウィンドウプロシージャに渡します。したがって、WM_TIMERメッセージが最後に処理されたメッセージである限り、別のメッセージがキューに追加されるまで、タイマーコールバックが呼び出されます。あなたは、より伝統的なメッセージループを使用することによってこの問題を解決することができ

:内のメッセージがあるまで

BOOL bRet; 

while((bRet = GetMessage(&msg, nullptr, 0, 0)) != 0) 
{ 
    if (bRet == -1) 
    { 
     // handle the error and possibly exit 
    } 
    else 
    { 
     TranslateMessage(&msg); 
     DispatchMessage(&msg); 
    } 

    pSCObj->Update(); 
    manager.Update(); 
} 

(。メッセージループがGetMessage()ドキュメントのサンプルから適応)

GetMessage()のではブロックされます待ち行列では、Sleep()に電話する必要はなく、何もする必要がなければ、プロセスはCPUを使用しません。

+0

私はすべてのプログラムで同じメッセージループを使います。もはやそれに注意を払っていない:) '睡眠(50)' shoudは良い警告だった。 +1 – Matthieu

+2

これは機能的な置き換えではないことに注意してください.Update()メソッドは十分に呼び出されません。 PeekMessage()を使用しても問題ありません。戻り値は無視してください。 –

+0

@Hansそれは公正です。質問者を始めさせるために最小限の例を挙げようとしていました。 – Andy

0

ちょうどKillTimer()を呼び出す:

KillTimer(hMainWindow, reinterpret_cast<UINT_PTR>(this)); 

接続が行われた場合には、あなたのTimerProc()コールバックで、またはあなたのAttempt()方法にすることができます。私はあなたがあなたのAttempt()方法でtrueにそれを設定していると思いますが、あなたのタイマーコールバックでfalsepSC->connectedを設定しているので、あなたはおそらく、あまりにも頻繁にAttempt()を呼び出してしまいます:

また、あなたのロジックは、私には奇妙に思えます。それをAttemptConnection()などの名前に変更することもできます。

+0

ああ申し訳ありませんが、私の質問は不明でした。私はコールバックが何度も何度も何度も呼び出されていることを意味していました。 – lequinne

+0

@lequinneあなたは 'Attempt()'から 'TimerProc()'を直接呼び出していますか? – Matthieu

+0

ロジックに関しては、私はコミュニケーションを受けるたびにconnected = trueを設定しています(かなり頻繁に起こるはずです)。コールバックでfalseに設定したので、10秒以内に通信が得られなかった場合、接続が失われているとみなして再接続を試みます。そうでなければ、Attempt()を呼び出すべきではありません。 – lequinne

1

PeekMessage()の戻り値がチェックされていないという問題があります。各ループで新しいメッセージがない場合、PeekMessageはmsgの内容を変更せずにそのまま送出します。

while (true) 
    { 
     if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){ 
      if (msg.message == WM_QUIT) 
       break;  

      if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 
      { 
       TranslateMessage(&msg); 
       DispatchMessage(&msg); 
      } 
     } 

     //UPDATES 
     pSCObj->Update(); 
     manager.Update(); 
     Sleep(50); 
    } 
関連する問題