Multithreaded Wait Dialog

Environment: Window95/98, NT

Well, this project actually started as an effort to do multithreaded DAO.  I had some calculations that were running *much* too long on user's machines and there was some concern that people might actually reboot their machines, thinking they had locked up.   The calculations in question involved going back and forth to a Jet database, so my first thought was to isolate the calculations in a thread of their own and show a little modal dialog letting the user know that the program was still running.

Needless to say, placing Jet in a worker thread did not work (at least, I couldn't get it to work...).  So, as a secondary option, I created a class that would start a worker thread and manage a dialog with an animation on it.  It works more or less like CWaitCursor, all you need to do is declare a variable of type CWaitDialog and call the Show function and the modal dialog will show until you call the Close function.   As a secondary option, you can create a dialog with an abort button on it.   This might be useful for printing or other operations, although a little extra work is required to get the class to respond to the button event.

The WaitDialog itself requires 3 classes: cWaitDialog, which is derived from CCmdTarget so it can use a message map.  cWaitDialog contains a cWaitDlgThread member, which is the worker thread derived from CWinThread.  Lastly is cWaitDlg, which is derived from CDialog.  This could really be any CDialog derivative, as long as you include the code in the OnTimer, OnCancel and OnOK functions.  The dialog in the sample project also includes 2 other classes, cAnimWnd and cMemDC.  cAnimWnd is a simple class that displays a series of bitmaps on a timer, and cMemDC is used by the cAnimWnd (from Keith Rule's CMemDC - thanks, Keith!).



// Creating a cWaitDialog without an abort button:
void CWaitDialogView::OnViewWaitDlg() 
{
   long i,x;
   cWaitDialog dlg;
   
   dlg.m_Text = "Calculating...please wait";

   dlg.Show();

// Do lengthy task here....
   
   dlg.Close();
}

//////////////////////////////////////////////
// Creating a cWaitDialog with an abort button, and creating an event to respond to:
void CWaitDialogView::OnViewAbortDlg() 
{
   HANDLE event;
   event = CreateEvent(NULL, TRUE, FALSE, "CONEVENTTEST");
// can't use a cWaitDialog here because we have to be able to wait for the event to fire,
// so create a cWaitDlgThread instead.  This is essentially what the cWaitDialog class is doing 
// internally anyhow.

   cWaitDlgThread *thread = (cWaitDlgThread *)AfxBeginThread(RUNTIME_CLASS(cWaitDlgThread), THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);

   thread->m_Eventname = "CONEVENTTEST";
   thread->m_bShowCancelButton = true;
   thread->m_Text = "Calculating...please wait";

   thread->ResumeThread();

      long i,x;

      x = 0;
   while ((WaitForSingleObject(event, 0)==WAIT_TIMEOUT) && (x < 10000000))
      {
// Do lengthy task here....
      }

   thread->m_Event->SetEvent();
   CloseHandle(event);
	
}

Download source & demo project - 22 Kb

History



Comments

  • Multipal Instance of a CDialog

    Posted by Legacy on 10/14/2002 12:00am

    Originally posted by: Nitin Dubey

    hello friends

    in my application i need to create multiple instance of a dialog box. i dont have any idea of implimenting UI-Threads in this. can any one send some example code or can give reference to any site where i can get the solution of my problem.

    thankz in advance

    Nitin

    Reply
  • A fixed error

    Posted by Legacy on 04/13/2002 12:00am

    Originally posted by: Hailan

     In the demo project, i found that the menu item of "abort dialog" can't work correctly. It came from the event invoker
    
    after the repition. The new codes are as follows:

    void CWaitDialogView::OnViewAbortDlg()
    {
    // TODO: Add your command handler code here
    HANDLE event;
    event = CreateEvent(NULL, TRUE, FALSE, "CONEVENTTEST");

    cWaitDlgThread *thread = (cWaitDlgThread *)AfxBeginThread(RUNTIME_CLASS(cWaitDlgThread), THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);

    thread->m_Eventname = "CONEVENTTEST";
    thread->m_bShowCancelButton = true;
    thread->m_Text = "Calculating...please wait";

    thread->ResumeThread();

    long i,x;

    x = 0;
    while ((WaitForSingleObject(event, 0)==WAIT_TIMEOUT) && (x < 10000000))
    {
    i = x * x;
    x++;
    }
    if(x>=10000000) //here!!!!!!!!
    thread->m_Event->SetEvent();
    CloseHandle(event);
    }

    Reply
  • memory leak

    Posted by Legacy on 09/23/2001 12:00am

    Originally posted by: Tom Malik

    I've discovered that as I keep dlg.Show()/dlg.Close(), about 150k of memory is eaten up each time, dwindling resources away time after time. If you have an application where this event dialog pops up regularly on certain user clicks, eventually the computer will crash. I've tried looking for the leak but with no success. Any ideas?

    Reply
  • One more assertion & fix

    Posted by Legacy on 09/13/2001 12:00am

    Originally posted by: Tom Malik

    The one last problem i found was that while the thread dialog was running in the background and I pressed return - it would close and cause an assertion error. This is because the dlg.Close() command is not called, and the window terminates prematurely. However, there is a way to fix this --- catch the keyboard input before it is processed.
    
    

    1. Add a "PreTranslateMessage" virtual function to the cWaitDlg.

    --------------------

    // Overrides
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(cWaitDlg)
    public:
    virtual BOOL PreTranslateMessage(MSG* pMsg); // <---
    protected:
    virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
    //}}AFX_VIRTUAL

    // Implementation

    ---------------------

    2. Check for a return key to be pressed, and dont process it.

    ----------------------

    BOOL cWaitDlg::PreTranslateMessage(MSG* pMsg)
    {
    // TODO: Add your specialized code here and/or call the base class

    // insert this code here
    if(pMsg->message == WM_KEYDOWN)
    {
    if(pMsg->wParam == VK_RETURN) // keyboard return key
    {
    return TRUE; // ignore return key, do not pass msg along
    }

    }
    // end insert

    return CDialog::PreTranslateMessage(pMsg);
    }

    Reply
  • Does not work in Dialogbox Parent!

    Posted by Legacy on 01/04/2000 12:00am

    Originally posted by: HENRY LEUNG

    I tried your cWaitDialog in a Dialog based Window. It does not work. As Chris Joyce said, it never ends. I put a TRACE at the functon cWaitDialog::Close(), it is called, but SetEvent() and CloseHandle() do not seem to end the Wait Dialog.
    Please explain why is it so.

    Reply
  • Call from Modal Dialog InitDialog loses focus

    Posted by Legacy on 09/15/1999 12:00am

    Originally posted by: Eric Margheim

    I tried calling cWaitDlg from the InitDialog of a modal dialog box. I call Show at the beginning and Close before the return TRUE. After the wait dialog is destroyed, my app is no longer the foreground application in Windows. This doesn't happen when I call it from a control within a CFormView class.

    Any ideas what's causing this?

    Reply
  • cWaitDialog exits before cWaitDlgThread is done

    Posted by Legacy on 06/21/1999 12:00am

    Originally posted by: Mark Gerrior

    When I added this to my project I had a lot of trouble with various Access Violations and objects not being
    deleted.  IMHO, cWaitDialog doesn't wait for the cWaitDlgThread to exit after it sets the event.  The fix for
    this is as follows:
    
    

    Place this line in cWaitDialog::Show() just before the call to ResumeThread():

    m_Thread->m_bAutoDelete = FALSE;

    My new cWaitDialog::Close() looks like this:

    void cWaitDialog::Close()
    {
    m_Thread->m_Event->SetEvent();
    CloseHandle(m_Event);

    DWORD exitCode = 0;

    if(!::GetExitCodeThread(m_Thread->m_hThread, &exitCode))
    {
    // NGetLastError("GetExitCodeThread in cWaitDialog::Close\n");
    }

    while (exitCode == STILL_ACTIVE)
    {
    TRACE("cWaitDlgThread is STILL_ACTIVE. Sleeping for 200ms.\n");
    Sleep(200);

    if(!::GetExitCodeThread(m_Thread->m_hThread, &exitCode))
    {
    // NGetLastError("GetExitCodeThread in cWaitDialog::Close - 2\n");
    }
    }

    delete m_Thread;
    }


    Reply
  • Other option ...

    Posted by Legacy on 06/21/1999 12:00am

    Originally posted by: Cristian Amarie

    If someone is curious, in my submission 'Shutting down workstations' there is a class named CEventDlg with
    the same functionality. I was never let down by that old class so, if it is interesting, anyone can use it.
    

    Reply
  • Assertion Error

    Posted by Legacy on 06/18/1999 12:00am

    Originally posted by: Al K L Koh

    A very good class. 
    
    However I did find a minor problem.

    Change the for loop statement as the following will cause an assertion error.

    void CWaitDialogView::OnViewWaitDlg()
    {
    // TODO: Add your command handler code here
    long i,x;
    cWaitDialog dlg;

    dlg.m_Text = "Calculating...please wait";

    dlg.Show();

    i = 0;
    //for (x = 0; x <1000000000;x++)
    for (x = 0; x <1000;x++)
    i = x * x;

    dlg.Close();
    }

    void cWaitDialog::Close()
    {
    //Assertion error here !
    m_Thread->m_Event->SetEvent();
    CloseHandle(m_Event);
    }

    Reply
  • Jet and Threads

    Posted by Legacy on 06/05/1999 12:00am

    Originally posted by: Alex Bath

    It is true that Jet does not support multi-threading,
    
    however I managed to get it to work fine for me. See
    "A class for worker threads - Dominik Filipp" in CodeGuru,
    its just the ticket.

    If you want total thread safety there is another route...
    Create a new process (in own address space ) altogether, perhaps with a window that displays the progress, then as you process the database write to a Memory-mapped file which is read by the parent process. You can even send
    messages between the two to communicate status'. (See MFC
    documentation)

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: August 14, 2014 @ 2:00 p.m. ET / 11:00 a.m. PT Data protection has long been considered "overhead" by many organizations in the past, many chalking it up to an insurance policy or an extended warranty you may never use. The realities of today makes data protection a must-have, as we live in a data-driven society -- the digital assets we create, share, and collaborate with others on must be managed and protected for many purposes. Check out this upcoming eSeminar and join Seagate Cloud …

  • Hybrid cloud platforms need to think in terms of sweet spots when it comes to application platform interface (API) integration. Cloud Velocity has taken a unique approach to tight integration with the API sweet spot; enough to support the agility of physical and virtual apps, including multi-tier environments and databases, while reducing capital and operating costs. Read this case study to learn how a global-level Fortune 1000 company was able to deploy an entire 6+ TB Oracle eCommerce stack in Amazon Web …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds