home *** CD-ROM | disk | FTP | other *** search
- Microsoft Foundation Classes Microsoft Corporation
- Technical Notes
-
- #11 : Using MFC as part of a DLL
-
- This note describes how you can use the MFC library as part of a
- Windows DLL. This note assumes you are familiar with Windows DLLs
- and how to build them.
-
- =============================================================================
- Overview
- ========
-
- We will describe how you can build a DLL that uses MFC classes. We
- provide simplified DLL support to reduce the impact on the MFC
- and C++ user.
-
- Interfaces:
- -----------
- This simplified DLL support assumes that interfaces between the application
- and the DLL are specified in normal C-like functions or explicitly exported
- classes. MFC Class interfaces are not automatically exported.
-
- If both a DLL and an application want to use MFC, then they will both
- have a copy of the MFC library statically linked into them. In fact,
- the versions of the libraries will be different. The application uses
- one of the standard versions of the MFC library (depending on the memory
- model, say 'mafxcw.lib') which the DLL uses a special version of the MFC
- library ('lafxdwd.lib').
-
- This gives you several advantages including:
-
- * the application using the DLL does not have to use MFC, or for
- that matter it does not have to be a C++ application.
-
- * the memory model of the application can be different than the DLL. For
- example our DLLs are large model, but the application using the DLL
- can still be medium model.
-
- * the size of the DLL depends only on those MFC and C runtime routines
- that are used and linked in by the linker. Therefore the size of a
- WINDLL is only slightly bigger than the exact same code in a large
- model application.
-
- * there are no problems with classes changing underneath you. DLL
- designers export only those interfaces they wish to.
-
- * if both DLL and application use MFC, there are no problems with the
- application wanting a different version of MFC than the DLL (or vice
- versa). Since the MFC library is statically linked into each DLL
- or EXE, there is no question about which version you have.
-
- * Several messy technical problems are avoided by not trying to split
- classes across DLL boundaries. The Microsoft C++ compiler does
- support this feature with the "__export" keyword on classes. Please
- refer to the C7 language reference for more details.
-
-
- Limitations:
- ============
-
- Some of the C runtime functions are not supported in DLLs.
- As a result of this, the following MFC functionality is not available
- in DLL-compatible MFC libraries:
-
- CTime::Format,
- CTime::FormatGmt,
- CTimeSpan::Format
-
- The MFC classes assume large model for the WINDLL version. As with any
- DLL, we also assume "SS != DS" (SS points to the application's
- stack segment, while DS points to the DLL's data segment).
-
- The OLE classes are not part of the WINDLL version. This is a practical
- consideration since OLE servers tend to be small stand-alone executables
- and MFC does not support OLE handlers (i.e. a more efficient way to build
- an OLE server packaged in a DLL).
-
- =============================================================================
- What to do in your DLL code:
- ============================
-
- Building:
- ---------
- When compiling your windows DLL, the symbol "_WINDLL" must be defined.
- Your DLL code must also be compiled with the following compiler switches:
- /ALw
- large model, SS!=DS
- /GD
- signifies you are a windows DLL (and causes the compiler to
- automatically define _WINDLL)
-
- The interfaces between the application and the DLL must be explicitly
- exported. We recommend you define your interfaces to be low bandwidth,
- sticking to C interfaces where possible. More direct C interfaces
- are easier to maintain than more complex C++ classes.
-
- If you wish high bandwidth C++ classes for your DLL interfaces,
- please see the C7 language reference for a description of how to export
- a class. This has a lot more subtleties to understand to use effectively.
-
- We recommend you place these interfaces in a separate header that can
- be included by both C and C++ files (that way you won't limit your DLL
- customers to C++ programmers). See the header 'TRACEAPI.H' in the DLLTRACE
- sample program for an example.
-
- Make sure these interfaces are declared as "FAR PASCAL _export"
- routines. If you want your interfaces to work for mixed model
- client applications, add explicit "FAR" keywords for data pointers.
-
- WinMain->LibMain
- ================
- The MFC library will define the standard windows 'LibMain' entry point
- that will initialize your CWinApp derived object as in a normal MFC
- application. Place all DLL specific initialization in the
- 'InitInstance' member function as with a normal MFC application.
-
- Note: the CWinApp::Run mechanism doesn't apply to a DLL since the
- application owns the main message pump. If your DLL brings up modeless
- dialogs or has a main frame window of its own, your application's main
- message pump must call a DLL-exported routine that calls CWinApp's
- PreTranslateMessage.
- See the DLLTrace sample for use of this function.
-
- WEPs
- ====
- If desired you can provide a Windows Exit Procedure (WEP) for your
- DLL just as described in the C SDK.
-
- =============================================================================
- What to do to link it all together:
- ===================================
-
- You must do a one time build of the WINDLL version of the MFC library.
- The WINDLL version of the MFC library is built with the command line:
-
- nmake MODEL=L TARGET=W DLL=1 DEBUG=1
- for the debugging version of the library 'lafxdwd.lib'
- nmake MODEL=L TARGET=W DLL=1 DEBUG=0
- for the retail version of the library 'lafxdw.lib'
-
- You must link your DLL with this library (lafxdwd or lafxdw) along with
- the large model WINDLL version of the C runtimes called 'ldllcew.lib'.
-
- =============================================================================
- Sample Code:
- ============
-
- Please see the MFC sample program directory DLLTRACE for a complete sample.
- This includes a simple DLL called 'TRACER.DLL' that implements the
- AFX Trace flags dialog (see TN007.TXT).
- It also has a simple HELLO.EXE application that calls the DLL to
- use the dialog.
-
- Several interesting thing to note:
-
- * the memory model and compiler flags of the DLL and the application
- are very different.
-
- * the link lines and .DEF files for the DLL and the application are also
- very different.
-
- * even though MFC DLLs must be large model, the application that uses
- them can be any memory model you like.
-
- * the application using the DLL doesn't even have to be in C++.
-
- * the interface between the application and the DLL is a "C"-like API
- with the compiler '_export' keyword set - see TRACEAPI.H.
-
- The one API defined in TRACEAPI.H illustrates what is needed for your
- APIs you will define in your DLL:
-
- #ifdef __cplusplus
- extern "C" {
- #endif /* __cplusplus */
-
- struct TracerData
- {
- BOOL bEnabled;
- UINT flags;
- };
-
- BOOL FAR PASCAL __export PromptTraceFlags(TracerData FAR* lpData);
-
- #ifdef __cplusplus
- }
- #endif
-
- * the declaration is enclosed in an 'extern "C" { }' block for C++ users.
- This has several advantages. First it makes your DLL APIs usable
- by non-C++ client applications. Second it reduces DLL overhead
- since C++ name mangling will not be applied to the exported name.
- Lastly it makes it easier to explicitly add to a .DEF file (for
- exporting by ordinal) without having to worry about name mangling.
-
- * all API functions are 'FAR PASCAL __export'.
- This will generate the correct prologue/epilogue sequence for the
- DLL entry points when we use the /GD compiler switch to build the DLL.
- There is no need to do any archaic "MakeProcInstance"s or '_loadds'
- entry points.
-
- * the structures used by the API are not derived from MFC classes, and
- are defined completely in the API header. This reduces the complexity
- of the interface between the DLL and the application and once again
- makes the DLL usable by C programs as well.
-
- * any data pointers used in the API are explicit FAR pointers.
- Since the DLL is compiled large model, data pointers are already
- FAR pointers by default. Adding the extra FAR keyword will allow
- your client applications to be small or medium model without having
- to change your header.
- Never have 'NEAR' pointers in an interface for a DLL.
-
- =============================================================================
-