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.
The MYMFC22B Project Example: A DLL Test Client Program
This example starts off as a client for mymfc22A.dll. It imports the CPersistentFrame class from the DLL and uses it as a base class for the SDI frame window. Later you'll add code to load and test the other sample DLLs in this module. Here are the steps for building the MYMFC22B example:
Run AppWizard to produce \mfcproject\mymfc22B. This is an ordinary MFC EXE program. Select Single Document. Otherwise, accept the default settings. Be absolutely sure that in Step 5 you accept the As A Shared DLL option.
Figure 10: AppWizard step 5 of 6, selecting As a shared DLL option.
Figure 11: MYMFC22A SDI project summary.
Copy the file persist.h from the \mfcproject\mymfc22A directory to \mfcproject\mymfc22B. Note that you're copying the header file, not the source file, persist.cpp.
Figure 12: Copying the Persist.h header file from the MYMFC22A project directory.
To \mymfc22B directory.
Figure 13: The MYMFC22B project directory.
Also insert the following line into MainFrm.h:
Change the CFrameWnd base class to CPersistentFrame as you did in MYMFC14. Replace all occurrences of CFrameWnd with CPersistentFrame in both MainFrm.h and MainFrm.cpp.
Figure 14: Invoking the find and replace menu.
Figure 15: Replacing all the CFrameWnd with CPersistentFrame in MainFrm.h and MainFrm.cpp files.
Add the mymfc22A import library to the linker's input library list. Choose Settings from Visual C++'s Project menu. Select All Configurations in the Settings For drop-down list. Then fill in the Object/Library Modules control on the Link page as shown below.
You must specify the full pathname for the mymfc22A.lib file unless you have a copy of that file in your project directory.
Figure 16: Adding the mymfc22A.lib (import) library to the linker's input library list.
Build and test the MYMFC22B program. If you run the program from the debugger and Windows can't find the mymfc22A.dll, Windows displays a message box when MYMFC22B starts. If all goes well, you should have a persistent frame application that works exactly like the one in EX15A. The only difference is that the CPersistentFrame code (Persist.h and Persist.cpp) is in an extension DLL.
Figure 17: MYMFC22B program output, using the CPersistentFrame class through the DLL.
MFC Regular DLLs: The CWinApp Derived Class
When AppWizard generates a regular DLL, the DllMain() function is inside the framework and you end up with a class derived from CWinApp (and a global object of that class), just as you would with an EXE program. You can get control by overriding CWinApp::InitInstance and CWinApp::ExitInstance. Most of the time, you don't bother overriding those functions, though. You simply write the C functions and then export them with the __declspec(dllexport) modifier (or with entries in the project's DEF file).
Using the AFX_MANAGE_STATE Macro
When mfc42.dll is loaded as part of a process, it stores data in some truly global variables. If you call MFC functions from an MFC program or extension DLL, mfc42.dll knows how to set these global variables on behalf of the calling process. If you call into mfc42.dll from a regular MFC DLL, however, the global variables are not synchronized and the effects will be unpredictable. To solve this problem, insert the line:
at the start of all exported functions in your regular DLL. If the MFC code is statically linked, the macro will have no effect.
The MFC Regular DLL Resource Search Sequence
When an EXE links to a regular DLL, resource loading functions inside the EXE will load the EXE's own resources. Resource loading functions inside the regular DLL will load the DLL's own resources. If you want your EXE code to load resources from the DLL, you can use AfxSetResourceHandle to temporarily change the resource handle. The code will be nearly the same as that shown in "The MFC Extension DLL Resource Search Sequence" topic. If you're writing an application that needs to be localized, you can put language-specific strings, dialogs, menus, and so forth in an MFC regular DLL. You might, for example, include the modules English.dll, German.dll, and French.dll. Your client program would explicitly load the correct DLL and use code such as that in "The MFC Extension DLL Resource Search Sequence" topic to load the resources, which would have the same IDs in all the DLLs.
The MYMFC22C Example: An MFC Regular DLL
This example creates a regular DLL that exports a single square root function. First you'll build the mymfc22C.dll file, and then you'll modify the test client program, MYMFC22B, to test the new DLL.
Here are the steps for building the MYMFC22C example:
Run AppWizard to produce \mfcproject\mymfc22C. Proceed as you did for MYMFC22A, but accept Regular DLL Using Shared MFC DLL (instead of choosing MFC Extension DLL) from the one and only AppWizard page.
Figure 18: MYMFC22C, new DLL project dialog.
Figure 19: The only step 1 of 1 AppWizard for MYMFC22C, a Regular DLL using shared MFC DLL.
Figure 20: MYMFC22C DLL project summary.
Examine the mymfc22C.cpp file. AppWizard generates the following code, which includes a derived CWinApp class:
// mymfc22C.cpp : Defines the initialization routines for the DLL.
#define new DEBUG_NEW
static char THIS_FILE = __FILE__;
// If this DLL is dynamically linked against the MFC
// DLLs, any functions exported from this DLL which
// call into MFC must have the AFX_MANAGE_STATE macro
// added at the very beginning of the function.
// For example:
// extern "C" BOOL PASCAL EXPORT ExportedFunction()
// // normal function body here
// It is very important that this macro appear in each
// function, prior to any calls into MFC. This means that
// it must appear as the first statement within the
// function, even before any object variable declarations
// as their constructors may generate calls into the MFC
// Please see MFC Technical Notes 33 and 58 for additional
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
// CMymfc22CApp construction
// TODO: add construction code here,
// Place all significant initialization in InitInstance
// The one and only CMymfc22CApp object
Add the code for the exported Mymfc22CSquareRoot() function. It's okay to add this code in the mymfc22C.cpp file, although you can use a new file if you want to:
extern "C" __declspec(dllexport) double Mymfc22CSquareRoot(double d)
if (d >= 0.0)
AfxMessageBox("Can't take square root of a negative number.");
You can see that there's no problem with the DLL displaying a message box or another modal dialog. You'll need to include math.h in the file containing this code because we are going to use the sqrt() pre-defined function.
Build the project and copy the DLL file. Copy the file mymfc22C.dll from the \mfcproject\mymfc22C\Debug directory to your system directory.
Figure 21: Generated DLL file of MYMFC22C program.
Continue on next module...part 3.
Further reading and digging:
MSDN What's New (MFC Feature Pack) - feature pack.
DCOM at MSDN.
COM+ at MSDN.
COM at MSDN.