TimerProc in c isn't working? - c

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;
}

Related

What is the bare minimum I need to write in Win32 to get a Window to open?

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);
}
}

Cannot Create Window-based Application in Non-main Thread

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?

The Difference between to usages of SetWindowsHookEx

First: I'm using Visual Studio 2010 on Windows XP - 32 Bit.
Right now I'm trying to write a DLL which will enable another application to work with low level keyboard hooks.
Even though I got it to work - I now want to understand why.
The non-working code:
#include <Windows.h>
#include <stdio.h>
static HINSTANCE hinst;
static HHOOK kbdHook = NULL;
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
printf(":"); fflush(stdout);
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
hinst = hinstDLL;
CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
kbdHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, hinst, 0);
break;
case DLL_PROCESS_DETACH:
UnhookWindowsHookEx(kbdHook);
break;
default:
break;
}
return TRUE;
}
The working code:
#include <Windows.h>
#include <stdio.h>
static HINSTANCE hinst;
static HHOOK kbdHook = NULL;
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
printf(":"); fflush(stdout);
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
MSG msg;
kbdHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), 0);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
hinst = hinstDLL;
CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
break;
case DLL_PROCESS_DETACH:
UnhookWindowsHookEx(kbdHook);
break;
default:
break;
}
return TRUE;
}
The only difference is that I moved the SetWindowsHookEx-call from DllMain to ThreadProc.
The question: Why does this make all the difference?
This is all explained in the documentation for LowLevelKeyboardProc callback function:
This hook is called in the context of the thread that installed it. The call is made by sending a message to the thread that installed the hook. Therefore, the thread that installed the hook must have a message loop.
Your non-working code installs the hook on a thread, that doesn't run a message loop.

Is possible run window application without message loop

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).

Why doesn't the window set cursor correctly?

As MSDN describes:
When the mouse moves over a window, the window receives a WM_SETCURSOR message (unless another window has captured the mouse).
If the application passes WM_SETCURSOR to DefWindowProc, the DefWindowProc function uses the following algorithm to set the cursor image:
If the window has a parent, forward the WM_SETCURSOR message to the parent to handle.
Otherwise, if the window has a class cursor, set the cursor to the class cursor.
If there is no class cursor, set the cursor to the arrow cursor.
And here's my source code:
#include <tchar.h>
#include <Windows.h>
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInsTance, LPTSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wcex = { 0 };
HWND hWnd;
BOOL ret;
MSG msg;
wcex.cbSize = sizeof(wcex);
wcex.lpfnWndProc = WndProc;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
// wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.lpszClassName = TEXT("MainWindow");
wcex.hIconSm = wcex.hIcon;
RegisterClassEx(&wcex);
hWnd = CreateWindow(wcex.lpszClassName, TEXT("Test"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_DESKTOP, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while (ret = GetMessage(&msg, NULL, 0, 0))
{
if (ret == -1)
{
return EXIT_FAILURE;
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(EXIT_SUCCESS);
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
When I move my cursor quickly over the window, the cursor doesn't change to an arrow, it become a resize arrow; if I set wcex.hCursor to LoadCursor(NULL, IDC_ARROW), everything will be all right. My question is: why doesn't my code work as MSDN says?
I mean, if I don't set wcex.hCursor, and I don't handle the WM_SETCURSOR message, the DefWindowProc should "set the cursor to the arrow cursor", but it seems it doesn't. Why is that?
See description of the hCursor member of the WNDCLASSEX:
A handle to the class cursor. This member must be a handle to a cursor
resource. If this member is NULL, an application must explicitly set
the cursor shape whenever the mouse moves into the application's
window.
WNDCLASSEX structure

Resources