Why the mouse cursor becomes "Busy..." whenever I run a simple "Hello World!" Win32 application?
Question
Thursday, May 5, 2011 5:03 PM
Whenever I build/compile my simple Win32 Hello World application and execute it, I see my mouse cursor change its sprite to the "Busy..." sprite animation. (In Windows XP, it's the hourglass animation, unless you have different cursors installed. In Windows Vista/7, it's the round, blue, ring that flashes in a specific rotation.)
I have two versions of the Message Loop that have exactly the same behavior described above. This only occurs if I use PeekMessage().
If I use GetMessage(), my program would just stall there; It hangs quite a while... So, I'm not going to use GetMessage(). And this has something to do with using Microsoft's most famous API.
Anyway, on to the codes. Here's one of it. The IF method:
MSG msg_struct;
ZeroMemory(&msg_struct, sizeof(MSG));
while (msg_struct.message != WM_QUIT)
{
if (PeekMessage(&msg_struct, NULL, NULL, NULL, PM_REMOVE))
{
TranslateMessage(&msg_struct);
DispatchMessage(&msg_struct);
}
}
And this, the WHILE method:
MSG msg_struct;
ZeroMemory(&msg_struct, sizeof(MSG));
while (msg_struct.message != WM_QUIT)
{
while (PeekMessage(&msg_struct, NULL, NULL, NULL, PM_REMOVE))
{
TranslateMessage(&msg_struct);
DispatchMessage(&msg_struct);
}
}
And yeah, that's just about it.
So I'm looking forward to a solution that stops my mouse cursor's "Busy..." animation, or stop making my program hang the mouse animation until it quits in Visual Studio 2010. Any helps are appreciated.
Thanks in advance.
All replies (16)
Friday, May 13, 2011 3:47 AM âś…Answered
I finally found the solution.
It was the windows class structure, wc.hCursor at fault.
wc.hCursor = LoadCursor(hInstance, IDC_ARROW);
It should have been
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
Because it wasn't suppose to tell the application to use its own cursor, which wasn't defined in the first place. Thus, it defaults to the "Busy..." cursor, because it couldn't find any cursors to load.
Thursday, May 5, 2011 5:26 PM
Why not to use simple:
while (GetMessage(&msg, NULL, NULL, NULL))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
?
Nikita Leontiev
Thursday, May 5, 2011 5:34 PM
I'm using DirectX. Also, it hangs the mouse cursor seriously when combined with DirectX usage.
Try this:
1. Make a simple Win32 Hello World program.
2. Just build/compile. Then debug.
3. Do not move the mouse. What cursor animation do you see?
4. Now, copy/paste the code I posted and implement it into your Win32 program.
5. Debug it again. Again, don't move the mouse. Now, what cursor animation do you see?
What is the problem?
Thursday, May 5, 2011 8:42 PM
Well, when using a PeekMessage loop with both if and while on the PeekMessage I see the nice pointer icon.
The thing is, the busy cursor is displayed if the message pump is taking a while to process the messages that it has. So what you need to do is not look at the PeekMessage loop but at the Window procedure itself.
This is a signature
Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.
Visit my (not very good) blog at
http://ccprogramming.wordpress.com/
Thursday, May 5, 2011 8:54 PM
The problem, simply, is that Windows determines that the application is "busy loading" and automatically displays a wait cursor, until it detects that the applications message loop has become idle.
As your while loops are structured, PeekMessage does not wait if there are no messages, so it always immediately returns, even when the app should be idle. The while loop immediately calls PeekMessage again. This means that, as far as windows can tell, the app never reaches the idle state that indicates loading has finished and the app is ready to receive user input - hence the permanent busy cursor.
Thursday, May 5, 2011 10:34 PM
The thing is PeekMessage works like GetMessage in that it takes the application out of the loading to the input idle state unless you tell it not to do that. You have to explicitly pass the PM_NOYIELD flag to PeekMessage in the last parameter to stop it from taking the process out of the busy status.
This is a signature
Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.
Visit my (not very good) blog at
http://ccprogramming.wordpress.com/
Friday, May 6, 2011 5:24 AM
Is it possible to change the last parameter of the PeekMessage() to PM_NOYIELD and then back to PM_REMOVE?
Or there is a more efficient way of using PM_REMOVE and making the program detects that it is idle, and you can stop Peeking now...?
Friday, May 6, 2011 7:40 AM
The mechanisim that windows uses to determine when an app is finished loading is, afaik, a somewhat undocumented heuristic process. Experimentation would be required to see what sequence of events is needed.
Or, rather, use MSGWaitForMultipleObjects instead of either PeekMessage, or GetMessage, as you can both provide a timeout, and/or get it to wait on any kind of kernel handle (waitable timers) in addition to allowing you to process windows messages as they arrive. This can result in a message loop that can still achieve a high fps, but minimize wasteful cpu cycles spent spinning.
Friday, May 6, 2011 12:10 PM
Since I learned Win32 programming from online resources, I have never seen how MSGWaitForMultipleObjects() is used in practice. Nor have ever seen how to make a program idle when it's done rendering something on the screen.
Would loved to have someone teach me about this. Thanks in advance.
Going back and forth between MSDN and Gamedev has ousted my energy. :(
Friday, May 6, 2011 12:41 PM
What is your goal? I can't understand what you're trying to do. Maybe I'm only one here who cannot understand.Nikita Leontiev
Friday, May 6, 2011 1:02 PM
This is a quick and dirty game loop using MsgWait. It has a number of things wrong with it, but it should serve to give you some ideas.
LONG idealFrame=33; // ~30fps
DWORD dwLastFrame = GetTickCount();
while(isRunning){
LONG timeTillNextFrame = idealFrame - (GetTickCount() - dwLastFrame);
if(timeTillNextFrame<0)
timeTillNextFrame=0;
DWORD ret = MsgWaitForMultipleObjects(0,NULL,FALSE,timeTillNextFrame,QS_ALLINPUT);
DWORD dwNow = GetTickCount();
if(ret==WAIT_OBJECT_0+0){
while(PeekMessage(&msg,0,0,0,PM_REMOVE)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else if(ret == WAIT_TIMEOUT){
int interval = dwNow-dwLastFrame;
DoGameLoop(interval); // do the tick
UpdateWindow(gameWindow); // repaint
dwLastFrame = dwNow;
}
else
break; // MsgWaitFor failed???
}
Friday, May 6, 2011 1:20 PM
What is your goal? I can't understand what you're trying to do. Maybe I'm only one here who cannot understand. Nikita Leontiev
I'm trying to get rid of the "Busy..." mouse cursor animation. (Which means the program isn't idle when just compile and run my program, which is TOTALLY not good for game programming.)
By the way, did you do the steps I provided above? Step 1 through Step 5 tells you why it happens, and that should've not happen.
This is a quick and dirty game loop using MsgWait. It has a number of things wrong with it, but it should serve to give you some ideas.
LONG idealFrame=33; // ~30fps DWORD dwLastFrame = GetTickCount(); while(isRunning){ LONG timeTillNextFrame = idealFrame - (GetTickCount() - dwLastFrame); if(timeTillNextFrame<0) timeTillNextFrame=0; DWORD ret = MsgWaitForMultipleObjects(0,NULL,FALSE,timeTillNextFrame,QS_ALLINPUT); DWORD dwNow = GetTickCount(); if(ret==WAIT_OBJECT_0+0){ while(PeekMessage(&msg,0,0,0,PM_REMOVE)){ TranslateMessage(&msg); DispatchMessage(&msg); } } else if(ret == WAIT_TIMEOUT){ int interval = dwNow-dwLastFrame; DoGameLoop(interval); // do the tick UpdateWindow(gameWindow); // repaint dwLastFrame = dwNow; } else break; // MsgWaitFor failed??? }
Oh wow. I'll try implementing that one, but it's to say, this is way off of the book's subject. If the mouse cursor still remains "Busy...", then I don't know what to do.
Oh why did the editors not put a warning in the books when it tells you the program you're running failed to exit out of "Busy" and not able to fall back to being "Idle"?
Friday, May 6, 2011 2:07 PM
Is it possible to change the last parameter of the PeekMessage() to PM_NOYIELD and then back to PM_REMOVE? Or there is a more efficient way of using PM_REMOVE and making the program detects that it is idle, and you can stop Peeking now...?
The point is that the normal behaviour of PeekMessage is without no yield. This means that when you start using it to retrieve the messages, then it should take the application out of the busy status. You have to go out of your way to call PeekMessage with PM_NOYIELD | PM_REMOVE to stop the application from going idle.
Without making any edits to it, try this sample.
#include <tchar.h>
#include <Windows.h>
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE, LPTSTR cmdline, int showcmd)
{
MSG msg = {0};
HWND wnd;
WNDCLASSEX wcx = {0};
wcx.cbSize = sizeof(WNDCLASSEX);
wcx.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcx.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wcx.hInstance = hInstance;
wcx.lpfnWndProc = MainWndProc;
wcx.lpszClassName = _T("MainWindow");
wcx.style = 0;
if(RegisterClassEx(&wcx) == 0)
{
MessageBox(NULL, _T("Failed to register the window class"), _T("Error"), MB_OK | MB_ICONERROR);
return -1;
}
wnd = CreateWindowEx(0, _T("MainWindow"), _T("Main"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, hInstance, NULL);
if(wnd == NULL)
{
MessageBox(NULL, _T("Failed to create the window class"), _T("Error"), MB_OK | MB_ICONERROR);
return -1;
}
ShowWindow(wnd, showcmd);
UpdateWindow(wnd);
while(msg.message != WM_QUIT)
{
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
//do stuff here
}
return msg.wParam;
};
LRESULT CALLBACK MainWndProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch(msg)
{
case WM_CLOSE:
DestroyWindow(wnd);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_PAINT:
{
HDC hDc;
PAINTSTRUCT ps;
hDc = BeginPaint(wnd, &ps);
TextOut(hDc, 40, 40, _T("Hello"), 5);
EndPaint(wnd, &ps);
}
default:
return DefWindowProc(wnd, msg, wparam, lparam);
}
}
That immediately goes into the input idle state for me.
This is a signature
Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.
Visit my (not very good) blog at
http://ccprogramming.wordpress.com/
Friday, May 6, 2011 6:46 PM
I tried that code sample.
Condition: My mouse cursor is placed 1/4 away from the left side of the monitor, 1/4 away from the top side of the monitor. Never leaving the Client Area of my program. From program startup until I must click on the red Close button.
I'm using Windows 7. If busy, it will show a blue ring flashing around and around. If it's not busy, it will be showing a pointing arrow. By checking, I meant "Function() != 0".
If PeekMessage() with PM_REMOVE flag only, without checking, it creates a busy program loop.
If PeekMessage() with PM_NOYIELD flag only, without checking, it creates a busy and non-responding program loop.
If PeekMessage() with PM_REMOVE and PM_NOYIELD flags, without checking, it creates a busy program loop.
If PeekMessage() with PM_NOYIELD with checking, it makes a busy and non-responding program loop.
If PeekMessage() with PM_REMOVE with checking, it makes a busy program loop (exitable).
If PeekMessage() with PM_REMOVE | PM_NOYIELD flags with checking, it creates a busy program loop.
If GetMessage(), without checking, it creates a busy program loop.
If GetMessage() with checking, it still creates a busy program loop.
For all above, once the mouse leaves the Client Area of the program, it return to normal. No matter what. (Which is not what I wanted...)
I see video games in windowed mode, take notice of the idle/busy problem, and they made it so that it's not being busy. What I'm now confused, is how do you go into a loop I made, and after finishing it, idles the program? Since I'm making a game loop call method in my message loop, I'm totally lost. When their program started to run, the mouse cursor would not be playing the "Busy..." animation at all.
In short, that sample above proves that it's not GetMessage() or PeekMessage() that's being the cause, and it's not even the Windows Procedure CALLBACK function, rather it's my DirectX game loop that's clearly troublesome. Now, I need to stall it, or "idle" it, and stop hogging my CPUs... Hm...
Basically, the main problem is only half done. but I like it more than itself being empty. :D
Friday, May 6, 2011 7:13 PM
Are you taking a long time in the directx loop? Are you directly or indirectly sending messages to the window? The idle state is reached the first tme the message loop calls GetMessage/PeekMessage and doesn't find any messages in the message queue.
Do you maybe have a message filter on you main loop which could be getting in the way?
This is a signature
Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.
Visit my (not very good) blog at
http://ccprogramming.wordpress.com/
Saturday, May 7, 2011 5:09 AM
Are you taking a long time in the directx loop? Are you directly or indirectly sending messages to the window? The idle state is reached the first tme the message loop calls GetMessage/PeekMessage and doesn't find any messages in the message queue.
Do you maybe have a message filter on you main loop which could be getting in the way?
This is a signature
Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.
Visit my (not very good) blog at
http://ccprogramming.wordpress.com/
- No. My DirectX loop only draws a sprite onto the screen, then there's nothing else left to be done.
- I'm not sure how it can directly or indirectly send messages to the window. Other than PostQuitMessage(), I have not been using PostMessage() at all.
- Now I know how "idle" comes to play. So, my next plan is to try and make sure the message queue is really empty, so then I can be idling, which is what I should be doing?
- If the message filter meant LRESULT CALLBACK WindowProc(), yes. All it tries to filter is WM_DESTROY, WM_CLOSE, and nothing else. Should I bring the DefWindowProc() into the switch...case function? If the message filter meant something else, then no. There isn't any message filters in my game loop other than WindowProc(). And, according to the book "Beginning Games Programming" by Jonathan S. Harbour, he did not add any codes in there that adds a new message filter. I'm on Chapter 6 in DirectX Programming, yet I couldn't find anything that leads my program to jump out and go to the idle state.
Do you have the book? If yes, do you suppose the book's code is supposed to not idle my program?