|
|
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.