Dynamic Creation of Thread-Separated Dialogs Having Only Its Class Name

Introduction

This article describes a way of creating class objects by the name of its classes. This way permits you to create a new class object by calling a function or class method that receives as input parameters a pointer to the CRuntimeClass object. Thus, this method encapsulates the procedure of object creation inside another class or function.

In general, the article demonstrates how to design a mechanism that creates a user-selected dialog window in its own child thread. The child thread class is derived from CWinThread and its InitInstanse method encapsulates the procedure of object creation. A user can choose a type of dialog that is to be created.

The project architecture represented in Figure 1.

Figure 1. Project Architecture

Writing a Dialog Class

For dialog class creation, we can use a standard VC++ wizard. All we need to do is enter class name and choose the class that it is derived from. The first step is to adapt the newly created class to the correct MFC macros DECLARE_DYNAMIC and IMPLEMENT_DYNAMIC to DECLARE_DYNCREATE and IMPLEMENT_DYNCREATE in ".h" and ".cpp" files of class.

Use of the DECLARE_DYNCREATE macro in ".h" and the IMPLEMENT_DYNCREATE macro in ".cpp" permits classes to be created by the framework dynamically at run time.

The class should look like the following:

class CDialog1 : public CDialog
{
   DECLARE_DYNCREATE(CDialog1)

public:
   CDialog1(CWnd* pParent = NULL);   // standard constructor
   virtual ~CDialog1();

// Dialog Data
   enum { IDD = IDD_DIALOG1 };

   DECLARE_MESSAGE_MAP()
public:
   afx_msg void OnClose();
};

It is convenient to add a WM_CLOSE event handler method to notify the thread which dialog is attached to the window that is going to be closed and it is necessary to call the ExitInstanse method. To let the thread know about this intention, the window has to send a WM_QUIT message.

void CDialog1::OnClose()
{
   this->PostMessage( WM_QUIT );

   CDialog::OnClose();
}

Writing a Child Thread Class

We also can create this class with the help of the VC++ class wizard; just set the derived class to CWinThread. It is necessary to repeat the procedure of changing the MFC macros DECLARE_DYNAMIC and IMPLEMENT_DYNAMIC to DECLARE_DYNCREATE and IMPLEMENT_DYNCREATE in the ".h" and ".cpp" files of the class. This class also is to be created dynamically at run time.

Obviously, we need some variables: pointer to dialog, dialog ID, pointer to CRuntimeClass object of attached dialog class.

class CChildThread : public CWinThread
{
   friend class CMainFrame;
   DECLARE_DYNCREATE(CChildThread)

public:
CChildThread( CRuntimeClass* pClass = NULL, UINT id = 0 );
   virtual ~CChildThread();

private:
   CRuntimeClass* m_pClass;
   UINT m_ID;

protected:
   CDialog* m_pDialog;

public:
   virtual BOOL InitInstance();
   virtual int ExitInstance();

   DECLARE_MESSAGE_MAP()
};

The class constructor ought to be modified to get some class variable values from input parameters. We can initialise the pointer to CRuntimeClass and dialog ID.

CChildThread::CChildThread( CRuntimeClass* pClass, UINT id )
{
   m_pClass  = pClass;
   m_ID      = id;
   m_pDialog = NULL;
}

Now, when the thread object already exists, the InitInstanse method might be called. The mechanism of class object creation by name is placed into this function.

BOOL CChildThread::InitInstance()
{
   if ( m_pClass != NULL)
   {
      CObject* pObject = m_pClass->CreateObject();

      if ( pObject->IsKindOf( RUNTIME_CLASS( CDialog ) ) )
      {
         CWnd desktop;
         desktop.Attach( ::GetDesktopWindow() );

         m_pDialog = ( CDialog* )pObject;
         m_pDialog->Create( m_ID, &desktop );

         m_pMainWnd   = m_pDialog;
         m_pActiveWnd = m_pDialog;
         m_pMainWnd->ShowWindow( SW_SHOW );
         m_pMainWnd->UpdateWindow();

         desktop.Detach();
      }
   }

   return TRUE;
}

First, the object will be created by using the CreateObject method of the CRuntimeClass class. Second, we should convince that just-created object is derived from CDialog using the IsKindOf method of the CObject class. And finally, the Create method of the CDialog class might be called.

The ExitInstance method of the class is to be extended. You should process such an operation like destroying the attached dialog.

int CChildThread::ExitInstance()
{
   if ( m_pDialog != NULL)
   {
      m_pDialog->DestroyWindow();
      delete m_pDialog;
      m_pDialog = NULL;
   }

   return CWinThread::ExitInstance();
}

Using a Class of the Child Thread Type

When a user performs actions to create a new dialog window by dialog selecting, we must take care of the handler that catches this event.

void CSampleDlg::OnDialogDialog1()
{
   CChildThread* pThread = new CChildThread(
                 RUNTIME_CLASS( CDialog1 ), IDD_DIALOG1 );
   pThread->CreateThread();

   m_aChildThreads.Add( pThread );
}

All we have to do is dynamically create a new CChildThread object, passing as input parameters to its constructor a pointer to the CRuntimeClass object and to call the CreateThread method of the newly created thread object. For convenience of subsequent destroying, the thread object pointers are to be stored in a special array. This array is useful when the application main window is going to be closed.

void CSampleDlg::OnClose()
{
   for ( int i = 0; i < m_aChildThreads.GetSize(); i++ )
   {
      if ( m_aChildThreads[i]->GetThreadPriority()
           == THREAD_PRIORITY_NORMAL )
      {
         m_aChildThreads[i]->ExitInstance();
         m_aChildThreads[i]->Delete();
      }
   }

   m_aChildThreads.RemoveAll();

   CDialog::OnClose();
}

Conclusion

Thus, it was cleared how to create a class object having only its class name and why this mechanism is needed. This project model is convenient to use when designing a multi thread application with a set of fixed dialog types when each thread has its own message queue. This model permits you to create windows with equal priority of overlapping. Nevertheless, there is an unresolved task to manage a behaviour of such dialogs, to control operations of minimise and restore.

The idea of using one child thread class for all types of dialogs is original. It actually optimises the project architecture when it is used in a thread-separated dialog.



Downloads

Comments

  • How to Send Data to the Dialog

    Posted by GuenniAtWork on 07/21/2005 08:52am

    How can i put data from the Main Dialog to the Thread Dialog?

    Reply
  • Re:G? Posted by gang5310 on 04/06/2004 09:52pm

    Re:G? Reply

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

Top White Papers and Webcasts

  • Learn How A Global Entertainment Company Saw a 448% ROI Every business today uses software to manage systems, deliver products, and empower employees to do their jobs. But software inevitably breaks, and when it does, businesses lose money -- in the form of dissatisfied customers, missed SLAs or lost productivity. PagerDuty, an operations performance platform, solves this problem by helping operations engineers and developers more effectively manage and resolve incidents across a company's global operations. …

  • Today's agile organizations pose operations teams with a tremendous challenge: to deploy new releases to production immediately after development and testing is completed. To ensure that applications are deployed successfully, an automatic and transparent process is required. We refer to this process as Zero Touch Deployment™. This white paper reviews two approaches to Zero Touch Deployment--a script-based solution and a release automation platform. The article discusses how each can solve the key …

Most Popular Programming Stories

More for Developers

RSS Feeds