Usando DLLs de extensão de Banco de Dados, OLE e Soquetes do MFC em DLLs regulares do MFC
Ao usar uma DLL de extensão do MFC de uma DLL regular do MFC, se a DLL de extensão do MFC não estiver conectada à cadeia de objetos CDynLinkLibrary
da DLL regular do MFC, você poderá encontrar um ou mais problemas relacionados. Como as versões de depuração de DLLs de suporte de Banco de Dados, OLE e Soquetes do MFC são implementadas como DLLs de extensão do MFC, você poderá ver problemas semelhantes se estiver usando esses recursos do MFC, mesmo que você não esteja usando explicitamente nenhuma DLL de extensão do MFC. Alguns sintomas são:
Ao tentar desserializar um objeto de um tipo de classe definido na DLL de extensão do MFC, a mensagem "Aviso: não é possível carregar CYourClass do arquivo. Classe não definida." aparecerá na janela de depuração TRACE e o objeto falhará ao serializar.
Uma exceção indicando classe inválida poderá ser gerada.
Os recursos armazenados na DLL de extensão do MFC não serão carregados porque
AfxFindResourceHandle
retornaráNULL
ou um identificador de recurso incorreto.DllGetClassObject
,DllCanUnloadNow
e as funções de membroUpdateRegistry
,Revoke
,RevokeAll
eRegisterAll
deCOleObjectFactory
falharão ao localizar uma fábrica de classes definida na DLL de extensão do MFC.AfxDoForAllClasses
não funcionará para nenhuma classe na DLL de extensão do MFC.Os recursos padrão de banco de dados soquetes ou OLE do MFC não serão carregados. Por exemplo,
AfxLoadString(AFX_IDP_SQL_CONNECT_FAIL)
retornará uma cadeia de caracteres vazia, mesmo quando a DLL regular do MFC estiver usando corretamente as classes de Banco de Dados do MFC.
A solução para esses problemas é criar e exportar uma função de inicialização na DLL de extensão do MFC que criará um objeto CDynLinkLibrary
. Chame essa função de inicialização exatamente uma vez em cada DLL regular do MFC que usa a DLL de extensão do MFC.
Suporte a OLE, MFC (ou DAO) ou Soquetes da MFC
Se você estiver usando qualquer suporte de OLE MFC, Banco de Dados MFC (ou DAO) ou Soquetes MFC em sua DLL regular do MFC, respectivamente, as DLLs de extensão de depuração do MFC MFCOxxD.dll
, MFCDxxD.dll
e MFCNxxD.dll
(em que xx é o número da versão) serão vinculadas automaticamente. Chame uma função de inicialização predefinida para cada uma das DLLs que você está usando:
Para suporte ao banco de dados, adicione uma chamada à
AfxDbInitModule
à sua DLL regular do MFC na funçãoCWinApp::InitInstance
. Verifique se essa chamada ocorre antes de qualquer chamada de classe base ou qualquer código adicionado que acesse oMFCDxxD.dll
. Essa função não recebe parâmetros e retornavoid
.Para obter suporte ao OLE, adicione uma chamada à
AfxOleInitModule
à sua DLL regular do MFC na funçãoCWinApp::InitInstance
. A funçãoCOleControlModule::InitInstance
já chamaAfxOleInitModule
, portanto, se você estiver criando um controle OLE e usarCOleControlModule
, não deverá adicionar essa chamada aAfxOleInitModule
.Para obter suporte a Soquetes, adicione uma chamada à
AfxNetInitModule
à sua DLL regular do MFC naCWinApp::InitInstance
.
Os builds de lançamento de DLLs do MFC e aplicativos não usam DLLs separadas para suporte a banco de dados, soquetes ou OLE. No entanto, é seguro chamar essas funções de inicialização no modo de lançamento.
Objetos CDynLinkLibrary
Durante cada operação mencionada no início deste artigo, o MFC precisa pesquisar um valor ou objeto específico. Por exemplo, durante a desserialização, o MFC precisa pesquisar todas as classes de tempo de execução disponíveis no momento para fazer a correspondência de objetos no arquivo com as respectivas classes adequadas de tempo de execução.
Como parte dessas pesquisas, o MFC examina todas as DLLs de extensão do MFC em uso percorrendo uma cadeia de objetos CDynLinkLibrary
. Objetos CDynLinkLibrary
são anexados automaticamente a uma cadeia durante a construção e, por sua vez, são criados para cada DLL de extensão do MFC durante a inicialização. Cada módulo (DLL de aplicativo ou regular do MFC) tem a própria cadeia de objetos CDynLinkLibrary
.
Para que uma DLL de extensão do MFC seja conectada a uma cadeia CDynLinkLibrary
, ela deve criar um objeto CDynLinkLibrary
no contexto de cada módulo que usa a DLL de extensão do MFC. Para usar uma DLL de extensão do MFC em DLLs regulares do MFC, a DLL de extensão deve fornecer uma função de inicialização exportada que cria um objeto CDynLinkLibrary
. Cada DLL regular do MFC que usa a DLL de extensão do MFC deve chamar a função de inicialização exportada.
Se você for usar apenas uma DLL de extensão do MFC de um aplicativo do MFC e nunca de uma DLL regular do MFC, será suficiente criar o objeto CDynLinkLibrary
na função DllMain
da DLL de extensão do MFC. É o que o código da DLL de extensão do MFC de DLL do MFC faz. Ao carregar uma DLL de extensão do MFC implicitamente, o DllMain
é carregado e executado antes que o aplicativo seja iniciado. As criações do CDynLinkLibrary
são conectadas a uma cadeia padrão que a DLL do MFC reserva para um aplicativo do MFC.
É uma má ideia ter vários objetos CDynLinkLibrary
de uma DLL de extensão do MFC em qualquer cadeia. Isso vale ainda mais se a DLL de extensão do MFC puder ser descarregada dinamicamente da memória. Não chame a função de inicialização mais de uma vez em qualquer módulo.
Exemplo de código
Esse código de exemplo pressupõe que a DLL regular do MFC é vinculada implicitamente à DLL de extensão do MFC. Para vincular implicitamente, vincule à biblioteca de importação (arquivo LIB) da DLL de extensão do MFC ao compilar a DLL regular do MFC.
As seguintes linhas devem estar na origem da DLL de extensão do 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
}
Não se esqueça de exportar a função InitYourExtDLL. Você pode usar __declspec(dllexport)
ou exportá-lo no arquivo DEF da sua DLL, conforme mostrado aqui:
// YourExtDLL.Def:
LIBRARY YOUREXTDLL
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD SINGLE
EXPORTS
InitYourExtDLL
Adicione uma chamada ao membro InitInstance
do objeto derivado de CWinApp
em cada DLL regular do MFC usando a DLL de extensão do 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;
}