Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to stop a process using a "Stop Button"

Tags:

c++

c

winapi

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!

like image 696
mario Avatar asked Aug 05 '10 12:08

mario


4 Answers

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.

like image 119
Pablo Santa Cruz Avatar answered Oct 30 '22 01:10

Pablo Santa Cruz


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

like image 43
Im0rtality Avatar answered Oct 30 '22 00:10

Im0rtality


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;
            } 
        } 
    }
}
like image 25
Aoi Karasu Avatar answered Oct 29 '22 23:10

Aoi Karasu


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.

like image 3
Hans Passant Avatar answered Oct 29 '22 23:10

Hans Passant