【问题标题】:Can I use a SetTimer() API in a console C++ application?我可以在控制台 C++ 应用程序中使用 SetTimer() API 吗?
【发布时间】:2011-11-23 19:17:03
【问题描述】:

我有一个控制台应用程序正在使用一个 DLL 文件,该文件使用 SetTimer() 调用来创建一个计时器并在其内部触发一个函数。电话如下:

SetTimer((HWND)NULL, 0, timer_num, (TIMERPROC)UnSyncMsgTimer)) == 0) 

它期望接收计时器消息,但这从未发生过。我假设是因为我的是一个控制台应用程序,而不是一个标准的 Windows GUI 应用程序(就像最初使用 DLL 文件的地方)。这会使 DLL 文件功能的关键部分停止工作。

我的应用程序需要保持控制台应用程序,我无法更改 DLL。

是否有变通办法来完成这项工作?

【问题讨论】:

  • @Hans:JallenA1 说他无法更改 DLL,所以使用SetTimer() 卡住了。

标签: c++ windows timer console


【解决方案1】:

看看下面的例子,它展示了如何在控制台应用程序中使用 WM_TIMER 消息:

(归功于simplesamples.info 网站)

#define STRICT 1 
#include <windows.h>
#include <iostream.h>

VOID CALLBACK TimerProc(HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime) {
  cout << "Time: " << dwTime << '\n';
  cout.flush();
}

int main(int argc, char *argv[], char *envp[]) {
      int Counter=0;
      MSG Msg;
      UINT TimerId = SetTimer(NULL, 0, 500, &TimerProc);

      cout << "TimerId: " << TimerId << '\n';
      if (!TimerId)
        return 16;
      while (GetMessage(&Msg, NULL, 0, 0)) {
        ++Counter;
      if (Msg.message == WM_TIMER)
        cout << "Counter: " << Counter << "; timer message\n";
      else
        cout << "Counter: " << Counter << "; message: " << Msg.message << '\n';
      DispatchMessage(&Msg);
    }

    KillTimer(NULL, TimerId);

    return 0;
}

【讨论】:

  • 从控制台应用程序创建和使用计时器的好例子,但是为了使该示例应用程序真正做任何有用的事情,计时器处理(和 Windows 消息泵送)需要进入一个单独的线程。
  • 什么时候退出while循环?没有任何东西在上面发布退出消息,也没有返回、中断或抛出......
  • @Chad:不一定需要在单独的线程中。该循环可以使用MsgWaitForMultipleObjects()GetQueueStatus() 来检测消息何时准备好进行处理,同时可以继续执行其他操作。
  • 没错,但是如果您已经有使用多线程程序的经验,那么与使用 WM_TIMER 消息和适当的构造使其正常工作相比,在线程中进行计时是微不足道的。
【解决方案2】:

使用SetTimer API 设置的定时器需要 Windows 消息处理函数主动运行,因为这是发送时间消息的地方。

如果您需要一个计时器线程,那么您可以注册一个 Window 类并创建一个默认窗口消息泵(参见this article 的简短示例),但更简单的过程可能是启动第二个线程来处理您的计时事件并发送通知。

【讨论】:

  • 您不需要窗口类来创建消息泵。只是一个调用Peek/GetMessage()TranslateMessage()DispatchMessage() 的简单循环。
  • 这个建议对我非常有用。我创建了一个简单的线程,线程进程调用Sleep()然后唤醒并执行它的任务。一旦你给了我这个想法,我很快就完成了;谢谢!
【解决方案3】:

您考虑过Waitable Timers 还是Timer Queues?虽然可以在控制台应用程序中使用 SetTimer,但这些其他工具可能更适合您。

【讨论】:

    【解决方案4】:

    您可以使用CreateTimerQueueTimer function

    HANDLE timer_handle_;
    CreateTimerQueueTimer(&timer_handle_, NULL, TimerProc, user_object_ptr, 10, 0, WT_EXECUTEDEFAULT);
    //callback
    void TimerProc(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
    {
        user_object* mgr = (user_object*) lpParameter;
        mgr->do();
        DeleteTimerQueueTimer(NULL, timer_handle_, NULL);
        timer_handle_ = NULL;
    }
    

    【讨论】:

      【解决方案5】:

      没有 Windows 的非常简单的计时器

      MSG Msg;
      
      UINT TimerId = (UINT)SetTimer(NULL, 0, 0, NULL); // 0 minute
      
      while (TRUE)
      {
          GetMessage(&Msg, NULL, 0, 0);
      
          if (Msg.message == WM_TIMER)
          {
              KillTimer(NULL, TimerId);
      
              cout << "timer message\n";
      
              TimerId = (UINT)SetTimer(NULL, 0, 60000, NULL); // one minute.
          }
      
          DispatchMessage(&Msg);
      }
      

      【讨论】:

        【解决方案6】:

        使用定时器队列

        创建一个定时器队列定时器。此计时器在指定的到期时间到期 时间,然后在每个指定的时间段之后。当定时器到期时, 回调函数被调用。

        以下示例创建一个计时器例程,将由 延迟 10 秒后来自 timer queue 的线程。首先, 代码使用CreateEvent函数创建事件对象 当计时器队列线程完成时发出信号。然后它 创建一个定时器队列和一个定时器队列定时器,使用 CreateTimerQueue 和 CreateTimerQueueTimer 函数, 分别。该代码使用WaitForSingleObject 函数 确定计时器例程何时完成。最后,代码 致电DeleteTimerQueue 进行清理。

        有关计时器例程的更多信息,请参阅WaitOrTimerCallback

        来自 MSDN 的示例代码:

        #include <windows.h>
        #include <stdio.h>
        
        HANDLE gDoneEvent;
        
        VOID CALLBACK TimerRoutine(PVOID lpParam, BOOLEAN TimerOrWaitFired)
        {
            if (lpParam == NULL)
            {
                printf("TimerRoutine lpParam is NULL\n");
            }
            else
            {
                // lpParam points to the argument; in this case it is an int
        
                printf("Timer routine called. Parameter is %d.\n", 
                        *(int*)lpParam);
                if(TimerOrWaitFired)
                {
                    printf("The wait timed out.\n");
                }
                else
                {
                    printf("The wait event was signaled.\n");
                }
            }
        
            SetEvent(gDoneEvent);
        }
        
        int main()
        {
            HANDLE hTimer = NULL;
            HANDLE hTimerQueue = NULL;
            int arg = 123;
        
            // Use an event object to track the TimerRoutine execution
            gDoneEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
            if (NULL == gDoneEvent)
            {
                printf("CreateEvent failed (%d)\n", GetLastError());
                return 1;
            }
        
            // Create the timer queue.
            hTimerQueue = CreateTimerQueue();
            if (NULL == hTimerQueue)
            {
                printf("CreateTimerQueue failed (%d)\n", GetLastError());
                return 2;
            }
        
            // Set a timer to call the timer routine in 10 seconds.
            if (!CreateTimerQueueTimer( &hTimer, hTimerQueue, 
                    (WAITORTIMERCALLBACK)TimerRoutine, &arg , 10000, 0, 0))
            {
                printf("CreateTimerQueueTimer failed (%d)\n", GetLastError());
                return 3;
            }
        
            // TODO: Do other useful work here 
        
            printf("Call timer routine in 10 seconds...\n");
        
            // Wait for the timer-queue thread to complete using an event 
            // object. The thread will signal the event at that time.
        
            if (WaitForSingleObject(gDoneEvent, INFINITE) != WAIT_OBJECT_0)
                printf("WaitForSingleObject failed (%d)\n", GetLastError());
        
            CloseHandle(gDoneEvent);
        
            // Delete all timers in the timer queue.
            if (!DeleteTimerQueue(hTimerQueue))
                printf("DeleteTimerQueue failed (%d)\n", GetLastError());
        
            return 0;
        }
        

        这是来自MSDN的另一个示例代码

        这是Codeproject的另一个例子

        #include <windows.h>
        HANDLE hTimer = NULL;
        unsigned long _stdcall Timer(void*)
        {
            int nCount = 0;
            while(nCount < 10)
            {
            WaitForSingleObject(hTimer, 5000);
            cout << "5 s\n";
            nCount++;
            }
            cout << "50 secs\n";
            return 0;
        }
        void main()
        {
            DWORD tid;
            hTimer = CreateEvent(NULL, FALSE, FALSE, NULL);
            CreateThread(NULL, 0, Timer, NULL, 0, &tid);
            int t;
            while(cin >> t)
            {
                if(0==t)
                    SetEvent(hTimer);
            }
            CloseHandle(hTimer);
        }
        

        资源:

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-05-21
          • 2014-02-04
          • 1970-01-01
          • 2022-01-20
          • 1970-01-01
          相关资源
          最近更新 更多