COlePropertyPage in ATL server

I have been using ATL extensively since it first appeared. Whilst ATL is marketed as a lightweight solution of Internet controls, it is also a very good tool for developing applications that expose their functionality via interfaces.

I wanted to use the flexibility of the MFC classes along with the simplicity that ATL lends to writing objects. Specifically, I saw no reason to use the ATL property page stuff when MFC contains a perfectly acceptable solution (COlePropertyPage) AND also allows me to add message handlers very simply using ClassWizard or the WizardBar.

Presented here is my solution to seamlessly add an MFC COlePropertyPage derived class to an ATL in-process server (DLL) that is marked as using MFC. Not a trivial exercise.

The explanation is lengthy, but the resulting class really very simple to use. I only hope my contribution is as useful to others as the information I have gleaned from your site.

This code has been tested using Visual C++ v5 under Windows NT 4.

Download the project files (36K)

File required to use this feature

MfcAtlPropertyPage.h (1K) MfcAtlPropertyPage.rgs (1K)

Warning

This example use undocumented MFC methods and member variables. These may change in a future release of VC++.


Specifics

You are using ATL to build and in-process server (DLL) that will expose one or more objects and wish to use the MFC COlePropertyPage class as the base for your property pages.

You have elected to use MFC as this server is not going anywhere near the internet so you are not concerned about heaving the MFC DLL down a 'phone line.

You want to use MFC for your property pages as those nice people at Microsoft must have put in a lot of time so you could use their COlePropertyPage class.


Setting up the project

  1. Create a new project (File | New | Project | ATL COM AppWizard).
  2. Enter the project name (I will call it ATLMFC) and make sure Create new workspace is selected. Click OK.
  3. The ATL COM AppWizard is displayed. Select the Dynamic Link Library (DLL) and Support MFC options. Press Finish, then OK.


Problem

ATL uses an object map to manage the creations all of the objects that your server exposes. This is, by default, in a file that has the same name as your project. In this case, the file is called ATLMFC.cpp. The object map starts with the line BEGIN_OBJECT_MAP(ObjectMap) and end with the line END_OBJECT_MAP().

In between these two lines go all of your object declarations, in ATL notation. An example might be:

OBJECT_ENTRY(CLSID_CTest, CTest)

The macro takes two parameters, the CLSID of your object and the class that will be used by ATL to create an instance of your object (never mind the specifics).

 All classes that go in the object list will be created as CComObject<CYourATLObjectClass>, such as CComObject<CTest>, from the above example (CComObject is an ATL class). This means that only ATL style classes may appear in this list. Specifically, you can not use this method to add your COlePropertyPage derived class directly to the object map. This seemed very restrictive to me, as I wanted to use the ClassWizard to add all of the messages to my property page. I just couldn't be doing with adding everything by hand (the ATL way).


Solution

The solution is to have a lightweight ATL wrapper class that links up with your COlePropertyPage derived class. To do this, several issues must be addressed:

  • The final class must be easy to use
  • Each property page ATL/MFC class must have a unique CLSID
  • The solution class must be able to register correctly in the system registry

My solution is to have a template ATL class, a special ATL registry file (.rgs) and to use a typedef to declare the final class that is used.


Template class

The file MfcAtlPropertyPage.h defines the template class that implements all of the stuff that ATL requires for the CComObject class and exposes your COlePropertyPage derived class. It also includes code for updating the system registry with the appropriate details.

The following, undocumented, MFC stuff is accessed in the FinalConstruct member function:

  • EnableAggregation
  • m_pOuterUnknown
  • xInnerUnknown

These are required in order to hook the ATL and MFC objects together properly


Registry file

The registry file MfcAtlPropertyPage.rgs contains the details for correct registration of the property page in the system registry. This file is used by CMfcAtlPropertyPage to register each property page that we create.


Creating a COlePropertyPage derived class for use with ATL

This section details, step by step, how to use an MFC COlePropertyPage derived class in your ATL project. These steps also appear in the header file MfcAtlPropertyPage.h.

Once only for the project

Import the resource file MfcAtlPropertyPage.rgs into your project. Give the resource an ID of IDR_MFCATLPPG (This is the name of the resource that CMfcAtlPropertyPage will use. Ensure the correct path is given in the file view for MfcAtlPropertyPage.rgs and change if neccessary.

Add an include for afxctl.h in the file StdAfx.h

Step by step

  • From the menu, select Insert | Resource.
  • Select Import
  • Change the Files of type to All Files
  • Locate the file MfcAtlPropertyPage.rgs
  • Select Import
  • If prompted, enter the resource type now. Call it REGISTRY
  • Select the resource in the project window (Resource tab), right-click, select Properties and change the ID of the resource to IDR_MFCATLPPG
  • Open the file StdAfx.h and add the line #include <afxctl.h> to it

1. Update your IDL/ODL file

Add a coclass statement to your IDL/ODL file for the new property page and support the interface IUnknown. This must appear within the library section of the file.

Example

[

uuid(E948B670-153F-11d1-8F2D-000000000000),

helpstring("MFC Property Page")

]

coclass PpgTest

{

interface IUnknown;

};

Make sure you use the GUIDGEN.EXE utility to generate the CLSID (uuid) for this class (Run GUIDGEN, select registry format then Copy. Paste the resulting text into the uuid entry and remove leading { and trailing }. Do not use the one given in this example.

2. Create the property page class

Create a property page resource and COlePropertyPage derived class as normal using the dialog editor and ClassWizard. Make the necessary change to the source files, as described below.

Step by step

Add the Dialog resource

  • From the menu, select Insert | Resource
  • Open the Dialog item
  • Select the IDD_OLE_PROPPAGE_LARGE resource
  • Select New
  • In the Resource view of the project window, ensure the language for the property page is correct (UK versions will by default create the resource as US). To change the language, select the resource in the project window, right-click and select Properties. Change the language to the correct entry.
  • Design your property page as you wish

Add a new class for the property page

  • Create a new class using ClassWizard (CTRL+W)
  • Select Create a new class
  • Give the class a name, I have called the example class CPpgTest
  • Unfortunately there is no option to derive from COlePropertyPage :-(. Select the next best thing, CPropertyPage
  • Select OK
  • Select OK

Add a new string resource to serve as the caption for the property page

  • Add the string resource
  • Enter the text that will appear in the tab for the property page (I have added the resource IDS_PPGTEST with the text Test)

Alter the source files

  • Open the header file for your property page (in this case CPpgTest)
  • Change the single instance of CPropertyPage to COlePropertyPage
  • Open the source file (in this case CPpgTest.cpp)
  • Change all instances of CPropertyPage to COlePropertyPage. There should be four of them
  • Add the line #include "resource.h" after the line #include "stdafx.h". ClassWizard expects the line #include "<project>.h" (where <project>.h is the main header file for your project) to include resource.h. For ATL projects this is not the case.
  • Add the second argument to the call to the COlePropertyPage constructor. This is the name of the string resource added above (in this example, IDS_PPGTEST)

3. Create a new header file for the class definition

Create an empty text file and add the following:

  • An include statement for MfcAtlPropertyPage.h
  • An include statement for your COlePropertyPage derived class header file
  • A typedef statement for the CmfcAtlPropertyPage template class using your property page. This is required as the ATL OBJECT_ENTRY macro does not accept template class declarations

Save the file in your project directory

Example

// OlePpgTest.h - Declaration of COlePpgTest typedef

#include "MfcAtlPropertyPage.h"

// Definition of CPpgTest (COlePropertyPage derived) class

#include "PpgTest.h"

// typedef that stops OBJECT_ENTRY macro from crying

typedef Extraview::CMfcAtlPropertyPage<&CLSID_PpgTest, CPpgTest> COlePpgTest;

4. Update the server object map

Open the main ATL server source file that contains the server object map. This file typically has the same name as your project, with the cpp extension.

Add your new include file to the list of includes. Add your typedef class to the object map by inserting a new OBJECT_ENTRY macro entry.

Example

// ATLMFC.cpp : Implementation of DLL Exports.

// <cut>

#include "OlePpgTest.h"

// <cut>

CComModule _Module;

BEGIN_OBJECT_MAP(ObjectMap)

OBJECT_ENTRY(CLSID_PpgTest, COlePpgTest)

END_OBJECT_MAP()

ATL will now use your MFC COlePropertyPage derived class as though it were part of ATL!!


Testing the property page

The workspace includes a project called Test which will display the property page. I have added a simple object to the ATLMFC project called Test (ITest, CLSID_Test) that supports the interface ISpecifyPropertyPages. This returns the details for the property page. The test program itself is a simple console application.

 



Comments

  • There are no comments yet. Be the first to comment!

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

Top White Papers and Webcasts

  • You may already know about some of the benefits of Bluemix, IBM's open platform for developing and deploying mobile and web applications. Check out this webcast that focuses on building an Android application using the MobileData service, with a walk-through of the real process and workflow used to build and link the MobileData service within your application. Join IBM's subject matter experts as they show you the way to build a base application that will jumpstart you into building your own more complex app …

  • A modern mobile IT strategy is no longer an option, it is an absolute business necessity. Today's most productive employees are not tied to a desk, an office, or a location. They are mobile. And your company's IT strategy has to be ready to support them with easy, reliable, 24/7 access to the business information they need, from anywhere in the world, across a broad range of communication devices. Here's how some of the nation's most progressive corporations are meeting the many needs of their mobile workers …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds