Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Automation of COM Dialogs in a DLL

0.00/5 (No votes)
28 Apr 2004 2  
Automation of COM Dialogs in a DLL

Introduction

Long have I wanted to reuse dialogs without having to worry about resource ids, DLLs, headers and libraries. I hoped MFC and COM would take care of that but never found a good article explaining how to do it. There are several books and articles about COM, MFC, ATL, components but I could never find one that would just show me how to put a COM dialog in a COM DLL and let me manage it through automation. I've finally figured out a simple process and share the process here.

I could see that you could create dialog resources, new classes for them, and enable the Automation for them, but you couldn�t create instances of them. I�m not sure why, since they derive from CCmdTarget. This article describes how to create a COM Automated dialog that you can bring up from any COM client (i.e VB or VC++) and control it.

Below is a UML diagram showing the component and test application architecture of this simple prototype and the relevant operations involved.

Creating the MFC COM DLL that holds the component

Create a new MFC DLL project:

Make sure it is an Regular DLL using shared MFC DLL and make sure �Automation� is checked. This creates the necessary entry points for the DLL to be registered.

Create the Dialog that will be automated

Now, add a dialog resource to the project. Add a button and double click it. Tell the Class Wizard to create a new class.

Create the dialog and make sure the �Automation� radio button is selected. Note that you cannot enable the �Createable by type ID�. This caused me lots of problems and we�ll see how to get around it later.

Add an event handler to the button press, for example:

void CMyComDlg::OnPressMe() 
{
     // TODO: Add your control notification handler code here

     AfxMessageBox("Pressed");
}

Now, you can add automation controls to the dialog. Using the Class Wizard is easiest. Choose �Add Method

Add some implementation to the automation handler to call the same button handler, for example:

void CMyComDlg::PressMe() 
{
     // TODO: Add your dispatch handler code here

     OnPressMe();
}

Creating the COM Dialog factory

At this point, this COM dialog can be seen outside the dialog, but you cannot create an instance of it. To fix that, we add an object that can be created dynamically. For example, use the Class Wizard to add a new class, derived from CCmdTarget. Make sure the Createable by type ID is checked.

Click OK. I�ve noticed a bug in Dev Studio, that sometimes, the interface doesn�t show up. To get it to appear, just close the project and reopen it. That should fix it.

Otherwise, use the class wizard to add a new Automation interface for the new factory.

Note the return type is of LPDISPATCH. That is the key to passing the dialog out of the DLL to COM Automation clients. In the implementation, you return the dispatch interface pointer through COM to the client.

//////////////////////////////////////////////////////////

// CComDialogFactory message handlers


#include "MyComDlg.h"


LPDISPATCH CComDialogFactory::GetDialog() 
{
     // Yes this is a leak, the *dlg would be a member of the class.

     CMyComDlg *dlg = new CMyComDlg();
     // Set the argument as true to increase the ref count

     return dlg->GetIDispatch(TRUE);
}

Build the project.

Run the regsvr32.exe on the DLL to register the component.

Visual Basic Client

You can now create a VB project to use this dialog and control it easily.

Create a VB Exe project, Choose Project References and browse to the newly compiled type library (TLB file).

Add a button and a handler to the VB form. The code below creates the factory, then creates the dialog. Note the dialog doesn�t appear, you would have to add a �DoModal� or show dialog automation method to get that to happen.

Private Sub Command1_Click()
    ' create the factory

    Dim factory As ComDlgInDll.ComDialogFactory
    Set factory = New ComDlgInDll.ComDialogFactory
    ' allocate the dialog

    Dim dlg As ComDlgInDll.MyComDlg
    ' let the factory make it

    Set dlg = factory.GetDialog
    ' press the dialog button.

    dlg.PressMe
End Sub

Visual C++ Client

The VC++ client isn�t quite as simple. Create a new MFC project (Doc/view, dialog, whatever) add a menu or button and a handler. You have to make sure you initialize the COM libraries if the MFC project doesn�t do it for you in OnInitDialog or InitInstance:

     HRESULT hrx;
     hrx = CoInitialize(NULL);
     ASSERT( SUCCEEDED( hrx ) );

And a similar call to close the libraries OnDestory or ExitInstance:

     CoUninitialize();

To use the component, you do this:

// Import the COM type library

#import "..\Debug\ComDlgInDll.tlb" no_namespace
void CTestAppDlg::OnButton1() 
{
     // TODO: Add your control notification handler code here

     HRESULT hrx;
     // Use smart pointers to create an instance of the factory

     IComDialogFactoryPtr pFactory;
     hrx = pFactory.CreateInstance( __uuidof(ComDialogFactory) );
     ASSERT( SUCCEEDED( hrx ) );
     if ( SUCCEEDED( hrx ) )
     {
          // Get the factory to show the dialog

          IMyComDlgPtr pDlg;
          pDlg = pFactory->GetDialog();
          // And activate the button through COM

          pDlg->PressMe();
     }
}

Conclusion

At this point you have a truly reusable dialog component, with defined interfaces that you can access through any COM client. There is no worrying about copying headers and cpp files around, making sure your resource ID�s don�t overlap and merging or managing of resource files. Just the DLL and the type library.

The code in this article has minimal error checking, and is meant for illustrative purposes only. The code has been tested on VC++ 6.0 SP5, Win 2K SP4

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here