Last Updated:

Developing MFC Extension DLLs in Visual C++

Visual C++

Prepare and link a DLL module for some sample extended class.

Qualified windows software professionals are moving away from the Windows SDK and moving to modern Windows development environments that provide a greater degree of abstraction from the low-level built-in windows mechanisms. As a result of such changes, the Microsoft Visual C++ language turned out to be in a winning situation, in which the basis for the object-oriented view of the Windows API is the MFC base class library (Microsoft Foundation Classes).

MFC in the hands of an experienced developer is a powerful, but far from perfect tool. In fact, almost all the programmers I know who rely on MFC have had to develop their own set of extensions based on MFC classes at least once in their lives, from which the necessary derived classes were derived. But this, in the end, refers to the capabilities of C++. If a class is not suitable for your needs (and if it was essentially intended to be a base class in the first place), you can derive a derived class from it and then make changes to its components that do not suit you.

Suppose you have prepared a set of extensions for MFC that are expected to be used by other programmers in your company. The question arises, how to arrange these extensions? You could distribute source files or distribute components that are compatible with the Visual C++ Component Gallery. Or, if you prefer MFC, compile the extensions you have prepared as DLL modules. From MFC extension DLLs, classes are exported in the same way as from regular function DLLs. Any program dynamically linked to MFC DLLs can again dynamically communicate with MFC extension DLLs. All that is required from the developer is to include the necessary header files and the IMPORT DLL in the list of links of this program.

How difficult is it to prepare an MFC extension DLL? It's very simple if you use visual C++ and MFC tools. In this article, we'll show you how to create an MFC extension DLL that would make up for the glaring flaw in the MFC CToolTipCtrl class. In addition, we will tell you how to make a program that works with this module. When you realize how simple it all is, you may want to develop MFC extensions on your own.

Preparing the MFC Extension DLL

In theory, you can easily assign TollTips hints to dialog boxes or randomly selected dialog boxes using MFC's CToolTipCtrl class. (ToolTips tooltips are a miniature window with reference text that pops up when the mouse pointer is placed on a toolbar button or other interface object.) But there's a problem. Because the CToolTipCtrl::AddTool function does not automatically divide into subclasses of the window to which the ToolTip is assigned, you have to pass information about mouse-related events to the ToolTip control yourself. This usually means that the task of dividing the window into subclasses is up to you.

The ToolTip control, which serves as the basis of the CToolTipCtrl object, will divide itself into subclasses if you take care of passing the appropriate check boxes to it, a feature that the MFC development team has overlooked. Fortunately, correcting this oversight is not difficult at all. You just need to prepare a class that derives from the CToolTipCtrl class and replace the CToolTipCtrl::AddTool function with a similar function that contains a check box TTF_SUBCLASS in the uFlags field of the TOOLINFO structure used in TTM_ADDTOOL messages. Better yet, replace it with two functions - to add ToolTips to child windows and to rectangular areas of the window. The AddTool function provides these capabilities, but syntactically the two methods are very different from each other.

Per sheet. Figures 1 and 2 are the source code for the CToolTipCtrl-derived class called CToolTipCtrlEx. In addition to those inherited from CToolTipCtrl:AddWindow, the derived class has two functions: to assign a ToolTip to a child window and to AddRectangle, which does the same for a rectangular window area. To make it easier to assign a tooltip, both functions use the TTF_SUBCLASS check box. Let's designate the CToolTipCtrlEx object as m_tooltipCtrl, then the snippet for assigning a ToolTip hint to a button switch with a IDC_BUTTON ID looks pretty elementary:

m_tooltipCtrl.AddWindow(GetDlgItem(IDC_BUTTON),
"Enter hint text here!");

Leaf. 1. Header file of the CToolTipCtrlEx class.

// ToolTip.h: header file
//

/////////////////////////////////////////////////// //////////
//Window CToolTipCtrlEx

class AFX_EXT_CLASS CToolTipCtrlEx : public CToolTipCtrl
{
// Constructor
public:
  BOOL AddRectangle (CWnd* pWnd, LPCTSTR pszText,
                     LPCRECT preRect, UINT nIDTool);
  BOOL AddWindow(CWnd* pWnd, LPCTSTR pszText);
  CToolTipCtrlEx();

//Attributes
public:

//Operations
public:

//Overrides
  // ClassWizard generated virtual function overrides
  //{{AFX_VIRTUAL(CToolTipCtrlEx)
  //}}AFX_VIRTUAL

// Implementation
public:
  virtual ~CToolTipCtrlEx();

  // Generated message map functions
protected:
  //{{AFX_MSG(CToolTipCtrlEx)
    // Note that the "master" ClassWizard will add
    // macros
    // remove member functions here,
  //}}AFX_MSG

  DECLARE_MESSAGE_MAP()
};


-------------------------------------------------- ------------------------------
Sheet. 2. cpp file for the CToolTipCtrlEx class.

// ToolTip.cpp : implementation file
//

#include "stdafx.h"
#include "stdafx.h"
#include "ToolTip.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////// //////////
// CToolTipCtrlEx

CToolTipCtrlEx::CToolTipCtrlEx()
{
}

CToolTipCtrlEx::~CToolTipCtrlEx()
{
}

BEGIN_MESSAGE_MAP(CToolTipCtrlEx, CToolTipCtrl)
  //{{AFX_MSG_MAP(CToolTipCtrlEx)
    // NOTE - the ClassWizard will add remove mapping
    // macros here.
  //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////// /////////
// Message handlers CToolTipCtrlEx

BOOL CToolTipCtrlEx::AddWindow (CWnd* pWnd, LPCTSTR pszText)
{
  TOOLINFO ti;
  ti, cbSize = sizeof(TOOLINFO);
  ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
  ti.hwnd = pWnd->GetParent()->GetSafeHwnd();
  ti.uId = (UINT) pWnd->GetSafeHwnd();
  ti.hinst = AfxGetInstanceHandle();
  ti.lpszText = (LPSTR)pszText;

  return (BOOL) SendMessage (TTM_ADDTOOL, 0, (LPARAM) &ti);
}

BOOL CToolCtrlEx::AddRectangle (CWnd* pWnd, LPCTSTR pszText,
                                LPCRECT preRect, UINT nIDTool)
{
  TOOLINFO ti;
  ti.cbSize = sizeof(TOOLINFO);
  ti.uFlags = TTF_SUBCLASS;
  ti.hwnd = pWnd->GetSafeHwnd();
  ti.uId = nIDTool;
  ti.hinst = AfxGetInstanceHandle();
  ti.lpszText = (LPSTR)pszText;
  ::CopyRect(&ti.rect, pRect);

  return (BOOL) SendMessage (TTM_ADDTOOL, 0, (LPARAM) &ti);
}

How to arrange the CToolTipCtrlEx class as a DLL module? We offer step-by-step instructions for Visual C++ version 4.x:

 

Launch Visual C++, create a new project by selecting New from the File menu, and double-click on the Project Workspace command. In the Name field (name) of the workspace of the new project New Project Workspace, type the characters "MfcExt" (without quotes). In the Type window, select the MFC AppWizard(dll), then click the Create button.

In the Step 1 window of the AppWizard, in response to the question: "What type of DLL would you like to create?" ("What type of DLL do you want to generate?") - select "MFC Extension DLL (using shared MFC DLL)" Click on the Finish button and on OK button to generate the source code for the DLL.Note the bracketed phrase "using shared MFC DLL" following the words "MFC Extension DLL". MFC: A DLL must be linked dynamically to MFC libraries.

Refer to the ClassWizard Class Wizard and click the Add Class button. Select New to open the Create New Class window. In this window, select CToolTipCtrl in the Base class panel and CToolTipCtrlEx in the Name panel. Click the Change button to change the names of the Tooltip.h and Tooltip.cpp files. (There's no particular need for such changes, but I'm still following this step to get rid of long file names.) Deselect the Add to Component Gallery window to save disk space. Click the Create command to inform the ClassWizard class wizard to spawn a new class, and click OK to complete the wizard.

Add the AddWindow and AddRectangle functions to the CToolTipCtrlEx class. Ensure that both functions are declared public because they will be accessed outside of the CToolTipCtrlEx class. In Visual C++, there is an easy way to add a function that belongs to a class by right-clicking the class name in the ClassView window and selecting Add Function from the shortcut menu.

In the ClassView window, double-click CToolTipCtrlEx to open the class header file. Add AFX_EXT_CLASS to the class description to the right of the class keyword (see Sheet 1).

Create your project. As a result, you will get two very important files: the DLL module itself (Mfcext.dll) and the DLL module import library (Mfcext.lib). The import library contains mainly a list of the names of the exported functions or, as in our case, a list of exported C++ classes. By linking to the import library, a program can work with classes exported from MFC extension DLLs as if the library containing those classes were statically linked. In addition, the connection to the Mfcext.lib library is an indication to Windows that an Mfcext.dll file is required to run a particular program.

Using the MFC Extension DLL Module

Preparing a program that works with the Mfcext.dll module is not difficult. Simply include the Tooltip.h header file in each class that derives from the CToolTipCtrlEx class, and include the Mfcext.lib file in the list of libraries associated with your project. Then consider the CToolTipCtrlEx class as a regular MFC class. Don't forget to select "As a shared DLL" when it comes time to answer the questions of the AppWizard wizard so that your program can communicate with MFC dynamically. You can add the Mfcext.lib file to the list of links in your project by selecting Settings from the Visual C++ Build menu, clicking the Link tab, and entering the route to the Mfcext.lib file in the Object/library modules window.

For example, we provide the ToolTest program, which displays a single button in the dialog box. It dynamically binds to the Mfcext file.dll and uses the CToolTipCtrlEx class. The program works with dialog boxes, and the dialog box class owns the variable CToolTipCtrlEx named m_tooltipCtrl. The following snippet of the dialog box's OnInitDialog function source code creates a ToolTip control and assigns a ToolTip to the on-screen button of that window:

m_tooltipCtrl.Create (this);
m_tooltipCtrl.AddWindowTool (
GetDlgItem (IDC_EXIT);
"Click here to close");

When the cursor is placed on this button, the text "Click here" appears in the ToolTip window. Click on the button - and the program will be closed.

You can download toolTest and the Mfcext.dll file with the source code from PC Magazine Online (www.pcmag.com). Select Downloads from the menu on the left side of the base page, select PC Tech Archives, and then select V16n15.zip. You can also find this file in the CompuServe online information service in the Utilities/Tips forum (GO ZNT:TIPS). Our files are included in this archive. During the unzipping process (Mfcext.zip and Tooltest.zip), set the radio button in PKUNZIP to -d to expand the directories stored in the .zip files as well. Before you run ToolTest for execution, copy the Mfcext.dll file to the Windows system directory or to the directory where the Tooltest.exe executable is located. Otherwise, Windows will not be able to locate the Mfcext file.dll when ToolTest starts running. If you decide to prepare your own version of the Tooltest.exe module, change the route name in the Object/library modules field of the Project Settings dialog box to inform Visual C++ which directory your PC contains the Mfcext.lib file.

Conclusion

Developing MFC extension DLLs is a simple task, unless, of course, you know how to do it. When you share such extensions with other developers, do not forget to pass them both header files describing the classes of these DLL modules and the corresponding .lib files in addition to the DLL files themselves. Then your colleagues will have everything they need to take advantage of the extensions you have prepared.