why i can't use SetTimer() without a window?

1
2
3
4
5
6
7
8
9
static void CALLBACK TimerFunction(HWND _hWnd, UINT _msg, UINT_PTR _idTimer, DWORD _dwTime)
    {
        Timer * obj = (Timer*)_idTimer;
        if(obj->timerprocedure!=nullptr)
            obj->timerprocedure();
    }

//............
timerid=SetTimer(NULL, (UINT_PTR)this, intInterval,(TIMERPROC) &Timer::MultimediaTimerFunction);

'this' is the parameter for i get the Timer instance.
if i use a window(can't be GetDesktopWindow()), the timer is executed. but i must create a window just for that.
can anyone advice me?
Last edited on
Create an invisible window.
i did that and ignored the timer procedure for use WM_TIMER:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
class Timer
{
private:
    static unsigned int TimerCount;
    HANDLE m_timerHandle=0;
    UINT_PTR timerid;
    UINT m_uResolution=0;
    UINT resolution=0;
    unsigned int TimerID=0;
    DWORD intInterval=0;
    WNDCLASSEX wc;
    static HWND hwnd;
    bool blnTimerDestroyed=false;
    const char *g_szClassName = "myWindowClass";

    static LRESULT CALLBACK TimerWindow(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
        switch(msg)
        {
            case WM_TIMER:
            {
                Timer* obj=reinterpret_cast<Timer*>(wParam);
                if(obj->timerprocedure!=nullptr)
                {
                    obj->timerprocedure();
                }
                else
                    DebugText("no timer");

            }
            break;
            default:
                return DefWindowProc(hwnd, msg, wParam, lParam);
        }
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }

    static void CALLBACK MultimediaTimerFunction(UINT wTimerID, UINT msg, DWORD InstancePointer, DWORD dw1, DWORD dw2)
    {
        Timer* obj=(Timer*)(InstancePointer);
        if(obj->timerprocedure!=nullptr)
            obj->timerprocedure();
        else
            DebugText("error no timer");
    }

public:

    std::function<void()> timerprocedure=EmptyEvent;
    Timer(std::function<void()> tmrprocedure=EmptyEvent)
    {
        TimerCount+=1;
        TimerID=TimerCount-1;
        timerprocedure=tmrprocedure;
    }

    void Stop()
    {
        if(timerid!=0 || timerid!=NULL)
        {
            if(intInterval<10)
            {
                // destroy the timer
                timeKillEvent(timerid);

                // reset the timer
                timeEndPeriod (m_uResolution);
            }
            else
            {
                if(KillTimer(hwnd,timerid)==FALSE)
                    DebugText("error on destroying the timer: " + to_string(GetLastError()) + "\ttimer id" + to_string(TimerID));
            }
        }
    }

    DWORD GetInterval()
    {
        return intInterval;
    }

    void SetInterval(DWORD uintInterval)
    {
        intInterval = uintInterval;
    }

    property <DWORD> Interval{GetProperty(Timer::GetInterval),SetProperty(Timer::SetInterval)};

    void Start()
    {
        if(timerid!=0)
            Stop();

        if(intInterval<10)
        {
            TIMECAPS tc;
            timeGetDevCaps(&tc, sizeof(TIMECAPS));
            m_uResolution = min(max(tc.wPeriodMin, 0), tc.wPeriodMax);
            timeBeginPeriod(m_uResolution);
            timerid=timeSetEvent(intInterval, m_uResolution,&Timer::MultimediaTimerFunction ,(DWORD)this,    TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
        }
        else
        {
            if(hwnd==NULL)
            {
                wc.cbSize        = sizeof(WNDCLASSEX);
                wc.style         = 0;
                wc.lpfnWndProc   = Timer::TimerWindow;
                wc.cbClsExtra    = 0;
                wc.cbWndExtra    = 0;
                wc.hInstance     = GetModuleHandle(NULL);
                wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
                wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
                wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
                wc.lpszMenuName  = NULL;
                wc.lpszClassName = g_szClassName;
                wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

                if(!RegisterClassEx(&wc))
                {
                    MessageBox(NULL, "Window Registration Failed!", "Error!",
                        MB_ICONEXCLAMATION | MB_OK);
                }

                // Step 2: Creating the Window
                hwnd = CreateWindowEx(
                    WS_EX_CLIENTEDGE,
                    g_szClassName,
                    "My Timer Window",
                    WS_OVERLAPPEDWINDOW,
                    CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
                    NULL, NULL, GetModuleHandle(NULL), NULL);

                if(hwnd == NULL)
                {
                    MessageBox(NULL, "Window Creation Failed!", "Error!",
                        MB_ICONEXCLAMATION | MB_OK);
                }

                ShowWindow(hwnd, SW_HIDE);
                UpdateWindow(hwnd);

            }
            if(hwnd==NULL)
                DebugText("no window");
            timerid=SetTimer(hwnd, reinterpret_cast<UINT_PTR>(this), intInterval,NULL);
        }
        if(timerid==0 || timerid==NULL)
            DebugText("error: " + to_string(GetLastError()));
    }

    ~Timer()
    {
        if(timerid!=0)
            Stop();
        TimerCount-=1;
        if(TimerCount==0 && hwnd!=NULL)
            DestroyWindow(hwnd);
    }
};
unsigned int Timer::TimerCount=0;
HWND Timer::hwnd=NULL;

my Stop() is correct with KillTimer()?
why the question!?! because sometimes the timer isn't destroyed for be created again(like gif's animation, they can have diferent delays from frames).
what you can tell?
because sometimes the timer isn't destroyed for be created again(like gif's animation, they can have diferent delays from frames).
MSDN wrote:
The KillTimer function does not remove WM_TIMER messages already posted to the message queue.

Don't kill and recreate the same timer over and over. Create one timer and use it for all animations by keeping state:
1
2
3
4
5
6
7
8
//Assume 17 ms timer.
void Animation::timer_event(){
    this->time_to_next_frame -= 17;
    if (this->time_to_next_frame > 0)
        return;
    this->advance_animation();
    this->time_to_next_frame += this->current_frame.duration;
}
i'm sorry, saying that: how can i destroy the timer?
Your code looks correct to me. If you continue to receive WM_TIMER messages after you killed the timer, it's possible that they were already queued at the time you did so.
my problem, sometimes, after the KillTimer() and then the SetTimer(), is that the timer don't starts :(
that function works fine. the problem was on another place. sorry. now is resolved.
Topic archived. No new replies allowed.