I coded this multiple times. But it doesn't even seem to work in a simple console hello word application. Is hWND the one to blame, lambda, or the casting of the lambda?
void sleeper()
{
Sleep(10000);
}
int main()
{
SetTimer
(GetConsoleWindow(), 1, 1000, [](HWND, UINT, UINT_PTR, DWORD)
{
printf("Hello World!");
}
);
sleeper();
return 0;
}
It doesn't give me warnings and it wasn't so similar to the next example after all.
This is the other app, a maybe ugly windowed application that has the same issue, no timerproc execution:
else if (message == WM_PAINT)
{
PAINTSTRUCT ps;
static HDC hdc = BeginPaint(hWnd, &ps);// TODO: Add any drawing code that uses hdc here...
static std::vector<std::vector<std::vector<int>>> color[4] =
{
std::vector<std::vector<std::vector<int>>>(0x7F),
std::vector<std::vector<std::vector<int>>>(0x7F),
std::vector<std::vector<std::vector<int>>>(0x7F),
std::vector<std::vector<std::vector<int>>>(0xFF)
};
SetTimer
(hWnd, 1, 5000, [](HWND hWnd, UINT nMsdg, UINT_PTR unnamedParam, DWORD dwTime)->void
{
int x = 0;
int y = 0;
SetPixelV(hdc, x, y, COLORREF(color[x][y][0] * 0x1 color[x][y][1] * 0x100 color[x][y][2] * 0x10000));
}
);
EndPaint(hWnd, &ps);
}
Now in the second sample it has the message handling I think, but it doesn't draw a pixel. I have to say, separating RGBA was not so smart, I'm just too used to scripting.
CodePudding user response:
You cannot cast a lamba to a TIMEPROC* or any other type of function pointers that use a different calling convention than the default (one can not specify the calling convention of a lambda). Lambdas are callable objects. This type is similar to a class, with a member function.
Aside from that, you MUST use the correct declaration for yout TIMERPROC hook. It is:
// definition from the MS website. It is incomplete (typical from MS)
// ref: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nc-winuser-timerproc
void Timerproc(
HWND unnamedParam1,
UINT unnamedParam2,
UINT_PTR unnamedParam3,
DWORD unnamedParam4
)
// the actual definition from winuser.h.
typedef VOID (CALLBACK* TIMERPROC)(HWND, UINT, UINT_PTR, DWORD):
// note the use of CALLBACK, which expands to __stdcall. That's the very important
// detail missing from the actual documentation.
You can declare your timeproc as a free-standing function, or as a static member function of a class, Unfortunately the onluy parameter you can pass to the callback is a HWND, this means that if you want to pass any extra parameter to your callback, you have to use static (aka global) variables.
Example 1.
void CALLBACK myTimerProc(HWND, UINT, UINT_PTR, DWORD)
{
printf("Hello World!");
}
int main()
{
// NOTE nIDEvent, the timer ID has to be unique for the window and NON-ZERO,
// See MS documentation here: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-settimer
SetTimer(GetConsoleWindow(), 1, 1000, myTimerProc);
sleeper();
return 0;
}
Example2, if you want to define locally:
int main()
{
struct local // or any other
{
static void CALLBACK timerProc(HWND, UINT, UINT_PTR, DWORD)
{
printf("Hello World!");
}
}
SetTimer(GetConsoleWindow(), 1, 1000, local::timerProc);
sleeper();
return 0;
}
EDIT: For reference, the actual parameters for the TIMERPROC callback.
Source: http://www.icodeguru.com/VC&MFC/MFCReference/html/_mfc_cwnd.3a3a.settimer.htm
void CALLBACK EXPORT TimerProc(
HWND hWnd, // handle of CWnd that called SetTimer
UINT nMsg, // WM_TIMER
UINT nIDEvent // timer identification
DWORD dwTime // system time
);