Thread: Stop button doesnt stop a function (using PostMessage)

  1. #1
    Registered User
    Join Date
    Mar 2007
    Posts
    416

    Stop button doesnt stop a function (using PostMessage)

    I'm trying to make a function that will scan through the files that are in a directory of the users choice to search for a certain file. However, the stop button I tried to make doesn't actually work. It's not even possible to do anything while it's searching, including closing the program. I'm using PostMessage() to go through the process one file at a time, hoping that after each file the user could have the option to stop it. Unlike having SendMessage where the user definitely cannot do anything until it's finished. Is there a different route to take so I can stop it in mid search?

    Here is what I think is causing the problem.

    Code:
            //update what the user sees
            SendMessage(hStatus, SB_SETTEXT, 0, (LPARAM)"Scanning..");
    
            //update percentage
            percent = 100*(sofar/total); //get the total percent
    
            itoa(percent,Percent,10);   //change the integer percent to string
    
            strcat(Percent,"%"); //add percent sign to percentage
    
            char OverAll[MAX_PATH] = "Progress: "; //reset the overall progress
    
            strcat(OverAll,Percent); //set overall percentage
    
            SendMessage(hStatus, SB_SETTEXT, 1, (LPARAM)OverAll); //display overall percentage
    
            PostMessage(Hwnd,WM_COMMAND,SCAN,0); //repeat the process
    EDIT: just tried using Sleep(500) and it still has the same problem. I clicked the stop button really fast hoping I'd catch it, but nothing. I also can't regain focus of the window.
    Last edited by scwizzo; 03-06-2008 at 11:15 PM.

  2. #2
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    The problem is that you do not do a message pump while executing your code. This, in turn, causes your window to "freeze."
    To fix this, the usual approach is to execute your event code in a different thread.
    Do you know how threads work or used them?
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  3. #3
    Registered User
    Join Date
    Mar 2007
    Posts
    416
    Honestly I don't know what a thread is, but I have an idea of how they work. I'll get to reading on creating/using them, though.

    EDIT: Ok, I got the thread thing working, but it doesn't repeat the function like I want it to. Is there a way to repeat this without using PostMessage and using threads that I'm not aware of?

    EDIT 2: I got it working the way I'd like now, but want to know if this is a proper way to do it. My code goes something like this...

    Code:
    _beginthread(&Search,0,NULL);
    
    //goes down to the Search thread
    
    void Search(void* pArgv){
         while(something == true){
              //does a bunch of stuff...
         }
         _endthread();
    }
    Last edited by scwizzo; 03-07-2008 at 08:51 AM.

  4. #4
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Don't call _endthread. The thread will automatically termine when the function is done.
    Assuming you are using raw Win32, your main thread should always be doing a message pump. In your WindowProc, spawn a new thread for each of your event handlers. This way the GUI will be able to respond to your input, such as clicking the Stop button.
    The general approach now, is to use a flag which you set if you want to stop the process. The file searching code can reguarly check this flag and stop searching if set.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  5. #5
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    >> I'm using PostMessage() to go through the process one file at a time, hoping that after each file the user could have the option to stop it.
    I don't see anything wrong with this approach. Multi-threading is viable solution, but with it's own set of challenges (specially if you're just learning it).

    It does sound as if you were "blocking" your message pump from running as Elysia mentioned. Are you sure you're only processing one file at time per each WM_COMMAND/SCAN message? The trick here is to only do a small amount of work when you receive the SCAN message and then return from the message handler so the message pump can process button clicks, focus events, ect... The more time you spend handling the SCAN message, the less responsive your app will "feel".

    gg

  6. #6
    Registered User
    Join Date
    Mar 2007
    Posts
    416
    Elysia-
    I don't understand what you mean by making a new thread for each event handle. Right now it's just one thread, one function (or process the thread calls), and one global variable.

    CodePlug-
    The PostMessage was stopping the program from basically getting any other message cause it would post the SCAN message so quickly. The SCAN message only does the _beginthread() function, and nothing else. I don't it gets any simpler than that.

  7. #7
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by scwizzo View Post
    Elysia-
    I don't understand what you mean by making a new thread for each event handle. Right now it's just one thread, one function (or process the thread calls), and one global variable.
    I mean for every button click or anything else, really, that executes a lot of code should run in its own thread so that your main app can continue to respond to messages and do a message pump.
    Otherwise your GUI will freeze because it's not responding to messages.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  8. #8
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    Well, I tried it myself - and I was wrong. PostMessage() can not be used in this way. Even though the message loop is running - it starves other messages from being processed - essentially making your message loop an infinite one.

    SetTimer() can be used in this fashion, since WM_TIMER is the very last message to be processed by GetMessage(). Using a timeout of 0 will cause WM_TIMER to come in immediately - and the message loop won't ignore other messages as they come in.

    Of course this method doesn't apply in all cases - and threading is bit more straight forward for doing something "in the background" while keeping your UI responsive.

    Code:
    #include <windows.h>
    #include <iostream>
    using namespace std;
    
    #define DO_WORK_ID 42
    
    LRESULT CALLBACK WinProc(HWND, UINT, WPARAM, LPARAM);
    
    int main()
    {
        const char *className = "WindowsApp";
    
        WNDCLASSA wincl = {0};
        wincl.hInstance = GetModuleHandle(0);
        wincl.lpszClassName = className;
        wincl.lpfnWndProc = WinProc;
        wincl.style = CS_DBLCLKS;    
        wincl.hIcon = LoadIcon(0, IDI_APPLICATION);
        wincl.hCursor = LoadCursor(0, IDC_ARROW);
        wincl.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
    
        if (!RegisterClassA(&wincl))
            return 1;
    
        HWND hwndParent;
        hwndParent = CreateWindowA(className, "Windows App", 
                                   WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                                   CW_USEDEFAULT, CW_USEDEFAULT,
                                   200, 100, HWND_DESKTOP, 0, 
                                   GetModuleHandle(0), 0);
        if (!hwndParent)
            return 1;
    
        HWND hwndChild;
        hwndChild = CreateWindowA("Button", "Button", WS_CHILD | WS_VISIBLE,
                                  10, 10,  170, 50,
                                  hwndParent, (HMENU)BUTTON_ID, 
                                  GetModuleHandle(0), 0);
        if (!hwndChild)
            return 1;
    
        MSG msg;
        BOOL bRet;
        for (;;)
        {
            bRet = GetMessage(&msg, hwndParent, 0, 0);
            if ((bRet == 0) || (bRet == -1))
                break;
    
            if (msg.message == WM_TIMER)
                cout << "msg = WM_TIMER" << endl;
            else
                cout << "msg = " << msg.message << endl;
    
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }//while
    
        return (int)msg.wParam;
    }//main
    
    
    LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, 
                             WPARAM wParam, LPARAM lParam)
    {
        static int counter = 0;
        static bool bRun = false;
    
        switch(msg)
        {
            case WM_DESTROY:
            {
                PostQuitMessage(0);
                return 0;
            }//case
                
            case WM_COMMAND:
            {
                if (wParam == BUTTON_ID)
                {
                    bRun = !bRun;
                    if (bRun)
                    {
                        cout << "bRun = true" << endl;
                        SetTimer(hwnd, DO_WORK_ID, 0, 0);
                    }//if
                    else
                    {
                        cout << "bRun = false" << endl;
                        KillTimer(hwnd, DO_WORK_ID);
                    }//else
    
                    return 0;
                }//if
            }//case
    
            case WM_TIMER:
            {
                cout << "Do Work: " << ++counter << endl;
                return 0;
            }//case
        }//switch
    
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }//WinProc
    gg

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. BN_CLICKED, change button style
    By bennyandthejets in forum Windows Programming
    Replies: 13
    Last Post: 07-05-2010, 11:42 PM
  2. Getting an error with OpenGL: collect2: ld returned 1 exit status
    By Lorgon Jortle in forum C++ Programming
    Replies: 6
    Last Post: 05-08-2009, 08:18 PM
  3. Troubleshooting Input Function
    By SiliconHobo in forum C Programming
    Replies: 14
    Last Post: 12-05-2007, 07:18 AM
  4. Problem with Visual C++ Object-Oriented Programming Book.
    By GameGenie in forum C++ Programming
    Replies: 9
    Last Post: 08-29-2005, 11:21 PM
  5. Question..
    By pode in forum Windows Programming
    Replies: 12
    Last Post: 12-19-2004, 07:05 PM