Breaking a while loop in a called Function - c++

On clicking the start button the function RunB() executes the while loop . I need to break the while loop execution midway using the Stop Button .
switch (msg)
{
case WM_CREATE:
CreateWindow(TEXT("button"), TEXT("Browser"),
WS_VISIBLE | WS_CHILD,
30, 100, 80, 25,
hwnd, (HMENU)1, NULL, NULL);
CreateWindow(TEXT("button"), TEXT("Stop"),
WS_VISIBLE | WS_CHILD,
30, 200, 80, 25,
hwnd, (HMENU)2, NULL, NULL);
break;
case WM_COMMAND:
if (LOWORD(wParam) == 1) {
Obj.RunB();
}
break;
if (LOWORD(wParam) == 2) {
//Code to break the while loop
}
break;
Code for the Called Function RunB:
void RunB(){
while(n<15){
//Some statements here:
}
How do I break the while loop using the Stop Button ?

The event driven action (i.e. pressing a button), shouldn't engage a looping or business logic.... Otherwise the whole windows will be halt until it gets the synchronous response.

If you find you have some modal action that is going to take a long time to complete and you absolutely can't break it up, then you need to periodically process messages from within your modal action.
For example:
while(n<15){
DoAPieceOfWork(n);
FlushPendingMessages();
}
And FlushPendingMessages would be implemented something like:
void FlushPendingMessages(){
MSG msg;
while(PeekMessage(&msg,0,0,0,PM_REMOVE)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
This will keep your application mostly responsive. Normaly you would also display a modeless dialog at the same time, so that people know your application is busy and cannot be interacted with.
To be more correct, before calling TranslateMessage/DispatchMessage you must also check for WM_QUIT and repost it to terminate your app, and you can also explicitly check for WM_APP+x messages- using code something like this:
#define WM_APP_QUITLOOP (WM_APP+1)
// use this from anywhere to tell your processing loop to quit
PostMessage(NULL,WM_APP_QUITLOOP,0,0L);
BOOL FlushPendingMessages(){
MSG msg;
while(PeekMessage(&msg,0,0,0,PM_REMOVE)){
switch(msg.message){
case WM_APP_QUITLOOP:
return FALSE;
case WM_QUIT:
PostQuitMessage(msg.wParam);
return FALSE;
default:
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return TRUE;
}
Your processing loop would need to check the return value from FlushPendingMessages and abort if its FALSE of course.
Edit: as per #IInspectable's comment.

Related

MessageBox() returning 0 when called from Win32 button press

I'm barely a week into Win32 GUI programming, so I'm confident/hopeful this is something simple. For your consideration, I've provided a sample of my code below.
As a quick brief, my application watches for another application to be open so that I can modify that application's memory. I've placed this initial check at the top of my UI looper as follows such that it will only run once (in which case the user can only cancel and the app closes, or execution resumes past the if statement with hWndApp having a value assigned):
if (!hWndApp) {
appCheck();
}
If I start my application and the other application isn't running, appCheck(); fires and the waterfall of execution therefrom acts accordingly: a message box appears (and will keep appearing if the user clicks "Retry") until the other application's window is found. If the user clicks "Cancel," the application exits and all is well. If they click "Retry" once the other application is running, then my application will finish painting to the screen and execution is normal.
The funny business starts the next time I call appCheck(); (which happens when one of either two buttons is clicked) if the other application has been opened, then closed.
While debugging (via Visual Studio 2017), the variable I assign the MessageBox() call to equals 0 when the other application has been opened, then closed, then the following:
Push button to call appCheck();
getProcessHandleAndPID(); is then called within the if statement because the window can't be found
AppCheckMessageBox(); is then called within the while loop because the window can't be found
The debugger then points to the first line inside of AppCheckMessageBox();, which is the entire int msgboxID = MessageBox(); bit
Pressing F11 (Step Into), no window shows and the application exists after the default choice in the switch statement is triggered since the value of msgboxID is 0 (indicating the MessageBox() call failed, so I tried calling GetLastError() before exit(EXIT_FAILURE), but to no avail).
I'm not sure where my error lies, but I've sought many solutions--none of which have panned out. Finally, if you see any variables below that look misnamed or undeclared, it's solely due to my modification of the code for this post to try to generalize/ shorten it. I may have left out some global variable declarations, etc.
Thank you for any help/guidance you can provide! I'm at my wit's end with this right now...lol.
//--------------------------------------------------
// Function to get process handle and PID of app /
//------------------------------------------------
void getProcessHandleAndPID()
{
hWndApp = FindWindow(NULL, _T("NameOfApplication"));
while (!hWndApp) {
AppCheckMessageBox();
}
//Much more code here
}
//---------------------------------
// Function to show message box /
//-------------------------------
int AppCheckMessageBox()
{
int msgboxID = MessageBox(
NULL, //I tried making this hWndApp as well, but no difference
(LPCWSTR)L"Cancel to exit or start the app and click Retry.",
(LPCWSTR)L"Application Not Found!",
MB_ICONSTOP | MB_RETRYCANCEL | MB_SYSTEMMODAL | MB_SETFOREGROUND
);
switch (msgboxID)
{
case IDCANCEL:
exit(EXIT_FAILURE);
case IDRETRY:
getProcessHandleAndPID();
break;
default:
//GetLastError();
exit(EXIT_FAILURE);
}
return msgboxID;
}
//------------------------------------------------
// Function to check if application is running /
//----------------------------------------------
void appCheck() {
if (!FindWindow(NULL, _T("NameOfApplication"))) {
getProcessHandleAndPID();
}
}
//--------------------------------------------------
// Function to get process handle and PID of app /
//------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (!hWndApp) {
appCheck();
}
switch (message)
{
case WM_PAINT:
//Code here
break;
case WM_CREATE:
//Code here
break;
case WM_COMMAND:
switch (HIWORD(wParam))
{
case BN_CLICKED:
if (LOWORD(wParam) == BTN_ENABLE) {
appCheck();
//Do stuff with button press
}
if (LOWORD(wParam) == BTN_DISABLE) {
appCheck();
//Do stuff with button press
}
break;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
Not really an answer, but too long for comments:
This isn't your real code. Many things are missing, there are mismatched braces which would prevent compilation, etc. Always show your real code if you want help.
As David says, calling appCheck() every time you receive a message is the wrong approach. If you want to call it once after your window opens, do that before entering your message loop.
Your code is needlessly recursive (getProcessHandleAndPID() calls AppCheckMessageBox() which calls getProcessHandleAndPID() which calls...) and will potentially lead to a stack overflow.

C++ CreateWindow: button position gets offset at window maximize

I have a weird problem over here. I created a DLL proxy for Spotify so I can "overlay" a button onto it. Basicially, thats how it works:
DllMain
-> Creates CMain class
-> Creates CToggleButton class
-> Hooks the button onto the Spotify window
It has two methods, one static one which I use for the thread since threads can't call member functions, and one non-static function which gets called by the member function.
With this, I create the thread and pass an instance of the CToggleButton class via lpParam:
CreateThread(0, NULL, WindowThreadStatic, (void*)this, NULL, NULL);
Then, the WindowThreadStatic function:
DWORD WINAPI CToggleButton::WindowThreadStatic(void* lpParam)
{
return ((CToggleButton*)lpParam)->WindowThread();
}
And the main window thread function inside the class:
DWORD CToggleButton::WindowThread()
{
MSG msg;
hButton = CreateWindowA("BUTTON", "Test", (WS_VISIBLE | WS_CHILD), 0, 0, 100, 20, parenthWnd, NULL, hInst, NULL);
bool bQueueRunning = true;
while (bQueueRunning)
{
if (PeekMessage(&msg, parenthWnd, 0, 0, PM_REMOVE))
{
switch (msg.message)
{
case WM_QUIT:
bQueueRunning = false;
break;
case WM_LBUTTONDOWN:
if (msg.hwnd == hButton)
{
MessageBoxA(parenthWnd, "Button!", "Button", MB_OK);
continue;
}
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Sleep(10);
}
return 0;
}
As you can see, this also contains the message loop for the button (I didn't use GetMessage() here because it was very unresponsive so I decided to use PeekMessage() together with a 10ms delay, which works fine.)
Little picture to show how it looks like:
All great, but if I maximize the window, the button disappears. When I minimize and maximize the window a few times, the button can be seen again, but with very weird coordinates (not the original 0,0 I gave him).
So what is my problem here? Why do the coordinates get offset?
Thanks for reading my long post :)

Handling Windows messages so that my application responds correctly

I had an old piece of code that I wrote about 15 years ago to do some file manipulation, which runs through a script to process 1/2 sourcefiles and output to 1/2 outputfiles and I've been trying to write it 'properly' so that it will run under Windows 7/8 as a scheduled task.
I've ported it to Visual Studio 2013 Express, and managed to get it to work (execute and generate the desired results) pretty quickly, processing my text input file, stripping rubbish out of it, and generating a formatted CSV file in about 38 seconds, however it Ghosts, and goes non-responsive until such time as the processing of the file completes, which is okish for user execution, but Windows 7 and 8 don't like running it as a scheduled task, and close it as soon as it ghosts.
I've tried re-writing the large chunk of processing code so that it returns to the main message handling loop after each line of script, and this functions, albeit about ten-twenty times slower (depending on whether I'm using GetMessage or PeekMessage, however I'm still struggling with the application ghosting, despite each line of script only taking a few milliseconds to run.
My Main Window code is currently;
while (msg.message != WM_QUIT)
{
while ((PeekMessage(&msg, NULL, 0, WM_COMMAND - 1, PM_REMOVE) > 0) ||
(PeekMessage(&msg, NULL, WM_COMMAND+1, 0xFFFF, PM_REMOVE) > 0))
// While there are any system messages with a value <> WM_COMMAND,
// Process these first
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) > 0)
// Process one WM_COMMAND message i.e. one of mine.
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
where my WndProc function has a giant case statement that processes all my posted messages to perform one sub-task of my file processing and all the windows system-type responses. I've cut out some of the 'doing stuff' commands, but you'll get the gist
it's a;
until we reach my iteration bit in the scriptfile;
process phase 1
until we finish processing the sourcefile or go round enough iterations;
process phase 2
until we reach the end of the sourcefile
process phase 3
end
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
//////////////////////////////
/* Start of my menu uptions */
//////////////////////////////
case MI_FILE_EXIT:
DestroyWindow(hWnd);
return(0);
case MI_RUN_EXECUTE:
// * Open Necessary Files * //
// * Start Processing ScriptFile * //
phase = 1;
command = 'A';
PostMessage(hWnd, WM_COMMAND, MI_PHASE_1, lParam);
return(0);
case MI_PHASE_1:
nextcommand = ProcessCommand(command);
if (ScriptFileComplete)
{
// We've reached the end of the script - stop processing
PostMessage(hWnd, WM_COMMAND, MI_SCRIPT_COMPLETE, lParam);
break;
}
else if (nextcommand = '<')
{
// prep for start of phase 2
phase = 2;
tiptr = tptr;
command = nextcommand;
PostMessage(hWnd, WM_COMMAND, MI_PHASE_2, lParam);
break;
}
else
{
// process the nextcommand
command = nextcommand;
PostMessage(hWnd, WM_COMMAND, MI_PHASE_1, lParam);
break;
}
return(0);
case MI_PHASE_2:
nextcommand = ProcessCommand(command);
redrawscreen(hWnd);
if (nextcommand == '>')
{
// we're at the end of the iteration
if (UseIterationCount)
{
IterationCount--;
if (IterationCount <= 0)
{
phase = 3;
command = nextcommand;
PostMessage(hWnd, WM_COMMAND, MI_PHASE_3, lParam);
break;
}
}
}
else if (ScriptFileComplete)
{
// We've reached the end of the script - stop processing
PostMessage(hWnd, WM_COMMAND, MI_SCRIPT_COMPLETE, lParam);
break;
}
else if (SourceFileAComplete)
// We've reached the end of the Source File - stop processing
{
PostMessage(hWnd, WM_COMMAND, MI_SCRIPT_COMPLETE, lParam);
break;
}
else // All's normal and we're just processing the next command
{
command = nextcommand;
PostMessage(hWnd, WM_COMMAND, MI_PHASE_2, lParam);
break;
}
return(0);
case MI_PHASE_3:
nextcommand = ProcessCommand(command);
command = nextcommand;
// test to see if we go round phase 3 loop again
if ((!ScriptFileComplete) && (!SourceFileAComplete))
{
PostMessage(hWnd, WM_COMMAND, MI_PHASE_3, lParam);
break;
}
else // we've cleared that and we're at scriptfile EOF
{
PostMessage(hWnd, WM_COMMAND, MI_SCRIPT_COMPLETE, lParam);
break;
}
return(0);
case MI_SCRIPT_COMPLETE:
// We're at the end of the script - close things down.
CloseFiles();
DrawMenuBar(hWnd);
if (AutoExit)
PostMessage(hWnd, WM_QUIT, wParam, lParam);
return(0);
case MI_DO_NOTHING: // blank code for initial entry to main message loop
return(0);
default: // somehow an invalid message was posted
log("invalid message was posted");
return(0);
}
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
redrawscreen(hWnd);
EndPaint(hWnd, &ps);
return(0);
case WM_DESTROY:
PostQuitMessage(0);
return(0);
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return(0);
}
So the idea is that after each call to processCommand (i.e. carry out one line of my script processing), return to the main message handle, respond to any events (like someone moving the window or clicking on the close button), and then process the next line of my script.
I'm clearly missing something (or lots of things) regarding which messages I should be checking and processing on a regular basis, so if anyone can offer suggestions/advice as to;
What messages should I be handling before all others?
How often should my application be checking for system messages?
Am I going about this completely wrong?
e.g. should I be threading the processing code? - the app shouldn't require any user interaction while it's running, but it would be good practise to allow a user to move/resize/quit it, which I was hoping to achieve through posting messages back to WM_COMMAND
Thank you very much for even reading this far. Any and all advice no matter how sharp (if it helps) appreciated.
Richard.
- UPDATE -
Thanks both for the pointers - it's clear that this does warrant threading my slow file access bits of code, so I've re-written to do this, but now I'm just a bit stuck as to where I should do fire off the thread / join afterwards - There's lots of examples where the thread is fired off in the main window and then joined straight afterwards e.g.;
void My_Slow_Task(){
; // Process lots of data
}
int main(){
std::thread t1(My_Slow_Task);
t1.join();
return 0;
}
but as pointed out below doing this in my message handling block just means it sits there like a lemon until the thread finishes, but I need a user to be able to make changes to the outputfiles etc. before they kick off the file manipulation process (it can be automated, but it needs to be able to not be as well), so at the moment, I'm after something like;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
// one of these messages is the menuitem for 'Run_my_big_chunk_of_processing' and sets 'ExecutingScript' to TRUE
// another will be to change the location of the output file or edit the script etc.
if (ExecutingScript == TRUE)
{
ExecutingScript = FALSE;
std::thread t1(Run_my_big_chunk_of_processing);
t1.join();
PostMessage(hWnd, WM_COMMAND, MI_RUN_COMPLETE, lParam);
// to do the close files, tidy up and feed back to the user.
}
}
If anyone's knows how I can handle the request from the user to start the slow process and fire it off, without the GUI having to wait for it to finish before handling other messages, then that'll be it sorted.
- SOLUTION? -
Use an outer control loop for user interaction while the thread isn't running, and an inner one for while it is;
_twinMain()
{
// Initialise Stuff
// Pre-exec message loop
// Outer messagehandling loop
while (!AllDone)
// we're !AllDone on entry, and AllDone when the app gets
// a WM_QUIT or other triggered abort e.g. script failure
{
// Pre/post-exec message loop
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (ExecutingScript)
// this will be set by auto-run in the ini file,
// or manually by a user clicking the menu option
{
std::thread t1(RunThread);
// Exec message loop
while (ExecutingScript)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) > 0)
// There may be no messages, as we could be in auto-run
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
t1.join();
PostMessage(hWnd, WM_COMMAND, MI_RUN_COMPLETE, lParam);
}
}
return (int) msg.wParam;
}
Thanks for all your help
VS2013 has the C++11 <thread> stuff, no need for non-standard libraries. std::aync(std::launch::async) will run a background task, std::future::wait_for allows you to check from the messsage loop whether the operation has finished. Of course, you can also use a old-style PostQuitMessage(WM_APP) from the processing thread. Either way, after the message loops exits, call .join() on the worked thread to clean it up, then exit the main thread.

How to stop a process using a "Stop Button"

I created a simple window with two buttons,
the first one calls a function that lasts a long time,
the second one sets the value of a variable "stop" to TRUE,
that was initially set to FALSE.
My intention is that, by pressing the first button it runs a long process,
that controls if the stop variable is set to TRUE or FALSE for every loop,
if the value is TRUE the function should return, so the process is stopped.
...
static BOOL stop = FALSE; // My variable defined somewhere
...
int longProcess () // My function
{
while(stop == FALSE) {
// do something
}
return 0;
}
...
switch (msg)
{
case WM_CREATE:
{
...
Button1 = CreateWindowEx(0,
TEXT("BUTTON"),
TEXT("Start"),
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
100, 100, 100, 20,
hWnd,
(HMENU)BUTTON_START,
NULL,
NULL);
Button2 = CreateWindowEx(0,
TEXT("BUTTON"),
TEXT("Stop"),
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
200, 200, 100, 20,
hWnd,
(HMENU)BUTTON_STOP,
NULL,
NULL);
...
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case BUTTON_START:
longProcess(); // Starts the process
break;
case BUTTON_STOP:
stop = TRUE; // Should stop the process
break;
}
}
break;
...
}
}
The problem is that when I press the first button the process starts normally,
but when I press the second button in order to stop the process nothing happens,
I noticed that the stop variable is set to TRUE only after the end of the process.
I thought that probably in a problem related to the message queue...
What could be the best solution???
It is correct to call longProcess() there and in that way? (I'am a newbie :) )
Thanks!
You need to run the long process on a separate thread and your approach should work.
This is, instead of just calling longProcess function on Start Button Click, create a thread, and run the long process on it.
What's happening is that your long process is blocking your UI thread, which is responsible for handling UI events. So, Stop Button Click won't be handled until longProcess() finishes.
In Delphi we have Application.ProcessMessages() which basically processes all pending messages and returns. And you can put this line to cycle to make UI more responsive.
With function like that you could do this
while(stop == FALSE) {
// do something
...
ProcessPendingMessages();
}
EDIT:
This applies if you don't want to split code to separate thread - quick'n'dirty workaround
How about using PeekMessage?
int longProcess () // My function
{
while(stop == FALSE)
{
// do something
while (PeekMessage(&msg, hwnd, 0, 0, PM_NOREMOVE))
{
// check for the stop button
if ((msg.message == WM_COMMAND) && (LOWORD(wParam) == BUTTON_STOP))
stop = TRUE;
}
}
}
}
At the very minimum, you'll have to declare your variable with the volatile keyword. But the best way to do it is to use an event. CreateEvent() to initialize it, SetEvent() to signal the stop condition, WaitForSingleObject() with a 0 timeout to test it.
As a variation of AOI Karasu's answer, MFC has CWinThread::PumpMessage().
I use it in worker thread loops to keep them responsive. It works great.

Game loop in Win32 API

I'm creating game mario like in win32 GDI . I've implemented the new loop for game :
PeekMessage(&msg,NULL,0,0,PM_NOREMOVE);
while (msg.message!=WM_QUIT)
{
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else // No message to do
{
gGameMain->GameLoop();
}
}
But my game just running until I press Ctrl + Alt + Del ( mouse cursor is rolling ).
I've always been using something like that:
MSG msg;
while (running){
if (PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
try{
onIdle();
}
catch(std::exception& e){
onError(e.what());
close();
}
}
onIdle is actual game lopp implementation, onError() is an error handler (takes error description as argument), and "running" is either a global bool variable or a class member. Setting "running" to false shuts down the game.
I think this really depends on your context. Windows will only send a WM_QUIT in response to your application calling PostQuitMessage. A common (if not great) solution here is to use a bool to exit the message loop when your program wants to end.
I guess the program may ask user for continue or exit, inside GameLoop function call. On exit Post WM_QUIT message to the window.
PostMessage(hWnd, WM_QUIT, 0, 0 );
hWnd-> The handle of the game window
else make a call to
DestroyWindow(hWnd);
This will send a WM_DESTROY to your window procedure. There you can call
PostQuitMessage(0);