PRB: Using Extension DLL, Database/OLE/Sockets in Regular DLLLast reviewed: July 31, 1997Article ID: Q154126 |
The information in this article applies to:
SYMPTOMSWhen using an Extension DLL from a Regular DLL, you may run into one or more of a set of related problems. Note that because the MFC Database, OLE, and Sockets support DLLs are implemented as Extension DLLs, you might see similar problems if you are using these MFC features, even if you're not explicitly using any of your own Extension DLLs. Some symptoms are:
CAUSEThe Extension DLL is not wired into the CDynLinkLibrary object chain of the Regular DLL.
RESOLUTIONCreate and export an initialization function in the Extension DLL that creates a CDynLinkLibrary object. Call this initialization function exactly once from each Regular DLL that uses the Extension DLL. For an example of this, see the Sample Code section below. If you are using any MFC OLE, MFC Database (or DAO), or MFC Sockets support in your Regular DLL, you need to call a predefined initialization function for each MFCO4xD.DLL, MFCD4xD.DLL, and MFCN4xD.DLL you are using. These are the DLLs that are linked to automatically when using MFC OLE, MFC Database, or MFC Sockets support, respectively. For example, if you are using MFC OLE in an application or DLL, that app or DLL uses the MFCO4xD.DLL. See the References section below for more information. For database support, add a call to AfxDbInitModule() to your Regular DLL's CWinApp::InitInstance function. Make sure this call occurs before any base- class call or any added code that accesses the MFCD4xD.DLL. This function takes no parameters and returns void. For OLE support, add a call to AfxOleInitModule() to your Regular DLL's CWinApp::InitInstance. Note that the COleControlModule InitInstance() function calls AfxOleInitModule() already, so if you are building an OLE control and are using COleControlModule, you should not add this call to AfxOleInitModule(). For Sockets support, add a call to AfxNetInitModule() to your Regular DLL's CWinApp::InitInstance. Note that release builds of MFC DLLs and applications do not use separate DLLs for database, sockets, or OLE support. It is safe to call these initialization functions in release mode, however.
STATUSThis behavior is by design.
MORE INFORMATIONDuring each of the operations mentioned in the Symptoms section above, MFC needs to search for a desired value or object. For example, during de- serialization, MFC needs to search through all of the currently available Runtime Classes to match objects in the archive with their proper Runtime Class. As a part of these searches, MFC scans through all of the Extension DLLs in use by walking a chain of CDynLinkLibrary objects. CDynLinkLibrary objects attach automatically to a chain during their constructor and are created by each Extension DLL in turn during initialization. In addition, every module (EXE or Regular DLL) has its own chain of CDynLinkLibrary objects. In other words, the chain of Extension DLLs used by an Application is different from the chain of Extension DLLs used by one Regular DLL which is different from the chain of Extension DLLs used by another Regular DLL. This last point is one of the most common causes of the aforementioned problems mentioned in the Symptoms section. In order for an Extension DLL to get wired into a CDynLinkLibrary chain, it must create a CDynLinkLibrary object in the context of every module that will be using the Extension DLL. For example, if an Extension DLL is going to be used from Regular DLLs, it must provide an exported initialization function that creates a CDynLinkLibrary object. Every Regular DLL that uses the Extension DLL must call the exported initialization function. If an Extension DLL is only going to be used from an MFC application (EXE) and never from a Regular DLL, then it is sufficient to create the CDynLinkLibrary object in the Extension DLL's DllMain. This is what the AppWizard Extension DLL code does. When loading an Extension DLL implicitly, DllMain loads and executes before the application ever starts. Any CDynLinkLibrary creations are wired into a default chain that the MFC DLL reserves for an MFC application. This prevents any need to call the initialization function from an application. Nevertheless, it is safer and more recommended that all applications use the initialization function and that the Extension DLL not create a CDynLinkLibrary object in DllMain. Note that it is not a good idea to have multiple CDynLinkLibrary objects from one Extension DLL in any one chain, especially if the Extension DLL will be dynamically unloaded from memory. Don't call the initialization function more than once from any one module. The implementations of the AfxDbInitModule, AfxOleInitModule, and AfxNetInitModule functions can be found in the DLLDB.CPP, DLLOLE.CPP, and DLLNET.CPP files in the \MsDev\Mfc\Src directory, respectively.
Sample CodeThis sample code assumes that the Regular DLL is implicitly linking to the Extension DLL. This is accomplished by linking to the Import Library (.LIB) of the Extension DLL when building the Regular DLL. These lines should be in the source of the Extension DLL:
///////////////////// // YourExtDLL.cpp: #include "afxdllx.h" // standard MFC Extension DLL routines static AFX_EXTENSION_MODULE NEAR extensionDLL = { NULL, NULL }; extern "C" int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) { if (dwReason == DLL_PROCESS_ATTACH) { // Extension DLL one-time initialization. if (!AfxInitExtensionModule(extensionDLL, hInstance)) return 0; } return 1; // ok } // Exported DLL initialization is run in context of application // or Regular DLL. extern "C" void WINAPI InitYourExtDLL() { // Create a new CDynLinkLibrary for this app. new CDynLinkLibrary(extensionDLL); // Add other initialization here. }Be sure to export the InitYourExtDLL function. This could be done using _declspec(dllexport), or in your DLL's .DEF file as follows:
///////////////////// // YourExtDLL.Def: LIBRARY YOUREXTDLL CODE PRELOAD MOVEABLE DISCARDABLE DATA PRELOAD SINGLE EXPORTS InitYourExtDLLAdd a call to the InitInstance member of the CWinApp-derived object in each Regular DLL using the Extension DLL:
///////////////////////// // YourRegularDLL.cpp: class CYourRegularDLL : public CWinApp { public: virtual BOOL InitInstance(); // Initialization virtual int ExitInstance(); // Termination // Nothing special for the constructor. CYourRegularDLL(LPCTSTR pszAppName) : CWinApp(pszAppName) { } }; BOOL CYourRegularDLL::InitInstance() { // Any DLL initialization goes here. TRACE0("YOUR Regular DLL initializing\n"); // Wire any extension DLLs into CDynLinkLibrary chain. InitYourExtDLL(); return TRUE; } REFERENCESFor information on Regular DLLs, see MFC Technical Note 11. For information on Extension DLLs, see MFC Technical Note 33. For an example of an Extension DLL with an exported initialization function, see the DLLHUSK Sample on the Visual C++ CD-ROM in Samples MFC Samples Advanced MFC SamplesRelevant source code: in the \MsDev\Mfc\Src directory:
DLLINIT.CPP Extension DLL code DLLMODUL.CPP Regular DLL code DLLDB.CPP MFC Database Debug DLL (MFCD) code DLLOLE.CPP MFC OLE Debug DLL (MFCO) code DLLNET.CPP MFC Sockets Debug DLL (MFCN) codeFor more information covering how to use AFX_MANAGE_STATE in your Regular DLL, and other relevant topics, please see the following articles in the Microsoft Knowledge Base:
ARTICLE-ID: Q140850 TITLE : HOWTO: Converting DLLTRACE to Use MFC in Shared Library ARTICLE-ID: Q150121 TITLE : PRB: MFC Loads Wrong Resource in Extension DLL ARTICLE-ID: Q131946 TITLE : PRB: Bad Pointer from RUNTIME_CLASS with Class from _AFXDLL ARTICLE-ID: Q147315 TITLE : BUG: Access Violation After Unloading Extension DL Keywords : MfcDAO MfcDatabase MfcDLL MfcOLE kbcode kbprg Technology : kbMfc Version : 4.0 4.1 4.2 4.2b 5.0 Platform : NT WINDOWS |
================================================================================
© 1998 Microsoft Corporation. All rights reserved. Terms of Use. |