I have a very old application and I'm surprised. This application runs without message loop.
(GetMessage or PeekMessage).
How is it possible?
Edited example from Visual Studio:
HINSTANCE g_hInstance = NULL;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow);
ATOM _RegisterClass(HINSTANCE hInstance);
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
_RegisterClass(hInstance);
InitInstance(hInstance, SW_NORMAL);
return 0;
}
ATOM _RegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXA wcex = {0};
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_SAVEBITS;
wcex.lpfnWndProc = WndProc;
wcex.hInstance = hInstance;
wcex.lpszClassName = "TEST_CLASS";
ATOM a = 0;
a = RegisterClassExA(&wcex);
return a;
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
g_hInstance = hInstance; // Store instance handle in our global variable
hWnd = CreateWindowA("TEST_CLASS", "TEST_WINDOW", WS_OVERLAPPEDWINDOW,
0, 0, 0, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
SendMessageW(hWnd, WM_USER, 111, 0);
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_CREATE:
OutputDebugStringA("Create called.\n");
break;
case WM_USER:
{
if (wParam == 111)
{
OutputDebugStringA("User called.\n");
}
}
break;
case WM_DESTROY:
OutputDebugStringA("Destroy called.\n");
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
DEBUG OUTPUT:
Create called.
User called.
Destroy called.
The program '[2152] Test.exe: Native' has exited with code 0 (0x0).
That is expected behavior.
CreateWindow calls SendMessage to send WM_NCCREATE and WM_CREATE to the window being created. SendMessage behaves as follows (quote from MSDN):
If the specified window was created by the calling thread, the window procedure is called immediately as a subroutine.
Your program calls CreateWindow, which subsequently calls your window procedure (outputting "Create called" upon WM_CREATE) and then returns. It verifies that the window handle is non-null, which is the case, and returns with an exit code of 0 instead of entering a message pump.
It does not output "Destroy called" (as you maybe expected) because that isn't happening. The window is not being destroyed (well, eventually it is, by the operating system), the program just exits.
About the edited code:
The new code differs in calling SendMessageW, which again calls the window procedure directly. Therefore, the user message is received although there is no message pump.
It seems like the destroy message now makes it through, too, which is admittedly a bit surprising. Not sure what the reason for that would be.
Note that the window was created with an "A" function, so calling a "W" function is generally not advisable (even though it seems to "work" here).
Related
Question:
I am trying to set up the Winapi with C to display a simple window with the bare minimum of code, how do I do that in the way that my source code is formatted?
Issue:
The following does not open a window, it simply closes, why is this?
/* window_s.h */
typedef struct {
WNDCLASS wc;
HINSTANCE hInstance;
HWND hwnd;
} WINDOW;
/* setUpWinProc.h */
LRESULT CALLBACK WindowProc( HWND hwnd,
UINT uMsg, WPARAM wParam,
LPARAM lParam) { }
/* registerWindow.c */
void registerWindow(WINDOW *window) {
const char CLASS_NAME[]
= "Window Class Name";
window->wc.lpfnWndProc = WindowProc;
window->wc.hInstance = window->wc.hInstance;
window->wc.lpszClassName = CLASS_NAME;
RegisterClass(&(window->wc));
}
/* createWindow.c */
int_fast64_t CreateWindow_(WINDOW *window) {
window->hwnd = CreateWindowEx(
0, // Optional window styles
window->wc.lpszClassName, // Window class
"Window", // Window text
WS_OVERLAPPEDWINDOW, //Window style
// Size and position
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, // Parent window
NULL, // Menu
window->hInstance, // Instance handle
NULL // Additional application data
);
if (window->hwnd == NULL)
return 0;
return window->hwnd;
}
/* Window_Main.c */
#include <windows.h>
#include "window_s.h"
#include "setUpWinProc.h"
#include "registerWindow.c"
#include "createWindow.c"
#include <stdio.h>
int WINAPI WinMain ( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR pCmdLine,
int nCmdShow ) {
WINDOW window = {{}, hInstance};
registerWindow(&window);
CreateWindow_(&window);
ShowWindow(window.hwnd, nCmdShow);
}
This is part of the issue:
int WINAPI WinMain ( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR pCmdLine,
int nCmdShow ) {
WINDOW window = {{}, hInstance};
registerWindow(&window);
CreateWindow_(&window);
ShowWindow(window.hwnd, nCmdShow);
}
What do you think happens after ShowWindow returns and WinMain itself returns? (Hint: the program exits).
Extend your WinMain to pump messages with TranslateMessage+DispatchMessage.
int WINAPI WinMain ( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR pCmdLine,
int nCmdShow ) {
MSG msg;
WINDOW window = {{}, hInstance};
registerWindow(&window);
CreateWindow_(&window);
ShowWindow(window.hwnd, nCmdShow);
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Then your message proc needs to handle WM_CLOSE and WM_PAINT as a minimum and be able to forward to the default window proc for messages it doesn't handle.
LRESULT CALLBACK WindowProc( HWND hwnd,
UINT uMsg, WPARAM wParam,
LPARAM lParam) {
switch (uMsg) {
case WM_PAINT: {
PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
break;
}
case WM_DESTROY: {
PostQuitMessage(0);
break;
}
default: {
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
return 0;
}
Your RegisterClass call looks suspicous as well. Let's initialize like this:
WNDCLASSEXW wcex = {0};
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WindowProc;
wcex.hInstance = hInstance;
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszClassName = szWindowClass;
RegisterClassExW(&wcex);
If you have Visual Studio (and edition), there's a default Win32 application that generates the most minimal of stub applications that does exactly what you are trying to achieve. Look for the C++ project for "Default Windows Application" or similar.
The core issue is here:
LRESULT CALLBACK WindowProc( HWND hwnd,
UINT uMsg, WPARAM wParam,
LPARAM lParam) { }
As the compiler warned, this function needs to return a value (but isn't). The behavior of registering this as a window procedure is undefined. It will probably fail to create a window; CreateWindowEx() calls into the window procedure with WM_NCCREATE and WM_CREATE messages before it returns. Either message handler must return a particular value to continue window creation.
There's a similar issue with the window class name: It's using a local variable, but passes a pointer to it out. As registerWindow() returns, CLASS_NAME is gone. Class registration succeeds, but when it comes time to create the window, the call to CreateWindowEx() uses garbage as the window class name.
The first fix is thus:
LRESULT CALLBACK WindowProc( HWND hwnd,
UINT uMsg, WPARAM wParam,
LPARAM lParam) {
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
and
void registerWindow(WINDOW *window) {
static const char CLASS_NAME[] = "Window Class Name";
// ...
}
That solves the window creation, though you won't see the window for long (if at all) because the code immediately falls out of WinMain() (which also needs to return a value), causing the process to terminate.
To fix that, you'll have to dispatch messages on the thread that created the window. The following will address both of these issues:
int WINAPI WinMain ( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR pCmdLine,
int nCmdShow ) {
WINDOW window = {{}, hInstance};
registerWindow(&window);
CreateWindow_(&window);
ShowWindow(window.hwnd, nCmdShow);
MSG msg = {0};
while (GetMessage(&msg, NULL, 0, 0)) {
DispatchMessage(&msg);
}
return msg.wParam;
}
That's the bare minimum required (unless you count MessageBox() as "getting a window to open"). But it won't allow you to exit the application. To add that functionality, you'll want to add a WM_DESTROY handler that will signal the message loop to end, like so:
LRESULT CALLBACK WindowProc( HWND hwnd,
UINT uMsg, WPARAM wParam,
LPARAM lParam) {
switch (uMsg) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
In one of my projects, I need to create a window in a non-main thread. I have never done that so I don't much experience on that.
According to the MSDN documentation and the SO question, I should be able to create a window in other thread, but I cannot succeed. Even though, in thread start routine, I register a window class, create a window and provide a message loop, the thread starts and exits immediately. In addition, I cannot debug the thread start routine so I cannot hit the break points inside it.
Is there something I am missing? I hope I don't miss anything silly.
Please consider the following demo. Thank you for taking your time.
#include <Windows.h>
#include <tchar.h>
HANDLE hThread;
DWORD WINAPI OtherUIThreadFunc(LPVOID args);
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
HWND m_hwnd;
MSG msg;
WNDCLASSEX m_wcx;
const int MESSAGE_PROCESSED = 0;
const TCHAR* m_szClassName = _T("DemoWndCls");
const TCHAR* m_szWindowTitle = _T("Demo Window");
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int nCmdShow)
{
hThread = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)OtherUIThreadFunc, hInstance, 0, NULL);
/*MSG msg;
ZeroMemory(&m_wcx, sizeof(m_wcx));
m_wcx.cbSize = sizeof(m_wcx);
m_wcx.style = CS_VREDRAW | CS_HREDRAW;
m_wcx.hInstance = hInstance;
m_wcx.lpszClassName = m_szClassName;
m_wcx.lpfnWndProc = WndProc;
m_wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
m_wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
m_wcx.hbrBackground = (HBRUSH)COLOR_WINDOW;
if (!RegisterClassEx(&m_wcx))
return false;
m_hwnd = CreateWindowEx(0, m_wcx.lpszClassName, m_szWindowTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 480, 360, NULL, NULL, hInstance, NULL);
if (!m_hwnd)
return false;
ShowWindow(m_hwnd, SW_NORMAL);
UpdateWindow(m_hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;*/
}
DWORD WINAPI OtherUIThreadFunc(LPVOID args)
{
HINSTANCE hInstance = (HINSTANCE)args;
ZeroMemory(&m_wcx, sizeof(m_wcx));
m_wcx.cbSize = sizeof(m_wcx);
m_wcx.style = CS_VREDRAW | CS_HREDRAW;
m_wcx.hInstance = hInstance;
m_wcx.lpszClassName = m_szClassName;
m_wcx.lpfnWndProc = WndProc;
m_wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
m_wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
m_wcx.hbrBackground = (HBRUSH)COLOR_WINDOW;
if (!RegisterClassEx(&m_wcx))
return false;
m_hwnd = CreateWindowEx(0, m_wcx.lpszClassName, m_szWindowTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 480, 360, NULL, NULL, hInstance, NULL);
if (!m_hwnd)
return false;
ShowWindow(m_hwnd, SW_NORMAL);
UpdateWindow(m_hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
return MESSAGE_PROCESSED;
case WM_DESTROY:
PostQuitMessage(0);
return MESSAGE_PROCESSED;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
Window creation succeeds (in theory, anyway). The issue is that the primary thread moves one to return, which causes the runtime to terminate the process.
To solve the issue you will have to keep the primary thread alive. A call to WaitForSingleObject, or a message loop are possible options.
This is mostly a result of following the conventions of C and C++. In either case returning from the main function is equivalent to calling the exit() function. This explains why returning from the primary thread tears down the entire process.
Bonus reading: If you return from the main thread, does the process exit?
I'm having an issue with my Windows application where upon closing it from the taskbar or via hotkey it will occasionally hang. I'm wondering how to gracefully exit the following program:
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK OwnedWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static HWND mainHwnd;
static HWND ownedHwnd;
void create_windows()
{
HMODULE thisMod = GetModuleHandleA(NULL);
WNDCLASSA wc;
wc.style = CS_VREDRAW | CS_HREDRAW;
wc.lpfnWndProc = MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = thisMod;
wc.hIcon = 0;
wc.hCursor = 0;
wc.hbrBackground = 0;
wc.lpszMenuName = NULL;
wc.lpszClassName = "MAINWIN";
RegisterClassA(&wc);
wc.lpfnWndProc = OwnedWndProc;
wc.lpszClassName = "OWNEDWIN";
RegisterClassA(&wc);
mainHwnd = CreateWindowExA(WS_EX_TOPMOST, "MAINWIN", "MAINWIN", WS_POPUP, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), 0, 0, thisMod, NULL);
ShowWindow(mainHwnd, SW_SHOWNORMAL);
ownedHwnd = CreateWindowExA(WS_EX_LAYERED | WS_EX_TOPMOST, "OWNEDWIN", "OWNEDWIN", WS_POPUP, 0, 0, 200, 200, mainHwnd, 0, thisMod, NULL);
ShowWindow(ownedHwnd, SW_SHOWNORMAL);
}
int main(int argc, char **argv)
{
if (!RegisterHotKey(NULL, 1, MOD_NOREPEAT, VK_ESCAPE)) {
return 0;
}
create_windows();
BOOL bRet;
MSG msg;
while((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
if (bRet == -1) {
/* I'm never reached */
} else if (msg.message == WM_HOTKEY) {
UnregisterHotKey(NULL, 1);
PostMessageA(mainHwnd, WM_CLOSE, 0, 0);
} else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
/* Do a bit of cleanup */
return 0;
}
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static BOOL condition = FALSE;
switch (uMsg) {
case WM_CREATE:
SetTimer(hwnd, 1, 20, NULL);
return 0;
case WM_TIMER:
if (condition) {
KillTimer(hwnd, 1);
PostMessageA(ownedHwnd, WM_CLOSE, 0, 0);
} else {
/* Do processing here on both windows. The condition variable is
updated in here after the program does its thing. */
}
return 0;
case WM_CLOSE:
DestroyWindow(hwnd);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProcA(hwnd, uMsg, wParam, lParam);
}
LRESULT CALLBACK OwnedWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
/* Letting DefWindowProcA handle everything since I don't need this window to
do anything but close afterwards. */
return DefWindowProcA(hwnd, uMsg, wParam, lParam);
}
When it does hang, it always seems to occur after the timer has already been disabled and the owned window has been closed. Never before. Whether in console mode or windows mode its always the same, always after those two things happen and I try to close the window.
With printf statements (because I'm not entirely sure how to debug this) I've noticed that when it freezes WM_CLOSE and subsequently WM_DESTROY are never reached in MainWndProc, as if it's stuck somewhere deep in GetMessage or DispatchMessage, or my message loop, I'm not doing anything fancy in this program so I have no clue. When I manage to make this happen in the debugger it ends up still running but I'm not able to pause it and step to see where where it is executing.
Strangely, though not anymore I've observed, when I would close it in console mode the window would disappear but the process would continue to run in the background until the cmd window from which I launched the program received keyboard input or closes. Conversely in windows mode the same would happen but there'd be no cmd window, instead having to end it from the task manager.
I've never had any trouble with simple Windows GUI applications where only one window is needed. It's only when there are more that I run into this problem of it never fully closing and not knowing how to gracefully exit.
Welp it turns out using WinMain, instead of main, and not specifying it as the entry point (thus the C run-time library is initialized correctly) solved it. And that's all. I still cannot fully wrap my head around it.
Before I discovered this I noticed in the debugger that when the program got out of the message loop and exited, there were a number of threads still running. What's odd is I never created any threads...
I don't know what led me to try WinMain unfortunately as I'd been wildly experimenting with different configuration at that point in console and windows mode until I arrived at the one that worked.
WndProc is the window procedure of the main window. ChildProc is the window procedure of the child window. ChildProc is not receiving WM_DESTROY. What am I doing wrong?
EDIT: If I remove the WS_CHILD window style from hChild = CreateWindowExW(...); so it's hChild = CreateWindowExW(..., WS_VISIBLE, ...); I do get WM_DESTROY in ChildProc.
Also, I'm using Windows 10 and Visual Studio 2008
#include <windows.h>
HINSTANCE g_hInst;
LRESULT CALLBACK ChildProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_PAINT:
{
HDC hdc;
PAINTSTRUCT ps;
hdc = BeginPaint(hwnd, &ps);
if(hdc)
{
RECT rc;
GetClientRect(hwnd, &rc);
SetBkMode(hdc, TRANSPARENT);
FillRect(hdc, &rc, GetSysColorBrush(COLOR_GRAYTEXT));
TextOut(hdc, 0, 0, TEXT("Child"), 5);
EndPaint(hwnd, &ps);
}
}
break;
case WM_DESTROY:
MessageBoxW(0, L"Child WM_DESTROY", 0, MB_OK);
break;
default:
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HWND hChild;
switch(msg)
{
case WM_CREATE:
{
WNDCLASSEXW wc;
SecureZeroMemory(&wc, sizeof(WNDCLASSEXW));
wc.cbSize = sizeof(WNDCLASSEXW);
wc.hCursor = LoadCursorW(0, IDC_ARROW);
wc.hInstance = g_hInst;
wc.lpfnWndProc = ChildProc;
wc.lpszClassName = L"Childclass////";
if(!RegisterClassExW(&wc)) return -1;
hChild = CreateWindowExW(0, L"Childclass////", 0, WS_VISIBLE | WS_CHILD,
0, 0, 200, 100, hwnd, 0, g_hInst, 0);
if(!hChild) return -1;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEXW wc;
HWND hwnd;
MSG msg;
SecureZeroMemory(&wc, sizeof(WNDCLASSEXW));
wc.cbSize = sizeof(WNDCLASSEXW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.hCursor = LoadCursorW(0, IDC_ARROW);
wc.hIcon = LoadIconW(0, IDI_APPLICATION);
wc.hInstance = hInstance;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = L"Mainclass";
if(!RegisterClassExW(&wc)) return 0;
g_hInst = hInstance;
hwnd = CreateWindowExW(0, L"Mainclass", L"Main window", WS_OVERLAPPEDWINDOW, 240, 240, 400, 200, 0, 0, hInstance, 0);
if(!hwnd) return 0;
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while(GetMessageW(&msg, 0, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return (int)msg.wParam;
}
when you call DestroyWindow (assume with valid window handle) - all child windows of course will be destroyed. and all child windows of course received WM_DESTROY
ChildProc is not receiving WM_DESTROY.
this is false. i absolute sure it receive it.
What am I doing wrong?
debug diagnostic and call PostQuitMessage from wrong place.
you decide that ChildProc is "not receiving" WM_DESTROY only because you not view message box. but it will be just closed, even before shown, if you call PostQuitMessage(0); before it.
when a window is being destroyed WM_DESTROY is sent first to the owned windows (if any), then to window being destroyed and finally to the child windows (if any).
so in case you use child window - first parent window received WM_DESTROY and you call PostQuitMessage then child window call MessageBox which just returned without show due previous PostQuitMessage call.
if you use owned window - it receive WM_DESTROY first and show MessageBox normal. and only after you close it parent window receive WM_DESTROY finally and you call PostQuitMessage
for fix this, at first need call PostQuitMessage from WM_NCDESTROY - the parent window receive this message after all owned and child windows.
at second the MessageBox not the best for debug diagnostic. much better use DbgPrint, OutputDebugString or breakpoints in debugger
thank #RemyLebeau for link to Raymond Chen blog - why MessageBox() does not show anything if PostQuitMessage() was already called beforehand:
The other important thing about modality is that a WM_QUIT message
always breaks the modal loop.
So, if PostQuitMessage() is called before MessageBox(), the latter will receive the WM_QUIT message, cancel its UI, re-post WM_QUIT, and exit.
I'm trying to write a callback for my timer. I defined the TimerProc like this:
void CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
{
//body of callback
}
and then the SetTimer defined like this:
myTimer = SetTimer(NULL,Timer_ID,30000,TimerProc);
my problem is that the callback never being called once the time elpassed (30 sec).
thank's for help.
SetTimer works by sending a WM_TIMER message to the default window procedure. Hence, as the MSDN states:
When you specify a TimerProc callback function, the default window procedure calls the callback function when it processes WM_TIMER. Therefore, you need to dispatch messages in the calling thread, even when you use TimerProc instead of processing WM_TIMER.
So make sure that you have a Message Loop running.
Quick test code. Works fine for me.
#include <windows.h>
static const TCHAR gc_szClassName[] = TEXT("Test");
static const TCHAR gc_szWindowTitle[] = TEXT("Test");
#define IDT_TIMER 0x100
VOID CALLBACK TimerProc(HWND hWnd, UINT uMessage, UINT_PTR uEventId, DWORD dwTime)
{
// display a message box to see the results of our beautiful program
MessageBox(hWnd, TEXT("This should pop up every 10 seconds.."), TEXT("Yay!"), MB_OK | MB_ICONINFORMATION);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
{
switch (uMessage)
{
case WM_CREATE:
// run every 10 seconds
SetTimer(hWnd, IDT_TIMER, 10000, TimerPRoc);
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
KillTimer(hWnd, IDT_TIMER);
PostQuitMessage(EXIT_SUCCESS);
break;
}
return DefWindowProc(hWnd, uMessage, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCommandLine, int nShowCommand)
{
// define variables
HWND hWnd;
WNDCLASS wc;
MSG msg;
// unused parameters
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpszCommandLine);
UNREFERENCED_PARAMETER(nShowCommand);
// initialize WNDCLASS structure
ZeroMemory(&wc, sizeof(wc));
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.lpszClassName = gc_szClassName;
// attempt to register the class
if (RegisterClass(&wc) != 0)
{
// attempt to create the window
hWnd = CreateWindow(gc_szClassName, gc_szWindowTitle, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, hInstance, NULL);
if (hWnd != NULL)
{
// retrieve messages
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// use the return-code from the window
return (int)msg.wParam;
}
}
return EXIT_FAILURE;
}