| Tenouk C & C++ | MFC Home | C++, MFC & DLL 2 | C++, MFC & DLL 4 | Download | Site Index |


 

 

 

 

 

 

Module 16b:

Windows Dynamic Link Libraries - DLL 3

 

 

 

 

 

 

This is a continuation from the previous module... Program examples compiled using Visual C++ 6.0 (MFC 6.0) compiler on Windows XP Pro machine with Service Pack 2. Topics and sub topics for this Tutorial are listed below. If you think the terms used in this DLL tutorial quite blur, you can try studying the Win32 DLL first.

  1. Updating the MYMFC22B Example: Adding Code to Test mymfc22C.dll

  2. A Custom Control DLL

  3. What Is a Custom Control?

  4. A Custom Control's Window Class

  5. The MFC Library and the WndProc() Function

  6. Custom Control Notification Messages

  7. User-Defined Messages Sent to the Control

 

 

Updating the MYMFC22B Project Example: Adding Code to Test mymfc22C.dll

 

When you first built the MYMFC22B program, it linked dynamically to the MYMFC22A MFC extension DLL. Now you'll update the project to implicitly link to the MYMFC22C MFC regular DLL and to call the DLL's square root function.

 

Following are the steps for updating the MYMFC22B example.

 

Add a new dialog resource and class to \mfcproject \mymfc22B. Use the dialog editor to create the IDD_MYMFC22C template, as shown here.

 

Adding and modifying a new dialog resource to MYMFC22B project.

 

Figure 22: Adding and modifying a new dialog resource to MYMFC22B project.

 

Then use ClassWizard to generate a class CTest22cDialog, derived from CDialog.

 

Adding and modifying a new class to MYMFC22B project.

 

Figure 23: Adding and modifying a new class to MYMFC22B project.

 

The controls, data members, and message map function are shown in the following table.

 

Control ID

Type

Data Member

Message Map Function

IDD_MYMFC22C

Dialog template

-

-

IDC_INPUT

edit

m_dInput (double)

-

IDC_OUTPUT

edit

m_dOutput (double)

-

IDC_COMPUTE

button

-

OnCompute

 

Table 3.

 

Adding message map functions.

 

Figure 24: Adding IDC_COMPUTE message handler function.

 

Adding data members/member variables using ClassView.

 

Figure 25: Adding data members/member variables using ClassView.

 

Adding data members/member variables using ClassWizard.

 

Figure 26: Adding data members/member variables using ClassWizard.

 

Code the OnCompute() function to call the DLL's exported function. Edit the ClassWizard-generated function in Test22cDialog.cpp as shown here:

 

void CTest22cDialog::OnCompute()

{

    UpdateData(TRUE);

    m_dOutput = Mymfc22CSquareRoot(m_dInput);

    UpdateData(FALSE);

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

MFC Visual C++ code segment

 

Listing 5.

 

You'll have to declare the Mymfc22CSquareRoot() function as an imported function. Add the following line to the Test22cDialog.h file:

 

extern "C" __declspec(dllimport) double Mymfc22CSquareRoot(double d);

 

 

MFC Visual C++ code segment

 

Listing 6.

 

Integrate the CTest22cDialog class into the MYMFC22B application. You'll need to add a top-level menu, Test, and a Mymfc22C DLL option with the ID ID_TEST_MYMFC22CDLL.

 

Adding and modifying menu and its item to the menu resource.

 

Figure 27: Adding and modifying menu and its item to the menu resource.

 

Use ClassWizard to map this option to a member function in the CMymfc22BView class, and then code the handler in Mymfc22BView.cpp as follows:

 

void CMymfc22BView::OnTestMymfc22Cdll()

{

    CTest22cDialog dlg;

    dlg.DoModal();

}

 

MFC Visual C++ code segment

 

Listing 7.

 

Using ClassWizard to map the menu item to a member function in the CMymfc22BView class.

 

Figure 28: Using ClassWizard to map the menu item to a member function in the CMymfc22BView class.

 

Of course, you'll have to add this #include line to the Mymfc22BView.cpp file:

 

#include "Test22cDialog.h"

 

MFC Visual C++ code segment

 

Listing 8.

 

 

Add the MYMFC22C import library to the linker's input library list. Choose Settings from Visual C++'s Project menu, and then add \mfcproject\mymfc22C\Debug\mymfc22C.lib to the Object/Library modules control on the Link page. Use a space to separate the new entry from the existing entry. In this example a full path is used as shown in the following Figure.

 

Adding the mymfc22C.lib (import) library to the linker's input library list.

 

Figure 29: Adding the mymfc22C.lib (import) library to the linker's input library list.

 

Now the program should implicitly link to both the MYMFC22A DLL and the MYMFC22C DLL. As you can see, the client doesn't care whether the DLL is a regular DLL or an extension DLL. You just specify the LIB name to the linker.

 

Build and test the updated MYMFC22B application. Choose Mymfc22C DLL from the Test menu. Type a number in the Input edit control, and then click the Compute Sqrt button. The result should appear in the Output control.

 

MYMFC22B program output with new DLL that used to compute a square root of a given number.

 

Figure 30: MYMFC22B program output with new DLL that used to compute a square root of a given number.

 

A Custom Control DLL

 

Programmers have been using DLLs for custom controls since the early days of Windows because custom controls are neatly self-contained. The original custom controls were written in pure C and configured as stand-alone DLLs. Today you can use the features of the MFC library in your custom controls, and you can use the wizards to make coding easier. A regular DLL is the best choice for a custom control because the control doesn't need a C++ interface and because it can be used by any development system that accepts custom controls (such as the Borland C++ compiler). You'll probably want to use the MFC dynamic linking option because the resulting DLL will be small and quick to load.

 

What Is a Custom Control?

 

You've seen ordinary controls and Microsoft Windows common controls in Module 5, and you've seen ActiveX controls in Module 18. The custom control acts like an ordinary control, such as the edit control, in that it sends WM_COMMAND notification messages to its parent window and receives user-defined messages. The dialog editor lets you position custom controls in dialog templates. That's what the "head" control palette item, shown here, is for.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Custom control in control palette.

Figure 31: Custom control in control palette.

 

You have a lot of freedom in designing your custom control. You can paint anything you want in its window (which is managed by the client application) and you can define any notification and inbound messages you need. You can use ClassWizard to map normal Windows messages in the control (WM_LBUTTONDOWN, for example), but you must manually map the user-defined messages and manually map the notification messages in the parent window class.

 

A Custom Control's Window Class

 

A dialog resource template specifies its custom controls by their symbolic window class names. Don't confuse the Win32 window class with the C++ class; the only similarity is the name. A window class is defined by a structure that contains the following:

The Win32 RegisterClass() function copies the structure into process memory so that any function in the process can use the class to create a window. When the dialog window is initialized, Windows creates the custom control child windows from the window class names stored in the template. Suppose now that the control's WndProc() function is inside a DLL. When the DLL is initialized (by a call to DllMain()), it can call RegisterClass() for the control. Because the DLL is part of the process, the client program can create child windows of the custom control class. To summarize, the client knows the name string of a control window class and it uses that class name to construct the child window. All the code for the control, including the WndProc() function, is inside the DLL. All that's necessary is that the client loads the DLL prior to creating the child window.

 

The MFC Library and the WndProc() Function

 

Okay, so Windows calls the control's WndProc() function for each message sent to that window. But you really don't want to write an old-fashioned switch-case statement, you want to map those messages to C++ member functions, as you've been doing all along. Now, in the DLL, you must rig up a C++ class that corresponds to the control's window class. Once you've done that, you can happily use ClassWizard to map messages.

The obvious part is the writing of the C++ class for the control. You simply use ClassWizard to create a new class derived from CWnd. The tricky part is wiring the C++ class to the WndProc() function and to the application framework's message pump. You'll see a real WndProc() in the MYMFC22D example, but here's the pseudocode for a typical control WndProc() function:

 

LRESULT MyControlWndProc(HWND hWnd, UINT message WPARAM wParam, LPARAM lParam)

{

    if (this is the first message for this window)

    {

        CWnd* pWnd = new CMyControlWindowClass();

        attach pWnd to hWnd

    }

    return AfxCallWndProc(pWnd, hWnd, message, WParam, lParam);

}

 

The MFC AfxCallWndProc() function passes messages to the framework, which dispatches them to the member functions mapped in CMyControlWindowClass.

 

Custom Control Notification Messages

 

The control communicates with its parent window by sending it special WM_COMMAND notification messages with parameters, as shown here.

 

Parameter

Usage

(HIWORD) wParam

Notification code

(LOWORD) wParam

Child window ID

lParam

Child window handle

 

Table 4

 

The meaning of the notification code is arbitrary and depends on the control. The parent window must interpret the code based on its knowledge of the control. For example, the code 77 might mean that the user typed a character while positioned on the control.

 

The control might send a notification message such as this:

 

GetParent()->SendMessage(WM_COMMAND, GetDlgCtrlID() | ID_NOTIFYCODE << 16, (LONG) GetSafeHwnd());

 

On the client side, you map the message with the MFC ON_CONTROL macro like this:

 

ON_CONTROL(ID_NOTIFYCODE, IDC_MYCONTROL, OnClickedMyControl)

 

Then you declare the handler function like this:

 

afx_msg void OnClickedMyControl();

 

User-Defined Messages Sent to the Control

 

You have already seen user-defined messages in Module 6. This is the means by which the client program communicates with the control. Because a standard message returns a 32-bit value if it is sent rather than posted, the client can obtain information from the control.

 

 

Continue on next module...part 4.

 

 

 

 

Further reading and digging:

  1. Win32 dynamic link library, DLL.

  2. MSDN MFC 7.0 class library online documentation.

  3. MSDN MFC 9.0 class library online documentation - latest version.

  4. MSDN Library

  5. Windows data type.

  6. Win32 programming Tutorial.

  7. The best of C/C++, MFC, Windows and other related books.

  8. Unicode and Multibyte character set: Story and program examples.

 

 

 

 


 

| Tenouk C & C++ | MFC Home | C++, MFC & DLL 2 | C++, MFC & DLL 4 | Download | Site Index |