MFC (DLL di estensione)
Una DLL di estensione MFC è una DLL che in genere implementa classi riutilizzabili derivate dalle classi esistenti di Microsoft Foundation Class Library.
Una DLL di estensione MFC presenta le funzionalità e i requisiti seguenti:
L'eseguibile client deve essere un'applicazione MFC compilata con
_AFXDLL
definito.Una DLL di estensione MFC può essere usata anche da una normale DLL MFC collegata dinamicamente a MFC.
Le DLL dell'estensione MFC devono essere compilate con
_AFXEXT
definito. Ciò impone_AFXDLL
anche di essere definito e garantisce che le dichiarazioni appropriate vengano estratte dai file di intestazione MFC. Garantisce anche cheAFX_EXT_CLASS
sia definito come__declspec(dllexport)
durante la compilazione della DLL, che è necessario se si usa questa macro per dichiarare le classi nella DLL dell'estensione MFC.Le DLL dell'estensione MFC non devono creare un'istanza di una classe derivata da
CWinApp
, ma devono basarsi sull'applicazione client (o DLL) per fornire questo oggetto.Le DLL dell'estensione MFC devono tuttavia fornire una
DllMain
funzione ed eseguire qualsiasi inizializzazione necessaria.
Le DLL di estensione vengono compilate usando la versione della libreria a collegamento dinamico di MFC (nota anche come versione condivisa di MFC). Solo i file eseguibili MFC (applicazioni o DLL MFC normali) compilati con la versione condivisa di MFC possono usare una DLL di estensione MFC. Sia l'applicazione client che la DLL dell'estensione MFC devono usare la stessa versione di MFCx0.dll. Con una DLL di estensione MFC, è possibile derivare nuove classi personalizzate da MFC e quindi offrire questa versione estesa di MFC alle applicazioni che chiamano la DLL.
Le DLL di estensione possono essere usate anche per passare oggetti derivati da MFC tra l'applicazione e la DLL. Le funzioni membro associate all'oggetto passato esistono nel modulo in cui è stato creato l'oggetto. Poiché queste funzioni vengono esportate correttamente quando si usa la versione DLL condivisa di MFC, è possibile passare liberamente puntatori a oggetti derivati da MFC o MFC tra un'applicazione e le DLL di estensione MFC caricate.
Una DLL di estensione MFC usa una versione condivisa di MFC nello stesso modo in cui un'applicazione usa la versione DLL condivisa di MFC, con alcune considerazioni aggiuntive:
Non dispone di un
CWinApp
oggetto derivato da . Deve funzionare con l'oggettoCWinApp
derivato da -dell'applicazione client. Ciò significa che l'applicazione client è proprietaria del message pump principale, del ciclo di inattività e così via.AfxInitExtensionModule
Chiama nella funzioneDllMain
. Il valore restituito di questa funzione deve essere controllato. Se viene restituito un valore zero daAfxInitExtensionModule
, restituire 0 dallaDllMain
funzione.Crea un oggetto CDynLinkLibrary durante l'inizializzazione se la DLL dell'estensione MFC vuole esportare
CRuntimeClass
oggetti o risorse nell'applicazione.
Prima della versione 4.0 di MFC, questo tipo di DLL era denominato AFXDLL. AFXDLL fa riferimento al simbolo del _AFXDLL
preprocessore definito durante la compilazione della DLL.
Le librerie di importazione per la versione condivisa di MFC vengono denominate in base alla convenzione descritta in Convenzioni di denominazione per le DLL MFC. Visual Studio fornisce versioni predefinite delle DLL MFC, oltre a una serie di DLL non MFC che è possibile usare e distribuire con le applicazioni. Questi sono documentati in Redist.txt, che viene installato nella cartella Programmi\Microsoft Visual Studio.
Se si esporta usando un file con estensione def, inserire il codice seguente all'inizio e alla fine del file di intestazione:
#undef AFX_DATA
#define AFX_DATA AFX_EXT_DATA
// <body of your header file>
#undef AFX_DATA
#define AFX_DATA
Queste quattro righe assicurano che il codice venga compilato correttamente per una DLL di estensione MFC. L'uscita da queste quattro righe potrebbe causare la compilazione o il collegamento della DLL in modo errato.
Se è necessario passare un puntatore a oggetti derivato da MFC o MFC da o verso una DLL MFC, la DLL deve essere una DLL di estensione MFC. Le funzioni membro associate all'oggetto passato esistono nel modulo in cui è stato creato l'oggetto. Poiché queste funzioni vengono esportate correttamente quando si usa la versione DLL condivisa di MFC, è possibile passare liberamente puntatori a oggetti derivati da MFC o MFC tra un'applicazione e le DLL di estensione MFC caricate.
A causa di problemi di mangling ed esportazione dei nomi C++, l'elenco di esportazione da una DLL di estensione MFC potrebbe essere diverso tra le versioni di debug e di vendita al dettaglio della stessa DLL e DLL per piattaforme diverse. Il MFCx0.dll al dettaglio ha circa 2.000 punti di ingresso esportati; il debug MFCx0D.dll ha circa 3.000 punti di ingresso esportati.
Gestione della memoria
MFCx0.dll e tutte le DLL di estensione MFC caricate nello spazio indirizzi di un'applicazione client usano lo stesso allocatore di memoria, il caricamento delle risorse e altri stati globali MFC come se fossero nella stessa applicazione. Ciò è significativo perché le librerie DLL non MFC e le normali DLL MFC eseguono esattamente l'opposto e hanno ogni DLL allocata dal proprio pool di memoria.
Se una DLL di estensione MFC alloca memoria, tale memoria può essere liberamente intermixato con qualsiasi altro oggetto allocato dall'applicazione. Inoltre, se un'applicazione che si collega dinamicamente a MFC non riesce, la protezione del sistema operativo mantiene l'integrità di qualsiasi altra applicazione MFC che condivide la DLL.
Analogamente, altri stati MFC globali, come il file eseguibile corrente da cui caricare le risorse, vengono condivisi anche tra l'applicazione client e tutte le DLL di estensione MFC, nonché MFCx0.dll stesso.
Condivisione di risorse e classi
L'esportazione delle risorse viene eseguita tramite un elenco di risorse. Ogni applicazione contiene un elenco di oggetti CDynLinkLibrary collegati singolarmente. Quando si cerca una risorsa, la maggior parte delle implementazioni MFC standard che caricano le risorse esamina prima il modulo di risorsa corrente (AfxGetResourceHandle
) e se la risorsa non viene trovata nell'elenco degli oggetti CDynLinkLibrary che tentano di caricare la risorsa richiesta.
L'elenco a piedi presenta gli svantaggi che è leggermente più lento e richiede la gestione degli intervalli di ID risorsa. Ha il vantaggio che un'applicazione client che collega diverse DLL di estensione MFC può usare qualsiasi risorsa fornita da DLL senza dover specificare l'handle dell'istanza dll. AfxFindResourceHandle
è un'API usata per l'spostamento dell'elenco di risorse per cercare una determinata corrispondenza. Accetta il nome e il tipo di una risorsa e restituisce l'handle di risorsa in cui è stato trovato per la prima volta (o NULL).
Se non si vuole esaminare l'elenco e caricare solo le risorse da una posizione specifica, usare le funzioni AfxGetResourceHandle
e AfxSetResourceHandle
salvare l'handle precedente e impostare il nuovo handle. Assicurarsi di ripristinare l'handle di risorse precedente prima di tornare all'applicazione client. Per un esempio di utilizzo di questo approccio per caricare in modo esplicito un menu, vedere Testdll2 .cpp nell'esempio MFC DLLHUSK.
La creazione dinamica di oggetti MFC in base a un nome MFC è simile. Il meccanismo di deserializzazione dell'oggetto MFC deve avere tutti gli CRuntimeClass
oggetti registrati in modo che possa ricostruire creando dinamicamente oggetti C++ del tipo richiesto in base a quanto archiviato in precedenza.
Nel caso dell'esempio MFC DLLHUSK, l'elenco ha un aspetto simile al seguente:
head -> DLLHUSK.EXE - or - DLLHUSK.EXE
| |
TESTDLL2.DLL TESTDLL2.DLL
| |
TESTDLL1.DLL TESTDLL1.DLL
| |
MFCOxxD.DLL |
| |
MFCDxxD.DLL |
| |
MFCxxD.DLL MFCxx.DLL
dove xx è il numero di versione, ad esempio 42 rappresenta la versione 4.2.
Il MFCxx.dll è in genere l'ultimo nell'elenco di risorse e classi. MFCxx.dll include tutte le risorse MFC standard, incluse le stringhe di prompt per tutti gli ID dei comandi standard. Posizionarlo alla fine dell'elenco consente alle DLL e all'applicazione client stessa di non avere la propria copia delle risorse MFC standard, ma di basarsi sulle risorse condivise nel MFCxx.dll.
L'unione delle risorse e dei nomi di classe di tutte le DLL nello spazio dei nomi dell'applicazione client presenta lo svantaggio di richiedere attenzione agli ID o ai nomi scelti.
L'esempio DLLHUSK gestisce lo spazio dei nomi delle risorse condivise usando più file di intestazione.
Se la DLL dell'estensione MFC deve mantenere dati aggiuntivi per ogni applicazione, è possibile derivare una nuova classe da CDynLinkLibrary e crearla in DllMain
. Durante l'esecuzione, la DLL può controllare l'elenco di oggetti CDynLinkLibrary dell'applicazione corrente per trovare quello per la DLL dell'estensione MFC specifica.