Uso de archivos DLL de extensión MFC de base de datos, OLE y Sockets en archivos DLL de MFC normales
Cuando se usa un archivo DLL de extensión MFC desde un archivo DLL de MFC normal, si el primero no está conectado a la cadena de objetos CDynLinkLibrary
del segundo, podría encontrarse con uno o varios problemas relacionados. Dado que las versiones de depuración de la base de datos MFC, OLE y Sockets que admiten archivos DLL se implementan como archivos DLL de extensión MFC, es posible que observe problemas similares si usa estas características de MFC, incluso si no utiliza explícitamente ninguno de sus propios archivos DLL de extensión MFC. Algunos de los síntomas son los siguientes:
Al intentar deserializar un objeto de un tipo de clase definida en el archivo DLL de extensión MFC, el mensaje "Advertencia: No se puede cargar CYourClass desde el archivo. Clase sin definir." en la ventana de depuración TRACE y el objeto no se podrá serializar.
Se puede producir una excepción que indica una clase incorrecta.
Los recursos almacenados en el archivo DLL de extensión MFC no se cargan porque
AfxFindResourceHandle
devuelveNULL
o un identificador de recursos incorrecto.DllGetClassObject
,DllCanUnloadNow
y las funciones miembroUpdateRegistry
,Revoke
,RevokeAll
yRegisterAll
deCOleObjectFactory
no pueden encontrar un generador de clases definido en el archivo DLL de extensión MFC.AfxDoForAllClasses
no funciona con ninguna clase del archivo DLL de extensión MFC.La base de datos MFC estándar, los sockets o los recursos OLE no se pueden cargar. Por ejemplo,
AfxLoadString(AFX_IDP_SQL_CONNECT_FAIL)
devuelve una cadena vacía, incluso cuando el archivo DLL de extensión MFC usa correctamente las clases de la base de datos MFC.
La solución a estos problemas es crear y exportar una función de inicialización en el archivo DLL de extensión MFC que crea un CDynLinkLibrary
objeto . Llame a esta función de inicialización exactamente una vez desde cada archivo DLL de MFC estándar que use el archivo DLL de extensión MFC.
Compatibilidad con OLE de MFC, base de datos MFC (o DAO) o sockets MFC
Si utiliza alguna compatibilidad con OLE de MFC, base de datos MFC (o DAO) o Sockets de MFC, respectivamente, en el archivo DLL de MFC normal, los archivos DLL de extensión MFC de depuración de MFC MFCOxxD.dll
, MFCDxxD.dll
y MFCNxxD.dll
(donde xx es el número de versión) se vinculan automáticamente. Con cada uno de estos archivos DLL que se usen, llame a una función de inicialización predefinida:
Para la compatibilidad con la base de datos, agregue una llamada a
AfxDbInitModule
a la funciónCWinApp::InitInstance
de los archivos DLL de MFC normales. Asegúrese de que esta llamada se produce antes de que cualquier llamada de clase base o cualquier código agregado accedan aMFCDxxD.dll
. Esta función no toma ningún parámetro y devuelvevoid
.Para la compatibilidad con OLE, agregue una llamada a
AfxOleInitModule
a la funciónCWinApp::InitInstance
de los archivos DLL de MFC normales. La funciónCOleControlModule::InitInstance
ya llama aAfxOleInitModule
, por lo que si está creando un control OLE y usaCOleControlModule
, no debe agregar esta llamada aAfxOleInitModule
.Para la compatibilidad con Sockets, agregue una llamada a
AfxNetInitModule
a la funciónCWinApp::InitInstance
de los archivos DLL de MFC normales.
Las compilaciones de versión de las aplicaciones y archivos DLL de MFC no usan archivos DLL independientes para la compatibilidad con la base de datos, OLE o Sockets. Sin embargo, es seguro llamar a estas funciones de inicialización en modo de versión.
Objetos CDynLinkLibrary
Durante cada operación mencionada al principio de este artículo, MFC necesita buscar un valor u objeto determinados. Por ejemplo, durante la deserialización, MFC necesita buscar en todas las clases en tiempo de ejecución actualmente disponibles para que los objetos del archivo coincidan con su clase en tiempo de ejecución adecuada.
Como parte de estas búsquedas, MFC examina todos los archivos DLL de extensión de MFC en uso caminando por una cadena de CDynLinkLibrary
objetos. CDynLinkLibrary
Los objetos se adjuntan automáticamente a una cadena durante su construcción y se crean mediante cada DLL de extensión MFC a su vez durante la inicialización. Cada módulo (aplicación o archivo DLL de MFC normal) tiene su propia cadena de objetos CDynLinkLibrary
.
Para que un archivo DLL de extensión MFC se encadene en una CDynLinkLibrary
cadena, debe crear un CDynLinkLibrary
objeto en el contexto de cada módulo que use el archivo DLL de extensión MFC. Para utilizar un archivo DLL de extensión de MFC en archivos DLL de MFC normales, el archivo DLL de extensión debe proporcionar una función de inicialización exportada que cree un objeto CDynLinkLibrary
. Cada archivo DLL de MFC estándar que use el archivo DLL de extensión MFC debe llamar a la función de inicialización exportada.
Si solo va a utilizar un archivo DLL de extensión de MFC de una aplicación MFC y nunca de un archivo DLL de MFC normal, basta con crear el objeto CDynLinkLibrary
en la función DllMain
del archivo DLL de extensión de MFC. Esto es lo que hace el código DLL de extensión de MFC del Asistente para archivos DLL de MFC. Al cargar un archivo DLL de extensión MFC de manera implícita, DllMain
se carga y ejecuta antes de que se inicie la aplicación. Las CDynLinkLibrary
creaciones se conectan a una cadena predeterminada que el archivo DLL de MFC reserva para una aplicación MFC.
No es aconsejable tener varios objetos CDynLinkLibrary
de un archivo DLL de extensión MFC en una cadena. Esto especialmente cierto si el archivo DLL de extensión de MFC se puede descargar dinámicamente de la memoria. No llame a la función de inicialización más de una vez desde cada módulo.
Código de ejemplo
En este código de ejemplo se supone que el archivo DLL de MFC normal crea un vínculo implícitamente con el archivo DLL de extensión de MFC. Para crear un vínculo implícitamente, cree un vínculo a la biblioteca de importación (archivo LIB) del archivo DLL de extensión de MFC cuando compile el archivo DLL de MFC normal.
Las líneas siguientes deben estar en el código fuente del archivo DLL de extensión MFC:
// YourExtDLL.cpp:
// standard MFC extension DLL routines
#include "afxdllx.h"
static AFX_EXTENSION_MODULE extensionDLL;
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
// MFC 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 MFC DLL
extern "C" void WINAPI InitYourExtDLL()
{
// create a new CDynLinkLibrary for this app
new CDynLinkLibrary(extensionDLL);
// add other initialization here
}
Asegúrese de exportar la función InitYourExtDLL. Puede usar __declspec(dllexport)
o exportarlo en el archivo DEF de su archivo DLL, como se muestra aquí:
// YourExtDLL.Def:
LIBRARY YOUREXTDLL
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD SINGLE
EXPORTS
InitYourExtDLL
Agregue una llamada al miembro InitInstance
del objeto derivado de CWinApp
en cada archivo DLL de MFC estándar mediante el archivo DLL de extensión MFC:
// 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 MFC DLL initializing\n");
// wire any MFC extension DLLs into CDynLinkLibrary chain
InitYourExtDLL();
return TRUE;
}