TN033: DLL Version of MFC. 27 minutes to read.
The DECLARE_SERIAL macro includes all the functionality of DECLARE_DYNAMIC and DECLARE_DYNCREATE. You can use the AFX_API macro to automatically export the CArchive extraction operator for classes that use the DECLARE_SERIAL and IMPLEMENT_SERIAL macros.
Contributors. In this article This note describes how you can use the MFCxx.DLL and MFCxxD.DLL (where x is the MFC version number) shared dynamic link libraries with MFC applications and MFC extension DLLs. For more information about regular MFC DLLs, see. This technical note covers three aspects of DLLs. The last two are for the more advanced users:. If you are interested in building a DLL using MFC that can be used with non-MFC applications (this is called a regular MFC DLL), refer to. Overview of MFCxx.DLL Support: Terminology and Files Regular MFC DLL: You use a regular MFC DLL to build a stand-alone DLL using some of the MFC classes.
Interfaces across the App/DLL boundary are 'C' interfaces, and the client application does not have to be an MFC application. This is the version of DLL support supported in MFC 1.0. It is described in and the MFC Advanced Concepts sample. Note As of Visual C version 4.0, the term USRDLL is obsolete and has been replaced by a regular MFC DLL that statically links to MFC. You may also build a regular MFC DLL that dynamically links to MFC. MFC 3.0 (and above) supports regular MFC DLLs with all the new functionality including the OLE and Database classes.
AFXDLL: This is also referred to as the shared version of the MFC libraries. This is the new DLL support added in MFC 2.0. The MFC library itself is in a number of DLLs (described below) and a client application or DLL dynamically links the DLLs that it requires. Interfaces across the application/DLL boundary are C/MFC class interfaces.
The client application MUST be an MFC application. This supports all MFC 3.0 functionality (exception: UNICODE is not supported for the database classes). Note The MFCSxxUD.LIB libraries are used in conjunction with the MFC shared DLLs.
These libraries contain code that must be statically linked to the application or DLL. An application links to the corresponding import libraries:. Debug: MFCxxD.LIB.
Release: MFCxx.LIB. Unicode Debug: MFCxxUD.LIB. Unicode Release: MFCxxU.LIB An 'MFC Extension DLL' is a DLL built upon MFCxx.DLL (and/or the other MFC shared DLLs). Here the MFC component architecture kicks in. If you derive a useful class from an MFC class, or build another MFC-like toolkit, you can place it in a DLL.
That DLL uses MFCxx.DLL, as does the ultimate client application. This permits reusable leaf classes, reusable base classes, and reusable view/document classes. Pros and Cons Why should you use the shared version of MFC. Using the shared library can result in smaller applications (a minimal application that uses most of the MFC library is less than 10K). The shared version of MFC supports MFC Extension DLLs and regular MFC DLLs. Building an application that uses the shared MFC libraries is faster than building a statically linked MFC application because it is not necessary to link MFC itself. This is especially true in DEBUG builds where the linker must compact the debug information — by linking with a DLL that already contains the debug information, there is less debug information to compact within your application.
Why should you not use the shared version of MFC:. Shipping an application that uses the shared library requires that you ship the MFCxx.DLL (and others) library with your program. MFCxx.DLL is freely redistributable like many DLLs, but you still must install the DLL in your SETUP program.
In addition, you must ship the MSVCRTxx.DLL, which contains the C-runtime library which is used both by your program and the MFC DLLs themselves. How to Write an MFC Extension DLL An MFC Extension DLL is a DLL containing classes and functions written to embellish the functionality of the MFC classes. An MFC Extension DLL uses the shared MFC DLLs in the same way an application uses it, with a few additional considerations:. The build process is similar to building an application that uses the shared MFC libraries with a few additional compiler and linker options.
An MFC Extension DLL does not have a CWinApp-derived class. An MFC Extension DLL must provide a special DllMain. AppWizard supplies a DllMain function that you can modify. An MFC Extension DLL will usually provide an initialization routine to create a CDynLinkLibrary if the MFC extension DLL wishes to export CRuntimeClasses or resources to the application. A derived class of CDynLinkLibrary may be used if per-application data must be maintained by the MFC extension DLL.
These considerations are described in more detail below. You should also refer to the MFC Advanced Concepts sample since it illustrates:. Building an application using the shared libraries. (DLLHUSK.EXE is an MFC application that dynamically links to the MFC libraries as well as other DLLs.). Building an MFC Extension DLL. (Note the special flags such as AFXEXT that are used in building an MFC extension DLL). Two examples of MFC Extension DLLs.
One shows the basic structure of an MFC Extension DLL with limited exports (TESTDLL1) and the other shows exporting an entire class interface (TESTDLL2). Both the client application and any MFC extension DLLs must use the same version of MFCxx.DLL. You should follow the convention of MFC DLL and provide both a debug and retail (/release) version of your MFC extension DLL.
Dryden Community Schools holds the following beliefs: All students are capable of high achievement and can be successful. All students should be valued as individuals and as contributing members of collaborative teams. Dryden high school. Mission Statement: Dryden Schools promote academic achievement and youth development, preparing students for lives of productive employment, sound relationships, and responsible citizenship in our community and the world. Vision Statement: The Dryden Central School District is an outstanding place to live and attend school because of its shared commitment to the highest quality education and.
This permits client programs to build both debug and retail versions of their applications and link them with the appropriate debug or retail version of all DLLs. Note If you use your MFC extension DLL from a regular MFC DLL, you must export this initialization function. This function must be called from the regular MFC DLL before using any MFC extension DLL classes or resources.
Exporting Entries The simple way to export your classes is to use declspec(dllimport) and declspec(dllexport) on each class and global function you wish to export. This makes it a lot easier, but is less efficient than naming each entry point (described below) since you have less control over what functions are exported and you cannot export the functions by ordinal. TESTDLL1 and TESTDLL2 use this method to export their entries. A more efficient method (and the method used by MFCxx.DLL) is to export each entry by hand by naming each entry in the.DEF file. Since we are exporting selective exports from our DLL (that is, not everything), we must decide which particular interfaces we wish to export.
This is difficult since you must specify the mangled names to the linker in the form of entries in the.DEF file. Don't export any C classes unless you really need to have a symbolic link for it. If you have tried exporting C classes with a.DEF file before, you may want to develop a tool to generate this list automatically. This can be done using a two-stage link process. Link your DLL once with no exports, and allow the linker to generate a.MAP file.
The.MAP file can be used to generate a list of functions that should be exported, so with some rearranging, it can be used to generate your EXPORT entries for your.DEF file. The export list for MFCxx.DLL and the OLE and Database MFC extension DLLs, several thousand in number, was generated with such a process (although it is not completely automatic and requires some hand tuning every once in a while). CDynLinkLibrary An MFC Extension DLL does not have a CWinApp-derived object of its own; instead it must work with the CWinApp-derived object of the client application. This means that the client application owns the main message pump, the idle loop and so on. If your MFC Extension DLL needs to maintain extra data for each application, you can derive a new class from CDynLinkLibrary and create it in the InitXxxDLL routine describe above. When running, the DLL can check the current application's list of CDynLinkLibrary objects to find the one for that particular MFC extension DLL. Using Resources in Your DLL Implementation As mentioned above, the default resource load will walk the list of CDynLinkLibrary objects looking for the first EXE or DLL that has the requested resource.
All MFC APIs as well as all the internal code uses AfxFindResourceHandle to walk the resource list to find any resource, no matter where it may reside. If you wish to only load resources from a specific place, use the APIs AfxGetResourceHandle and AfxSetResourceHandle to save the old handle and set the new handle.
Be sure to restore the old resource handle before you return to the client application. The sample TESTDLL2 uses this approach for explicitly loading a menu. Walking the list has the disadvantages that it is slightly slower and requires managing resource ID ranges. It has the advantage that a client application that links to several MFC extension DLLs can use any DLL-provided resource without having to specify the DLL instance handle. AfxFindResourceHandle is an API used for walking the resource list to look for a given match. It takes the name and type of a resource and returns the resource handle where it was first found (or NULL).
Writing an Application That Uses the DLL Version Application Requirements An application that uses the shared version of MFC must follow a few simple rules:. It must have a CWinApp object and follow the standard rules for a message pump. It must be compiled with a set of required compiler flags (see below). It must link with the MFCxx import libraries. By setting the required compiler flags, the MFC headers determine at link time which library the application should link with. To run the executable, MFCxx.DLL must be on the path or in the Windows system directory. Building with the Development Environment If you are using the internal makefile with most of the standard defaults, you can easily change the project to build the DLL version.
The following step assumes you have a correctly functioning MFC application linked with NAFXCWD.LIB (for debug) and NAFXCW.LIB (for retail) and you want to convert it to use the shared version of the MFC library. You are running the Visual C environment and have an internal project file. On the Projects menu, click Properties. In the General page under Project Defaults, set Microsoft Foundation Classes to Use MFC in a Shared DLL (MFCxx(d).dll). Building with NMAKE If you are using the external makefile feature of the Visual C, or are using NMAKE directly, you will have to edit your makefile to support compiler and linker options Required compiler flags:. /DAFXDLL /MD /DAFXDLL The standard MFC headers need this symbol to be defined:. /MD The application must use the DLL version of the C run-time library All other compiler flags follow the MFC defaults (for example, DEBUG for debug).
Edit the linker list of libraries. Change NAFXCWD.LIB to MFCxxD.LIB and change NAFXCW.LIB to MFCxx.LIB. Replace LIBC.LIB with MSVCRT.LIB. As with any other MFC library it is important that MFCxxD.LIB is placed before any C-runtime libraries. Optionally add /DAFXDLL to both your retail and debug resource compiler options (the one that actually compiles the resources with /R). This makes your final executable smaller by sharing the resources that are present in the MFC DLLs. A full rebuild is required after these changes are made.
Building the Samples Most of the MFC sample programs can be built from Visual C or from a shared NMAKE-compatible MAKEFILE from the command line. To convert any of these samples to use MFCxx.DLL, you can load the.MAK file into the Visual C and set the Project options as described above. If you are using the NMAKE build, you can specify 'AFXDLL=1' on the NMAKE command line and that will build the sample using the shared MFC libraries. The MFC Advanced Concepts sample is built with the DLL version of MFC.
This sample not only illustrates how to build an application linked with MFCxx.DLL, but it also illustrates other features of the MFC DLL packaging option such as MFC Extension DLLs described later in this technical note. Packaging Notes The retail version of the DLLs (MFCxxU.DLL) are freely redistributable. The debug version of the DLLs are not freely redistributable and should be used only during the development of your application. The debug DLLs are provided with debugging information. By using the Visual C debugger, you can trace execution of your application as well as the DLL. The Release DLLs (MFCxxU.DLL) do not contain debugging information. If you customize or rebuild the DLLs, then you should call them something other than 'MFCxx' The MFC SRC file MFCDLL.MAK describes build options and contains the logic for renaming the DLL.
Renaming the files is necessary, since these DLLs are potentially shared by many MFC applications. Having your custom version of the MFC DLLs replace those installed on the system may break another MFC application using the shared MFC DLLs. Rebuilding the MFC DLLs is not recommended. How the MFCxx.DLL Is Implemented The following section describes how the MFC DLL (MFCxx.DLL and MFCxxD.DLL) is implemented. Understanding the details here are also not important if all you want to do is use the MFC DLL with your application.
The details here are not essential for understanding how to write an MFC extension DLL, but understanding this implementation may help you write your own DLL. Implementation Overview The MFC DLL is really a special case of an MFC Extension DLL as described above. It has a very large number of exports for a large number of classes. There are a few additional things we do in the MFC DLL that make it even more special than a regular MFC extension DLL. Win32 Does Most of the Work The 16-bit version of MFC needed a number of special techniques including per-app data on the stack segment, special segments created by some 80x86 assembly code, per-process exception contexts, and other techniques. Win32 directly supports per-process data in a DLL, which is what you want most of the time.
For the most part MFCxx.DLL is just NAFXCW.LIB packaged in a DLL. If you look at the MFC source code, you'll find very few #ifdef AFXDLL, since there are very few special cases that need to be made. The special cases that are there are specifically to deal with Win32 on Windows 3.1 (otherwise known as Win32s). Win32s does not support per-process DLL data directly so the MFC DLL must use the thread-local storage (TLS) Win32 APIs to obtain process local data. Impact on Library Sources, Additional Files The impact of the AFXDLL version on the normal MFC class library sources and headers is relatively minor. There is a special version file (AFXVDLL.H) as well as an additional header file (AFXDLL.H) included by the main AFXWIN.H header.
The AFXDLL.H header includes the CDynLinkLibrary class and other implementation details of both AFXDLL applications and MFC Extension DLLs. The AFXDLLX.H header is provided for building MFC Extension DLLs (see above for details). The regular sources to the MFC library in MFC SRC have some additional conditional code under the AFXDLL #ifdef. An additional source file (DLLINIT.CPP) contains the extra DLL initialization code and other glue for the shared version of MFC. In order to build the shared version of MFC, additional files are provided.
(See below for details on how to build the DLL.). Two.DEF files are used for exporting the MFC DLL entry points for debug (MFCxxD.DEF) and release (MFCxx.DEF) versions of the DLL. An.RC file (MFCDLL.RC) contains all the standard MFC resources and a VERSIONINFO resource for the DLL. A.CLW file (MFCDLL.CLW) is provided to allow browsing the MFC classes using ClassWizard. Note: this feature is not particular to the DLL version of MFC.
Memory Management An application using MFCxx.DLL uses a common memory allocator provided by MSVCRTxx.DLL, the shared C-runtime DLL. The application, any MFC extension DLLs, and well as the MFC DLLs themselves use this shared memory allocator.
By using a shared DLL for memory allocation, the MFC DLLs can allocate memory that is later freed by the application or vice versa. Because both the application and the DLL must use the same allocator, you should not override the C global operator new or operator delete. The same rules apply to the rest of the C run-time memory allocation routines (such as malloc, realloc, free, and others). Ordinals and class declspec(dllexport) and DLL naming We do not use the class declspec(dllexport) functionality of the C compiler.
Instead, a list of exports is included with the class library sources (MFCxx.DEF and MFCxxD.DEF). Only these select set of entry points (functions and data) are exported. Other symbols, such as MFC private implementation functions or classes, are not exported All exports are done by ordinal without a string name in the resident or non-resident name table. Using class declspec(dllexport) may be a viable alternative for building smaller DLLs, but in the case of a large DLL like MFC, the default exporting mechanism has efficiency and capacity limits. What this all means is that we can package a large amount of functionality in the release MFCxx.DLL that is only around 800 KB without compromising much execution or loading speed.
MFCxx.DLL would have been 100K larger had this technique not been used. This also makes it possible to add additional entry points at the end of the.DEF file to allow simple versioning without compromising the speed and size efficiency of exporting by ordinal.
Major version revisions in the MFC class library will change the library name. That is, MFC30.DLL is the redistributable DLL containing version 3.0 of the MFC class library. An upgrade of this DLL, say, in a hypothetical MFC 3.1, the DLL would be named MFC31.DLL instead. Again, if you modify the MFC source code to produce a custom version of the MFC DLL, use a different name (and preferably one without 'MFC' in the name). See also Feedback.