|
|
1.1 root 1: Microsoft Foundation Classes Microsoft Corporation
2: Technical Notes
3:
4: #11 : Using MFC as part of a DLL
5:
6: This note describes how you can use the MFC library as part of a
7: Windows DLL. This note assumes you are familiar with Windows DLLs
8: and how to build them.
9:
10: =============================================================================
11: Overview
12: ========
13:
14: We will describe how you can build a DLL that uses MFC classes. We
15: provide simplified DLL support to reduce the impact on the MFC
16: and C++ user.
17:
18: Interfaces:
19: -----------
20: This simplified DLL support assumes that interfaces between the application
21: and the DLL are specified in normal C-like functions or explicitly exported
22: classes. MFC Class interfaces are not automatically exported.
23:
24: If both a DLL and an application want to use MFC, then they will both
25: have a copy of the MFC library statically linked into them. In fact,
26: the versions of the libraries will be different. The application uses
27: one of the standard versions of the MFC library (depending on the memory
28: model, say 'mafxcw.lib') which the DLL uses a special version of the MFC
29: library ('lafxdwd.lib').
30:
31: This gives you several advantages including:
32:
33: * the application using the DLL does not have to use MFC, or for
34: that matter it does not have to be a C++ application.
35:
36: * the memory model of the application can be different than the DLL. For
37: example our DLLs are large model, but the application using the DLL
38: can still be medium model.
39:
40: * the size of the DLL depends only on those MFC and C runtime routines
41: that are used and linked in by the linker. Therefore the size of a
42: WINDLL is only slightly bigger than the exact same code in a large
43: model application.
44:
45: * there are no problems with classes changing underneath you. DLL
46: designers export only those interfaces they wish to.
47:
48: * if both DLL and application use MFC, there are no problems with the
49: application wanting a different version of MFC than the DLL (or vice
50: versa). Since the MFC library is statically linked into each DLL
51: or EXE, there is no question about which version you have.
52:
53: * Several messy technical problems are avoided by not trying to split
54: classes across DLL boundaries. The Microsoft C++ compiler does
55: support this feature with the "__export" keyword on classes. Please
56: refer to the C7 language reference for more details.
57:
58:
59: Limitations:
60: ============
61:
62: Some of the C runtime functions are not supported in DLLs.
63: As a result of this, the following MFC functionality is not available
64: in DLL-compatible MFC libraries:
65:
66: CTime::Format,
67: CTime::FormatGmt,
68: CTimeSpan::Format
69:
70: The MFC classes assume large model for the WINDLL version. As with any
71: DLL, we also assume "SS != DS" (SS points to the application's
72: stack segment, while DS points to the DLL's data segment).
73:
74: The OLE classes are not part of the WINDLL version. This is a practical
75: consideration since OLE servers tend to be small stand-alone executables
76: and MFC does not support OLE handlers (i.e. a more efficient way to build
77: an OLE server packaged in a DLL).
78:
79: =============================================================================
80: What to do in your DLL code:
81: ============================
82:
83: Building:
84: ---------
85: When compiling your windows DLL, the symbol "_WINDLL" must be defined.
86: Your DLL code must also be compiled with the following compiler switches:
87: /ALw
88: large model, SS!=DS
89: /GD
90: signifies you are a windows DLL (and causes the compiler to
91: automatically define _WINDLL)
92:
93: The interfaces between the application and the DLL must be explicitly
94: exported. We recommend you define your interfaces to be low bandwidth,
95: sticking to C interfaces where possible. More direct C interfaces
96: are easier to maintain than more complex C++ classes.
97:
98: If you wish high bandwidth C++ classes for your DLL interfaces,
99: please see the C7 language reference for a description of how to export
100: a class. This has a lot more subtleties to understand to use effectively.
101:
102: We recommend you place these interfaces in a separate header that can
103: be included by both C and C++ files (that way you won't limit your DLL
104: customers to C++ programmers). See the header 'TRACEAPI.H' in the DLLTRACE
105: sample program for an example.
106:
107: Make sure these interfaces are declared as "FAR PASCAL _export"
108: routines. If you want your interfaces to work for mixed model
109: client applications, add explicit "FAR" keywords for data pointers.
110:
111: WinMain->LibMain
112: ================
113: The MFC library will define the standard windows 'LibMain' entry point
114: that will initialize your CWinApp derived object as in a normal MFC
115: application. Place all DLL specific initialization in the
116: 'InitInstance' member function as with a normal MFC application.
117:
118: Note: the CWinApp::Run mechanism doesn't apply to a DLL since the
119: application owns the main message pump. If your DLL brings up modeless
120: dialogs or has a main frame window of its own, your application's main
121: message pump must call a DLL-exported routine that calls CWinApp's
122: PreTranslateMessage.
123: See the DLLTrace sample for use of this function.
124:
125: WEPs
126: ====
127: If desired you can provide a Windows Exit Procedure (WEP) for your
128: DLL just as described in the C SDK.
129:
130: =============================================================================
131: What to do to link it all together:
132: ===================================
133:
134: You must do a one time build of the WINDLL version of the MFC library.
135: The WINDLL version of the MFC library is built with the command line:
136:
137: nmake MODEL=L TARGET=W DLL=1 DEBUG=1
138: for the debugging version of the library 'lafxdwd.lib'
139: nmake MODEL=L TARGET=W DLL=1 DEBUG=0
140: for the retail version of the library 'lafxdw.lib'
141:
142: You must link your DLL with this library (lafxdwd or lafxdw) along with
143: the large model WINDLL version of the C runtimes called 'ldllcew.lib'.
144:
145: =============================================================================
146: Sample Code:
147: ============
148:
149: Please see the MFC sample program directory DLLTRACE for a complete sample.
150: This includes a simple DLL called 'TRACER.DLL' that implements the
151: AFX Trace flags dialog (see TN007.TXT).
152: It also has a simple HELLO.EXE application that calls the DLL to
153: use the dialog.
154:
155: Several interesting thing to note:
156:
157: * the memory model and compiler flags of the DLL and the application
158: are very different.
159:
160: * the link lines and .DEF files for the DLL and the application are also
161: very different.
162:
163: * even though MFC DLLs must be large model, the application that uses
164: them can be any memory model you like.
165:
166: * the application using the DLL doesn't even have to be in C++.
167:
168: * the interface between the application and the DLL is a "C"-like API
169: with the compiler '_export' keyword set - see TRACEAPI.H.
170:
171: The one API defined in TRACEAPI.H illustrates what is needed for your
172: APIs you will define in your DLL:
173:
174: #ifdef __cplusplus
175: extern "C" {
176: #endif /* __cplusplus */
177:
178: struct TracerData
179: {
180: BOOL bEnabled;
181: UINT flags;
182: };
183:
184: BOOL FAR PASCAL __export PromptTraceFlags(TracerData FAR* lpData);
185:
186: #ifdef __cplusplus
187: }
188: #endif
189:
190: * the declaration is enclosed in an 'extern "C" { }' block for C++ users.
191: This has several advantages. First it makes your DLL APIs usable
192: by non-C++ client applications. Second it reduces DLL overhead
193: since C++ name mangling will not be applied to the exported name.
194: Lastly it makes it easier to explicitly add to a .DEF file (for
195: exporting by ordinal) without having to worry about name mangling.
196:
197: * all API functions are 'FAR PASCAL __export'.
198: This will generate the correct prologue/epilogue sequence for the
199: DLL entry points when we use the /GD compiler switch to build the DLL.
200: There is no need to do any archaic "MakeProcInstance"s or '_loadds'
201: entry points.
202:
203: * the structures used by the API are not derived from MFC classes, and
204: are defined completely in the API header. This reduces the complexity
205: of the interface between the DLL and the application and once again
206: makes the DLL usable by C programs as well.
207:
208: * any data pointers used in the API are explicit FAR pointers.
209: Since the DLL is compiled large model, data pointers are already
210: FAR pointers by default. Adding the extra FAR keyword will allow
211: your client applications to be small or medium model without having
212: to change your header.
213: Never have 'NEAR' pointers in an interface for a DLL.
214:
215: =============================================================================
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.