CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 3 123 LastLast
Results 1 to 15 of 43
  1. #1
    Join Date
    Apr 2004
    Posts
    204

    Exiting a Do-While loop

    My project requires a continual loop.

    In order to exit the loop I have set up a boolean variable that, when set, is used to exit the loop.

    Problem is, the loop does not yield to other processes (ie being able to press the "Quit" button, which sets the boolean variable enabling a way to exit the loop).

    VB has a DoEvents function which allows other processes to be carried out in a loop such as this.

    Since C++ does not have DoEvents I used the following in it's place.
    Code:
        while ( PeekMessage ( (LPMSG)&message, NULL, 0, 0, PM_REMOVE) )
        {
            DispatchMessage ((LPMSG)&message);
            TranslateMessage ((LPMSG)&message);
        }
        Sleep (0);

    The following code compiles and runs, but crashes with the error

    The instruction at "0x00000064" refrenced memort at "0x00000064". The memory could not be "read".

    when the Quit button is depressed.

    Can anyone spot the problem?



    Code:
    #define STRICT
    #define WIN32_LEAN_AND_MEAN  
    
    #include <windows.h>
    
    #define IDB_BTN100   100
    #define IDB_BTN200   200
    
    const char g_szMainWindowClassName[] = "myMainWindowClass";
    const char g_szChildWindowClassName[] = "myChildWindowClass";
    
    LRESULT CALLBACK	MainWndProc(HWND, UINT, WPARAM, LPARAM);
    LRESULT CALLBACK	ChildWndProc(HWND, UINT, WPARAM, LPARAM);
    
    HINSTANCE hInst;								
    
    HWND hMain;
    HWND hChild;
    HWND hBtn100;
    HWND hBtn200;
    
    bool bQuit;
    
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                       LPSTR lpCmdLine, int nCmdShow)
    {
    
    	WNDCLASSEX wcxM;	// for Main Window Class
        WNDCLASSEX wcxC;	// for Child Window Class
        
    	MSG Msg;
    	
    	hInst = hInstance;	// Store instance handle in our global variable
        
    	// Register the Main Window Class
    		wcxM.cbSize        = sizeof(WNDCLASSEX);
    		wcxM.style         = 0;
    		wcxM.lpfnWndProc   = MainWndProc;
    		wcxM.cbClsExtra    = 0;
    		wcxM.cbWndExtra    = 0;
    		wcxM.hInstance     = hInstance;
    		wcxM.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    		wcxM.hCursor       = LoadCursor(NULL, IDC_ARROW);
    		wcxM.hbrBackground = (HBRUSH)COLOR_APPWORKSPACE+1;
    		wcxM.lpszMenuName  = NULL;
    		wcxM.lpszClassName = g_szMainWindowClassName;
    		wcxM.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);
    
    		if(!RegisterClassEx(&wcxM))
    		{
    			MessageBox(NULL, "Main Window Registration Failed!", "Error!",
    				MB_ICONEXCLAMATION | MB_OK);
    			return 0;
    		}
    	
        // Register the Child Window Class
    		wcxC.cbSize			= sizeof(WNDCLASSEX); 
    		wcxC.style			= CS_HREDRAW | CS_VREDRAW;
    		wcxC.lpfnWndProc	= (WNDPROC)ChildWndProc;
    		wcxC.cbClsExtra		= 0;
    		wcxC.cbWndExtra		= 0;
    		wcxC.hInstance		= hInstance;
    		wcxC.hIcon			= NULL;
    		wcxC.hCursor		= LoadCursor(NULL, IDC_ARROW);
    		wcxC.hbrBackground	= (HBRUSH)COLOR_APPWORKSPACE+1;
    		wcxC.lpszMenuName	= NULL;
    		wcxC.lpszClassName	= g_szChildWindowClassName;
    		wcxC.hIconSm		= NULL;
    	
    		if(!RegisterClassEx(&wcxC))
    		{
    			MessageBox(NULL, "Child Window Registration Failed!", "Error!",
    				MB_ICONEXCLAMATION | MB_OK);
    			return 0;
    		}
     
    	// Create the Main Window
    		hMain = CreateWindowEx(
    					NULL,                        
    					g_szMainWindowClassName,
    					"Graphics Test",
    					WS_OVERLAPPEDWINDOW, // | WS_CLIPCHILDREN, 
    					CW_USEDEFAULT, CW_USEDEFAULT, 622, 340,
    					NULL, NULL, hInstance, NULL);
    
    		if(hMain == NULL)
    		{
    			MessageBox(NULL, "Main Window Creation Failed!", "Error!",
    				MB_ICONEXCLAMATION | MB_OK);
    			return 0;
    		}
    
    	// Display the Main Window 
    		ShowWindow(hMain, nCmdShow);
    		UpdateWindow(hMain);
    
        // Create message loop
    		while(GetMessage(&Msg, NULL, 0, 0) > 0)
    		{
    			TranslateMessage(&Msg);
    			DispatchMessage(&Msg);
    		}
    		return static_cast<int>(Msg.wParam);
    }
    
    
    LRESULT CALLBACK MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    
    	switch (message) 
    	{
    		case WM_CREATE:
    			//create the child window which will be the "graphic window"
    			hChild = CreateWindowEx(WS_EX_CLIENTEDGE,g_szChildWindowClassName, NULL,
    				WS_CHILD|WS_VISIBLE|WS_BORDER,
    				15, 15, 285, 285, hWnd, NULL, hInst, NULL);
         		//create the push buttons
    			hBtn100 = CreateWindow("button", "Run", WS_CHILD|WS_VISIBLE,
    				320, 280, 137, 25, hWnd, (HMENU)100, hInst, NULL);
    			hBtn200 = CreateWindow("button", "Quit", WS_CHILD|WS_VISIBLE,
    				470, 280, 137, 25, hWnd, (HMENU)200, hInst, NULL);
    			break;
    		case WM_COMMAND:
    			switch(wParam)
    			{
    				case IDB_BTN100: // Run button			
    					MessageBox(NULL, "Run button", "Test", MB_OK);	
    					do
    					{
    						// C++ equivalent to VB's DoEvents?
    						while ( PeekMessage ( (LPMSG)&message, NULL, 0, 0, PM_REMOVE) )
    						{
    							DispatchMessage ((LPMSG)&message);
    							TranslateMessage ((LPMSG)&message);
    						}
    					    Sleep (0);
    					}
    					while (bQuit == FALSE);				
    					return 0;			
    				case IDB_BTN200: // Quit button
    					bQuit = TRUE;
    					MessageBox(NULL, "Quit button", "Test", MB_OK);	
    					return 0;
    			}
    			break;
    		case WM_DESTROY:
    			PostQuitMessage(0);
    			break;
    		default:
    			return DefWindowProc(hWnd, message, wParam, lParam);
    	};
    	return 0;
    }
    
    
    LRESULT CALLBACK ChildWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	switch (message) 
    	{
    		//case WM_PAINT:	
    	          // break alone causes strange results
    		//	break;
    		case WM_MOUSEMOVE:
    			break;
    		case WM_LBUTTONUP:
    			MessageBox(NULL, "Button pushed inside Pic Box", "Test", MB_OK);
    			//InvalidateRect( hChild , NULL, TRUE );	
    			break;			
    		default:
    			return DefWindowProc(hWnd, message, wParam, lParam);
    	};
    	return 0;
    }

  2. #2
    Join Date
    Nov 2002
    Location
    California
    Posts
    4,556

    Re: Exiting a Do-While loop

    The most straight-forward solution is to run your loop in a separate thread. Otherwise, as you already found out, your program will not "yield" any processor time to handling of other tasks in your program, like clicking on the "Quit" button.

    Threads, however, intorduce complications into your program, most notably the need to synchronize access to shared data and to synchronize inter-thread event communications. One alternative to a separate thread is a so-called "gaming loop" for your message loop. For example, see http://www.codeproject.com/wtl/wtlgameloop.asp or http://www.mvps.org/directx/articles..._game_loop.htm

    This transforms your message loop into a sort of poor-man's multi-threaded app, except that there's only one thread. To work successfully, however, you will need to ensure that your "continual loop" is actually broken up into iterations, and that only one iteration is run before yielding to the PeekMessage part of the message loop.

    Incidentally, I won't tell you why your app is crashing (even though it's fairly evident) because your design is truly "not recommended". See, for example, the comments on PeekMessage in "The n Habits of Highly Defective Windows Applications" at http://www.flounder.com/badprogram.h...age%20anywhere

    Mike

  3. #3
    Join Date
    Jun 2004
    Location
    Chicago, United States
    Posts
    88

    Re: Exiting a Do-While loop

    Quote Originally Posted by mmscg
    My project requires a continual loop.
    The following code compiles and runs, but crashes with the error

    The instruction at "0x00000064" refrenced memort at "0x00000064". The memory could not be "read".

    when the Quit button is depressed.

    Can anyone spot the problem?
    The PeekMessage, DispatchMessage and TranslateMessage functions use MSG type not UINT as parameters. Try this :
    Code:
    do
    {
    	MSG msg;
    	while ( PeekMessage (&msg, NULL, 0, 0, PM_REMOVE) )
    	{
    		DispatchMessage (&msg);
    		TranslateMessage (&msg);
    	}
    }
    while (bQuit == FALSE);
    A.M.
    My Latest Articles:
    CCustomBitmapButton - An owner-draw button and a frame for the caption bar, in one class.
    CCustomTabCtrl - A clone of the Excel tab sheet control.

  4. #4
    Join Date
    Apr 2004
    Posts
    204

    Re: Exiting a Do-While loop

    amarcode:

    Works great! Thank you!


    MikeAThon:

    I checked out PeekMessage on the ....badprogram... link

    I could not understand anything the author was trying to say (except I am breaking every rule in the book)
    because his code snippets all use MFC, which I know nothing about.

    I also looked at the "game loop" links you provided, and they seem identical to what I am trying to do except
    they wrap this "continual loop" around the WinMain message pump.

    In my situation I only wanted to activate this loop at a press of a button (and exit it in the same way).

    If I still am not understanding what you are trying to say, please respond.

    And thanks also for again taking time to help!

  5. #5
    Join Date
    Sep 2001
    Location
    San Diego
    Posts
    2,147

    Re: Exiting a Do-While loop

    You may also want to check your CPU utilization when running this loop. You might want to put a Sleep in there to yield to other running processes (such as the operating system)...

    Code:
    do
    {
    	MSG msg;
    	while ( PeekMessage (&msg, NULL, 0, 0, PM_REMOVE) )
    	{
    		DispatchMessage (&msg);
    		TranslateMessage (&msg);
    		Sleep(0);
    	}
    }
    while (bQuit == FALSE);
    Hope this helps,

    - Nigel

  6. #6
    Join Date
    Apr 2004
    Posts
    204

    Re: Exiting a Do-While loop

    Yes I have Sleep(0); in my loop.
    I really wasn't sure where to put it so I ended up putting it here:
    Code:
    do
    {
    	MSG msg;
    	while ( PeekMessage (&msg, NULL, 0, 0, PM_REMOVE) )
    	{
    		DispatchMessage (&msg);
    		TranslateMessage (&msg);
    	}
    	Sleep(0);
    }
    while (bQuit == FALSE);
    Do you think it makes a difference as to where in the loop?
    Last edited by mmscg; November 11th, 2004 at 10:13 PM.

  7. #7
    Join Date
    Sep 2001
    Location
    San Diego
    Posts
    2,147

    Re: Exiting a Do-While loop

    Ah, so you do...

    If you have a lot of messages (depending on what you're doing), the inner loop could snag 100% of the CPU time while processing messages.

    Putting the Sleep inside the inner while would avoid this, but given a regular set of messages, as you have it will likely be fine.

    ( I would have put it in the inner loop, but that's just me )

    Regards,

    - Nigel

  8. #8
    Join Date
    Apr 2004
    Posts
    204

    Re: Exiting a Do-While loop

    So to be safe, I shall move it then.

    Thanks!

  9. #9
    Join Date
    Nov 2002
    Location
    California
    Posts
    4,556

    Re: Exiting a Do-While loop

    Sleep(0) should not be used here. It causes the current thread to yield the remainder of its time-slice to any other thread in the system with a higher current priority. It therefore will do two things here which seem wrong: it will rob your own program of valuable CPU time that it probably needs to complete its own tasks, and it will mask problems caused by incorrect program architecture that improperly over-utilizes the CPU.

    The thread scheduler in Windows is smarter than your program about when to stop your program (at the natural end of its timeslice) and to let others run in their timeslice. Let Windows do its job.

    @mmscg: To use the "game loop", your "run" button should merely set a global boolean to TRUE, and your "quit" button should set it to false. Then, in the main message loop, test the value of the global and run your "contiual loop" if it's TRUE and don't if it's FALSE.

    Mike

  10. #10
    Join Date
    Sep 2001
    Location
    San Diego
    Posts
    2,147

    Re: Exiting a Do-While loop

    Mike,

    I disagree.

    Removing the sleep prevents the windows task scheduler from doing its job, by forcing this thread to consume almost all of the spare CPU cycles in the machine.

    By giving up the remainder of the timeslice, you are permitting window to perform other essential scheduling.

    Otherwise in a tight loop, like this...

    while(1)
    ;

    This thread will use 100% of the CPU, regardless of its thread priority and other applications will not have their required share of the slices.

    In fact I would go as far as saying that without the sleep in his loop, the thread will consume 100% of his CPU, while it is sitting doing (next to) nothing.

    Hope this helps,

    - Nigel

  11. #11
    Join Date
    Apr 2004
    Posts
    204

    Re: Exiting a Do-While loop

    I found this in a Microsoft article:
    DoEvents is a Visual Basic function that yields execution so the operating system can process other events. This function cleans out the message loop and executes any other pending business in the Visual Basic runtime. Upon completing the pending business execution, the function calls the Sleep function with zero (0) as the argument so that the remaining time slice can be used to check the queue.

    The Sleep 32-bit API function is a subset of the DoEvents function. The Visual Basic program calling the function and the Visual Basic runtime executable and interactions with Windows are immediately put to sleep by this function. The programs remain inactive for the time in milliseconds specified in the Sleep argument.

    The Sleep function allows you to specify the amount of time your applications are inactive. The DoEvents function returns control to the Visual Basic program after the operating system has finished processing the events in its queue and all keys in the SendKeys queue have been sent.
    Does this say where they put the Sleep(0) call?

  12. #12
    Join Date
    Nov 2002
    Location
    California
    Posts
    4,556

    Re: Exiting a Do-While loop

    Don't try to use VB concepts in Win32 programming, at least not without understanding the full VB framework. For example, if the text you quoted is referring to the Win32 Slepp() API function, then it makes no sense to say that "the Sleep function [is called] with zero (0) as the argument so that the remaining time slice can be used to check the queue." The Win32 Sleep function immediately yields the time-slice, so that there's nothing left with which to "check the queue". Tis makes me think that the quoted text is referring to some VB wrapper to the Sleep() function, that does some extra work with the VB framework before it calls the actual Win32 Sleep() function.

    You need to describe what you want to do in your "continual loop". But again, I strongly recommend against Sleep(0), and you probably will not need it.

    @Nigel: I know you disagree, but Sleep(0) is usually a sign of architecture that needs improvement. For example, the programmer does not know why the app is eating 100% CPU time and feels it should not be, but can't figure out any other way to stop it, so he sticks a Sleep(0) (or worse, a Sleep(100)) in it. This would be a bad reason to use Sleep().

    One common use of Sleep(0) is in multi-threaded situations, where you need to play some sort of inter-thread "catch up" and you have determined that one thread has done all it can for now, and must wait for another thread to complete processing that the first thread needs. In such a situation, the first thread's continued use of its time-slice is wasteful, since we already know that it can't do anything further; it should therefore yield its time-slice, and Sleep(0) might make sense here. (WaitForSingleObject might make more sense, but each situation should be evaluated on its own.)

    Mike

    PS: There's almost never a justification for using Sleep(100), or anything above Sleep(0), for the reason that the "100" is usually an arbitrary number that the programmer found experimentally to "get it to work", without fully understanding why it didn't work in the first place. This is guaranteed to fail on someone else's system, at some time in the future.

  13. #13
    Join Date
    Apr 2004
    Posts
    204

    Re: Exiting a Do-While loop

    You need to describe what you want to do in your "continual loop". But again, I strongly recommend against Sleep(0), and you probably will not need it.
    I thought I would be able to complete this on my own... I was wrong.

    I was continuing with the "double-buffering" for graphics. I could not get the previous one working, so I continued to read up on the subject, thought I understood it, implemented it in VB (works GREAT), and now trying to build it in C++ Win32.

    The "continual loop" is there to generate random graphics in the "PictureBox", so that I could watch the effect with double-buffering ON and OFF (I didn't want to use a timer).

    I am posting my code. It builds and runs, but NO graphics appears in my "PictureBox".

    I tried calling UpdateFrame in the WM_PAINT handler, and InvalidateRect whereI had called UpdateFrame.

    This didn't work, and in fact caused strange screen behaviour.

    If anyone is able to help, it would be appreciated, as I am becoming very frustrated, that this graphics part is not really sinking-in for me.
    Attached Files Attached Files

  14. #14
    Join Date
    Apr 2004
    Posts
    204

    Re: Exiting a Do-While loop

    OK, I don't think the problem is a graphics one, but rather not understanding how to return an array thru a function

    I have a user-defined type "Box" and I declare an array GraphicObject[20] of type Box

    In my function UpdateFrame, I call the function MoveGraphicObject
    inside a for-loop that should fill all the parameters of a 20 element array.
    ie
    Code:
    for (i=0; i<=19; i++)
    {
        MoveGraphicObject(GraphicObject[i]);
    }
    Since GraphicObject is declared a global variable these values should be available anywhere in the program

    In my MessageBox "debugger"
    Code:
    wsprintf (cBuf, "%d", GraphicObject[i].x1 );
    MessageBox(NULL, cBuf, "Test", MB_OK);
    always returns zero (ditto GraphicObject[i].y1, GraphicObject[i].x2,GraphicObject[i].y2, etc.)

    yet I know MoveGraphicObject is calculating the values correctly because I do a similar test inside that function, and values other than zero are displayed.

    Can anyone see, what I am doing incorrectly in this regard?

  15. #15
    Join Date
    Apr 2004
    Posts
    204

    Re: Exiting a Do-While loop

    I changed:
    Code:
    void UpdateFrame()
    {
        for (i=0; i<=19; i++)
        {
            MoveGraphicObject(GraphicObject[i]);
        }
    }
    
    
    Box MoveGraphicObject(Box Obj)
    {
        if ( Obj.newB == TRUE )
            {	
                Obj.newB = FALSE;
            }
    }
    to:
    Code:
    void UpdateFrame()
    {
        for (i=0; i<=19; i++)
        {
            GraphicObject[i]=MoveGraphicObject(GraphicObject[i]);
        }
    }
    
    
    Box MoveGraphicObject(Box Obj)
    {
        if ( Obj.newB == TRUE )
            {	
                Obj.newB = FALSE;
            }
        return Obj;
    }
    Would this be the proper way?
    Last edited by mmscg; November 15th, 2004 at 10:42 PM.

Page 1 of 3 123 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured