c++ - my timer class

heres my class 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
class Timer
{
	private:
		int MilliSecondsTimer;
		bool blnDestroyed;
		UINT TimerId;
		HANDLE Timer1;

	public:

		int SetMilliSeconds(int MilliSeconds)
		{
			MilliSecondsTimer = MilliSeconds;
			return 0;
		}

		int GetMilliSeconds()
		{
			return (MilliSecondsTimer);
		}

		int Start(TIMERPROC TimerProc)
		{
			TimerId = SetTimer(0, 0, MilliSecondsTimer,TimerProc);

			return 0;
		}

		int Stop()
		{
			KillTimer( 0,TimerId);
			return 0;
		}

		~Timer()
		{
			Stop();
		}
};

these class works fine. but i need these function header for works in start() class member:
1
2
3
4
5
VOID CALLBACK MyTimerProc(
    HWND hwnd,        // handle to window for timer messages
    UINT message,     // WM_TIMER message
    UINT idTimer,     // timer identifier
    DWORD dwTime)     // current system time 

how can i change the start() class member for accept lambda or adress function like these:
void MyTimerProc()?
my problem is change the start() argument type, but how make the SetTimer() working inside of the class :(
Can you give an example of how you want to use that timer class? I'm not clear on what you're trying to do.
finally works:
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
class Timer
{

private:
    UINT_PTR timerid=0;
    unsigned int intInterval=0;
    void TimerProc(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime)
    {
         timerprocedure();
    }

    static void CALLBACK _TimerProc(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime )
    {
        reinterpret_cast<Timer*>(idEvent)->TimerProc(hwnd,uMsg,idEvent,dwTime);
    }


public:

    std::function<void()> timerprocedure=NULL;

    property<unsigned int> Interval
    {
        Get(unsigned int)
        {
            return intInterval;
        },
        Set(unsigned int uintInterval)
        {
            intInterval = uintInterval;
        }
    };

    void Start()
    {
        if(timerid!=0)
            KillTimer(GetForegroundWindow(),timerid);
        timerid=SetTimer( GetForegroundWindow(),reinterpret_cast<UINT>(this),(UINT)intInterval,&Timer::_TimerProc);
    }

    void Stop()
    {
        KillTimer(GetForegroundWindow(),timerid);
        timerid=0;
    }

    ~Timer()
    {
        KillTimer(GetForegroundWindow(),timerid);
    }
};

heres how i use it:
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
Timer c;

void timeranimation()
{
    //just change the form image

    m.SelectFrame=m.SelectFrame+1;
    if(m.SelectFrame==m.FramesCount)
         m.SelectFrame=0;
    a.Text="hello";
    a.Refresh();
}

int WinMain()
{
    a.Text=test4;
    /*c.timerprocedure= []()
    {
        m.SelectFrame=m.SelectFrame+1;
        if(m.SelectFrame==m.FramesCount)
        m.SelectFrame=0;
        a.Text="hello";
        a.Refresh();
    };*/
    c.timerprocedure=timeranimation;
    c.Interval=250;
    c.Start();
//............... 

these code work fine.
but see these line of SetTimer():
timerid=SetTimer( GetForegroundWindow(),reinterpret_cast<UINT>(this),(UINT)intInterval,&Timer::_TimerProc);
like you see i must use GetForegroundWindow()... i can't 0(zero), so what you can advice me?
The timer is per-window or no window. You can't use GetForgroundWindow() as there's no guarantee that you'll get the same window each time. The timer class will need to keep the HWND used to start the timer. But to be honest, I don't know you don't just use NULL.

The callback is interesting. You're attempting to route the callback to the right timer instance, and so you use this as the timer id. It does make the reader sit up and think!

This link shows how you can pass in a function with its args, to be called from within the function.
http://www.cplusplus.com/forum/general/138965/
Casting an UINT to a pointer is bad and it will crash on 64 bit.
"Casting an UINT to a pointer is bad and it will crash on 64 bit. "
maybe because it's a poniter.. i change to:
reinterpret_cast<UINT_PTR>(this)

kbw: so, without create an invisible window, how can i do it?
if the HWND is NULL, the timer isn't executed :(
A timer will work with HWND=NULL :)
so why you don't test it? ;)

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
//take a bonus ;)
/*properties

- how use create 1 property with macro:

      PROPERTY(TypeName,PropertyName,getfunction, setfunction)

- never forget to do 1 Copy Constructor inside of class's, that uses the property,
         for avoid copy the 'this' value\adress and use a diferent memory adress
*/
template <typename T>
class property
{
private:
    T PropertyValue;
    std::function<T(void)> getf;
    std::function<void(T)> setf;
public:

    property(const T value)
    {
        getf=nullptr;
        setf=nullptr;
        PropertyValue=value;
    };

    property(const property &value)  :  PropertyValue(value.PropertyValue) , getf(value.getf)
    {
    }

    property(std::function<T(void)> GetFunction=nullptr,std::function<void(T)> SetFunction=nullptr)
    {
        setf=SetFunction;
        getf=GetFunction;
    }

    property& operator=(const T &value)
    {
        PropertyValue=value;
        if (setf!=nullptr)
            setf(value);
        return *this;
    }

    property& operator=(const property &value)
    {
        PropertyValue = value.PropertyValue;
        if (setf!=nullptr)
            setf(PropertyValue);
        return *this;
    }

    operator T()
    {
        if (getf!=nullptr)
            return getf();
        else
            return PropertyValue;
    }

    friend ostream& operator<<(ostream& os, property& dt)
    {
        if(dt.getf==nullptr && dt.setf==nullptr)
            os << dt.PropertyValue;
        else if (dt.getf!=nullptr)
            os << dt.getf();
        return os;
    }

    friend istream& operator>>(istream &input, property &dt)
    {
        input >> dt.PropertyValue;
        if (dt.setf!=nullptr)
            dt.setf(dt.PropertyValue);
        return input;
    }

    friend istream &getline(istream &in, property &dt)
    {
        getline(in, dt.PropertyValue);
        if (dt.setf!=nullptr)
            dt.setf(dt.PropertyValue);
        return in;
    }
};

template<typename T, typename Fnc1_t, typename Fnc2_t, typename classthis>
property<T> GetProperty(Fnc1_t Getter, Fnc2_t Setter, classthis clsthis)
{
    return property<T>(std::bind(Getter, clsthis), std::bind(Setter, clsthis, std::placeholders::_1));
}

#define PROPERTY(TypeName,PropertyName,getfunction, setfunction) \
property<TypeName> PropertyName{std::bind(&getfunction, *this),std::bind(&setfunction, *this, std::placeholders::_1)}
#define Get(x) [this]()->x
#define Set(...) [this](__VA_ARGS__)->void


class Timer
{

private:
    UINT_PTR timerid=0;
    unsigned int intInterval=0;
    void TimerProc(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime)
    {
         timerprocedure();
    }

    static void CALLBACK _TimerProc(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime )
    {
        reinterpret_cast<Timer*>(idEvent)->TimerProc(hwnd,uMsg,idEvent,dwTime);
    }


public:

    std::function<void()> timerprocedure=NULL;

    property<unsigned int> Interval
    {
        Get(unsigned int)
        {
            return intInterval;
        },
        Set(unsigned int uintInterval)
        {
            intInterval = uintInterval;
        }
    };

    void Start()
    {
        if(timerid!=0)
            KillTimer(NULL,timerid);
        timerid=SetTimer( NULL,reinterpret_cast<UINT_PTR>(this),(UINT)intInterval,&Timer::_TimerProc);
    }

    void Stop()
    {
        KillTimer(NULL,timerid);
        timerid=0;
    }

    ~Timer()
    {
        KillTimer(NULL,timerid);
    }
};

how i use it:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

#define WinMain() WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPreviousInstance, LPSTR lpCmLine, int nCmdShow)

Timer c;

void timeranimation()
{
    //just change the form image

    m.SelectFrame=m.SelectFrame+1;
    if(m.SelectFrame==m.FramesCount)
         m.SelectFrame=0;
    a.Text="hello";
    a.Refresh();
}

int WinMain()
{
    a.Text=test4;
    c.timerprocedure=timeranimation;
    c.Interval=250;
    c.Start();
//..... 

please test it ;)
i did several samples, that's why i know... unless i have a problem on my class.. i accept sugestions
I used Visual Studio Express to generate an empty Windows app, then plugged in the timer. It works (as I said previously).

win_sample.cpp:
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
// win_sample.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "win_sample.h"

#define MAX_LOADSTRING 100

// Global Variables:
HINSTANCE hInst;								// current instance
TCHAR szTitle[MAX_LOADSTRING];					// The title bar text
TCHAR szWindowClass[MAX_LOADSTRING];			// the main window class name

// Forward declarations of functions included in this code module:
ATOM				MyRegisterClass(HINSTANCE hInstance);
BOOL				InitInstance(HINSTANCE, int);
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK	About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

	MSG msg;
	HACCEL hAccelTable;

	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
	LoadString(hInstance, IDC_WIN_SAMPLE, szWindowClass, MAX_LOADSTRING);
	MyRegisterClass(hInstance);

	if (!InitInstance (hInstance, nCmdShow))
	{
		return FALSE;
	}

	hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN_SAMPLE));

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

	return (int) msg.wParam;
}

// TIMER CALLBACK
VOID CALLBACK TimerProc(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
	TCHAR str[1024];
	_sntprintf(str, sizeof(str)/sizeof(TCHAR), _T("hWnd=0x%x uMsg=0x%x idEvent=%d dwTime=%ld\n"), hWnd, uMsg, idEvent, dwTime);
	OutputDebugString(str);
}

ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);

	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN_SAMPLE));
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= MAKEINTRESOURCE(IDC_WIN_SAMPLE);
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

	return RegisterClassEx(&wcex);
}

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // Store instance handle in our global variable

   HWND hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
   if (!hWnd)
      return FALSE;

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);
   SetTimer(NULL, 3, 1000, TimerProc); // Invoke timer
   return TRUE;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc;

	switch (message)
	{
	case WM_COMMAND:
		wmId    = LOWORD(wParam);
		wmEvent = HIWORD(wParam);
		// Parse the menu selections:
		switch (wmId)
		{
		case IDM_ABOUT:
			DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
			break;
		case IDM_EXIT:
			DestroyWindow(hWnd);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
		}
		break;
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		// TODO: Add any drawing code here...
		EndPaint(hWnd, &ps);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(lParam);
	switch (message)
	{
	case WM_INITDIALOG:
		return (INT_PTR)TRUE;

	case WM_COMMAND:
		if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
		{
			EndDialog(hDlg, LOWORD(wParam));
			return (INT_PTR)TRUE;
		}
		break;
	}
	return (INT_PTR)FALSE;
}


stdafx.h:
1
2
3
4
5
6
7
8
9
10
11
12
13
#pragma once

#include "targetver.h"

#define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers
// Windows Header Files:
#include <windows.h>

// C RunTime Header Files
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h> 
Last edited on
Where the hell is your application main loop ?
modoran: do you want my own cambalinho.h file?(yes... i can share it without problems)
is too big... more than 5850 lines of code ;)
i can make forms with just 1 line of code.. ;)

but goind back 1 thing that i'm confused: why i can't use the GetForegroundWindow()?
kbw: sorry.. but why i can use the NULL on my code?.. sorry.. i'm confused :(
You'' just have to debug it. Just create a seperate timer callback function and start a timer with: SetTimer(NULL, 3 /*some integer id*/, 1000 /*1 sec*/, TimerCallback /*your callback*/);
You can copy my callback that just writes to the debug console.

Once that works, start building your class around it, running it after each change.

EDIT: Computers are meant to be deterministic, but it doesn't always feel that way.
Last edited on
I repet the question, where is your application main loop ? It must be in WinMain. Without it, your callback is never called.

You posted your WinMain as being this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#define WinMain() WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPreviousInstance, LPSTR lpCmLine, int nCmdShow)

Timer c;

void timeranimation()
{
    //just change the form image

    m.SelectFrame=m.SelectFrame+1;
    if(m.SelectFrame==m.FramesCount)
         m.SelectFrame=0;
    a.Text="hello";
    a.Refresh();
}

int WinMain()
{
    a.Text=test4;
    c.timerprocedure=timeranimation;
    c.Interval=250;
    c.Start();
//.....  


But I don't see these here:
1
2
3
4
5
6
7
8
while (GetMessage(&msg, NULL, 0, 0))
	{
		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}



It is DispatchMessage that actually invokes your callback if first argument is NULL. And even if you don't want to be NULL, why don't you just give it your main window handle (you already know it) instead of stupid things like GetForegroundWindow ? You can have multiple timers with different IDs, but you need to process WM_TIMER messages.
Last edited on
is in winmain()
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
//Message Loop
WPARAM MessageLoop(HWND MainWindow)
{
    MSG msgEvents;
    /*while(GetMessage(&msgEvents,0,0,0)>0)
    {
        if(!IsDialogMessage(MainWindow,&msgEvents))
        {
            TranslateMessage(&msgEvents);
            DispatchMessage(&msgEvents);
        }
    }*/
    while(GetMessage(&msgEvents, NULL, 0, 0) > 0)
    {
        TranslateMessage(&msgEvents);
        DispatchMessage(&msgEvents);
    }
    return msgEvents.wParam;
}


int WinMain()
{
    a.Text=test4;
    c.timerprocedure=timeranimation;
    c.Interval=250;
    c.Start();
   return MessageLoop(a);
}

sorry about that.. realy sorry
@Cambalinho

http://msdn.microsoft.com/en-us/library/windows/desktop/ms644906
If the hWnd parameter is NULL, and the nIDEvent does not match an existing timer then it is ignored and a new timer ID is generated.

Your code is using the ID parameter to pass a pointer to the timer object.. this won't work with a NULL window handle.
sorry to all... but i continue confused with 1 thing...
i have the HWND=NULL and:
1
2
3
4
5
void TimerProc(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime)
    {
         //timerprocedure();
         MessageBox(NULL,"hi", "hi", MB_OK);
    }

the messagebox is showed.

1
2
3
4
5
void TimerProc(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime)
    {
         timerprocedure();
         MessageBox(NULL,"hi", "hi", MB_OK);
    }

but now nothing is done... is these that make me confuse...
Then see exactly where timerprocedure() fails and check all APIs return code and do a GetLastError after each of them to get to the problem.
Do you close the MessageBox each time or do you leave it open? I can't remember if it matters.

I used OutputDebugString because you can see it in the output windows in VS, and it doesn't interfere with the program.
the messagebox don't need be closed, because is open anotherone
Topic archived. No new replies allowed.