TN033: Versione della DLL di MFC

Questa nota viene descritto come è possibile utilizzare il file MFCxx. dll e MFCxxD. dll (dove x è il numero di versione MFC) condiviso librerie a collegamento dinamico con applicazioni MFC e dll di estensione. Per ulteriori informazioni su DLL regolari, vedere MFC usando come parte di una DLL.

Questa nota tecnica copre tre aspetti delle dll. Gli ultimi due sono per gli utenti più avanzati:

Se siete interessati a costruire una DLL utilizzando MFC che può essere utilizzato con applicazioni non MFC (questo è chiamato una DLL regolare), fare riferimento alla tecnica nota 11.

Panoramica di supporto MFCxx: terminologia e file

DLL regolare: si utilizza una DLL per generare una DLL stand-alone usando alcune delle classi MFC. Interfacce attraverso il limite di App/DLL sono interfacce "C", e l'applicazione client non deve essere un'applicazione MFC.

Questa è la versione di DLL di supporto supportato in MFC 1.0. Esso è descritto in 11 Note tecniche e il campione di MFC Advanced Concepts DLLTRACE.

&Notanbsp;  Di Visual C++ versione 4.0, il termine USRDLL è obsoleta ed è stata sostituita da una DLL regolare che collega in modo statico a MFC. Si può anche costruire una DLL regolare che collega dinamicamente a MFC.

MFC 3.0 (e sopra) supporta DLL regolari con tutte le nuove funzionalità tra cui le classi OLE e Database.

AFXDLL: questo è indicato anche come la versione condivisa delle librerie MFC. Questo è il nuovo supporto DLL aggiunto in MFC 2.0. Libreria MFC stessa è in un certo numero di dll (descritta sotto) e un'applicazione client o in una DLL collega dinamicamente le dll che esso richiede. Interfacce attraverso il limite di applicazione/DLL sono C + + / interfacce di classi MFC. L'applicazione client deve essere un'applicazione MFC. Questo supporta tutte le funzionalità di MFC 3.0 (excption: UNICODE non è supportato per le classi di database).

&Notanbsp;  Di Visual C++ versione 4.0, questo tipo di DLL viene definito come un' "estensione DLL".

Questa nota utilizzerà MFCxx per riferirsi all'intera DLL MFC impostato, che comprende:

&Notanbsp;  La MFCSxx [U] [D].LIB librerie vengono utilizzate in combinazione con MFC dll condivisa. Queste librerie contengono codice che deve essere collegato in modo statico all'applicazione o DLL.

Un'applicazione link alla corrispondente di librerie di importazione:

Un "MFC Extension DLL" è una DLL costruita su MFCxx (e/o altri MFC dll condivisa). Qui l'architettura a componenti MFC calci a. Se si deriva una classe utile da una classe MFC o costruire toolkit MFC-come un altro, è possibile inserire in un file DLL. Che DLL utilizza MFCxx. dll, come fa l'applicazione client finale. Ciò consente di classi riutilizzabili foglia, riutilizzabile classi base e classi di documento/vista riutilizzabili.

&Notanbsp;  Non è necessario per il collegamento con le MFCOxx [U] D, D MFCDxx [U] o MFCNxx [U] D Debug librerie a meno che l'applicazione utilizza la MFC/OLE, database o classi di rete rispettivamente.

Pro e contro

Perché si dovrebbe usare la versione condivisa di MFC?

Perché si dovrebbe non utilizzare la versione condivisa di MFC:

Come scrivere una DLL di estensione MFC

Una DLL di estensione MFC è una DLL che contiene classi e funzioni scritte per abbellire la funzionalità delle classi MFC. Il supporto di debug OLE e database DLLs (MFCOxxD. dll e MFCDxxD. dll) sono esempi di dll di estensione MFC in quanto usano MFCxxD. dll. Una DLL di estensione MFC utilizza le DLL MFC condivisa allo stesso modo che un'applicazione utilizza, con alcune considerazioni aggiuntive:

Queste considerazioni sono descritti in dettaglio qui sotto. È inoltre deve fare riferimento all'esempio MFC Advanced Concepts DLLHUSK poiché esso illustra

Sia l'applicazione client e tutte le dll di estensione devono utilizzare la stessa versione di MFCxx. Si dovrebbe seguire la convenzione della DLL MFC e fornire un debug e vendita al dettaglio (/ release) versione di DLL di estensione. Ciò consente di programmi client di costruire versioni di debug e di vendita al dettaglio delle loro applicazioni e collegarli con il debug appropriato o la versione finale di tutte le dll.

&Notanbsp;  A causa di C++ pressare e l'esportazione questione del nome, la lista di esportazione da una DLL di estensione può essere diversa tra le versioni di debug e al dettaglio di stessa DLL e dll per diverse piattaforme. Vendita al dettaglio MFCxx ha circa 2000 esportato i punti di ingresso; il debug MFCxxD. dll ha circa 3000 esportato punti di ingresso.

Breve nota sulla gestione della memoria

La sezione intitolata "Memory Management", vicino all'estremità di questa nota tecnica, descrive l'implementazione della MFCxx con la versione condivisa di MFC. Le informazioni che dovete sapere per implementare solo una DLL di estensione sono descritto qui.

MFCxx. dll e tutte le dll di estensione, caricate nello spazio di indirizzi di un'applicazione client utilizzeranno l'allocatore di memoria stessa, caricare risorse e altri Stati "globale" MFC come se fossero nella stessa applicazione. Questo è significativo, perché le librerie DLL non MFC e DLL regolare collegamento statico a MFC fare l'esatto contrario e avere ogni DLL di assegnazione di un proprio pool di memoria.

Se una DLL di estensione alloca memoria, allora che la memoria può liberamente intermix con qualsiasi altro oggetto allocato applicazione. Inoltre, se un'applicazione che utilizza le librerie MFC condivise si blocca, la protezione del sistema operativo manterrà l'integrità di qualsiasi altra applicazione MFC DLL di condivisione.

Allo stesso modo altri Stati MFC "globale", come il file eseguibile corrente per caricare risorse da, inoltre sono condivise tra l'applicazione client e tutte le dll di estensione MFC nonché MFCxx sé.

Costruzione di una DLL di estensione

È possibile utilizzare la creazione guidata applicazione per creare un progetto DLL di estensione MFC e genererà automaticamente il compilatore appropriato e impostazioni del linker. E ' stato anche generare una funzione DllMain che è possibile modificare.

Se si converte un progetto esistente a una DLL di estensione MFC, iniziare con le regole standard per la creazione di un'applicazione che utilizza la versione condivisa di MFC, quindi effettuare le seguenti operazioni:

Modificare i file di intestazione

L'obiettivo di un'estensione DLL è solitamente per esportare alcune funzionalità comuni in una o più applicazioni che possono utilizzare tale funzionalità. Questo si riduce a esportazione delle classi e funzioni globali che sono disponibili per applicazioni client.

A tal fine devono assicurare che ciascuna delle funzioni membro viene contrassegnata come importare o esportare come appropriato. Questo richiede dichiarazioni speciale: __declspec(dllexport) e declspec. Quando le classi sono utilizzate da applicazioni client, si desidera loro di essere dichiarato come declspec. Quando l'estensione DLL stessa è in fase di costruzione, deve essere dichiarati come __declspec(dllexport). Inoltre, le funzioni devono essere effettivamente esportate, così che i programmi client associare ad essi in fase di caricamento.

Per esportare la tua intera classe, utilizzare AFX_EXT_CLASS nella definizione della classe. Questa macro è definita dal quadro come __declspec(dllexport) quando AFXDLL e AFXEXT è definito, ma definito come declspec quando AFXEXT non è definito. AFXEXT come sopra descritto, è definita solo quando si costruisce la DLL di estensione. Ad esempio:

classe AFX_EXT_CLASS CExampleExport: CObject pubblica
{... classe di definizione...}

Non esportare la classe intera

A volte si desidera esportare solo i singoli membri necessari della vostra classe. Ad esempio, se si stanno esportando un CDialog-classe derivata solo potrebbe essere necessario esportare il costruttore e la chiamata DoModal . È possibile esportare questi membri utilizzando della DLL.File DEF, ma è anche possibile utilizzare AFX_EXT_CLASS più o meno allo stesso modo su singoli membri che è necessario esportare.

Ad esempio:

 classe CExampleDialog: CDialog pubblica
{
pubblica:
   AFX_EXT_CLASS CExampleDialog();
   AFX_EXT_CLASS int DoModal();
   / / riposo della definizione di classe
   .
   .
   .
}

Quando si esegue questa operazione, può incorrere in un altro problema dovuto al fatto che si esportano non più tutti i membri della classe. Il problema è nel modo che il lavoro delle macro MFC. In realtà, molte delle macro di aiutante di MFC dichiarare o definire membri dati. Pertanto, questi membri dati dovranno inoltre essere esportati dalla DLL.

Ad esempio, la macro DECLARE_DYNAMIC viene definita come segue durante la creazione di una DLL di estensione:

# define DECLARE_DY&NAMIC(class_name) \
protetto: \
 nbsp; _GetBaseClass() CRuntimeClass * PASCAL statico; \
   pubblico: \
   classe statica AFX_DATA CRuntimeClass # # class_name; \
   Virtual CRuntimeClass * GetRuntimeClass() const; \

La riga che inizia "statico AFX_DATA" dichiara un oggetto statico all'interno della classe. Per esportare correttamente questa classe e accedere alle informazioni di runtime da un client.EXE, è necessario esportare questo oggetto statico. Perché l'oggetto statico viene dichiarata con il modificatore AFX_DATA, solo bisogno di definire AFX_DATA essere __declspec(dllexport) quando si costruisce la DLL e definirlo come declspec quando si costruisce il vostro client eseguibile.

Come discusso in precedenza, AFX_EXT_CLASS è già definito in questo modo. Così solo bisogno di ridefinire AFX_DATA allo stesso AFX_EXT_CLASS circa la definizione della classe.

Ad esempio:

nbsp;  # undef AFX_DATA
   # define AFX_DATA AFX_EXT_CLASS
   classe CExampleView: CView pubblica
   {
     DECLARE_DY&NAMIC()
     / /... definizione di classe...
   };
   # undef AFX_DATA
   # define AFX_DATA

MFC utilizza sempre il simbolo AFX_DATA su elementi di dati che definisce all'interno della sua macro, così questa tecnica per tutti gli scenari di tali lavoro. Per esempio si lavorerà per DECLARE_MESSAGE_MAP.

&Notanbsp;  Se si stanno esportando l'intera classe anziché selezionati i membri della classe, i membri dati statici vengono automaticamente esportati.

È possibile utilizzare la stessa tecnica per esportare automaticamente l'operatore di estrazione CArchive per le classi che utilizzano le macro DECLARE_SERIAL e IMPLEMENT_SERIAL . Esportare l'operatore Archivio di bracketing le dichiarazioni di classe (situato nella.File H) con il seguente codice:

# undef AFX_API
# define AFX_API AFX_EXT_CLASS

lt; le dichiarazioni di classe qui >

# undef AFX_API
# define AFX_API

Limitazioni di AFXEXT

È possibile utilizzare il simbolo del preprocessore di _AFXEXT per le dll di estensione fino a quando non si dispone di più strati di dll di estensione. Se si dispone di estensione dll di chiamare o derivare dalle classi nella propria estensione dll, che quindi derivare dalle classi MFC, è necessario utilizzare il proprio simbolo del preprocessore per evitare ambiguità.

Il problema è che in Win32, devono dichiarare in modo esplicito i dati come __declspec(dllexport) se si vuole essere esportate da una DLL e declspec se si vuole essere importati da una DLL. Quando si definisce AFXEXT, le intestazioni MFC assicurarsi che AFX_EXT_CLASS è definita correttamente.

Quando si dispone di livelli multipli, un simbolo, come AFX_EXT_CLASS non è sufficiente, poiché una DLL di estensione può essere esportatori di nuove classi così come importare altre classi da un'altra estensione DLL. Per ovviare a questo problema, utilizzare un simbolo del preprocessore speciale che indica che stai costruendo la DLL rispetto all'utilizzo della DLL. Si supponga, ad esempio, le dll di estensione due, a. dll e b. dll. Ciascuno di essi Esporta alcune classi in esportano e B.H, rispettivamente. B. dll utilizza le classi da a. dll. I file di intestazione apparirebbe qualcosa di simile:

/ / ESPORTA&NO
# ifdef A_IMPL
 nbsp; # define CLASS_DECL_A __declspec(dllexport)
# else
   # define CLASS_DECL_A declspec
# endif

classe CLASS_DECL_A CExampleA: CObject pubblica
{... classe di definizione...};

/ / B.H
# ifdef B_IMPL
   # define CLASS_DECL_B __declspec(dllexport)
# else
   # define CLASS_DECL_B declspec
# endif

classe CLASS_DECL_B CExampleB: CExampleA pubblica
{... definizione di classe...}

Quando a. dll viene compilato, è costruito con /D A_IMPL e quando b. dll viene compilato, è costruito con /D B_IMPL. Utilizzando i simboli separati per ogni DLL, CExampleB viene esportato e CExampleA viene importato durante la creazione di b. dll. CExampleA viene esportato quando si costruisce a. dll e importato quando viene utilizzato da b. dll (o qualche altro client).

Questo tipo di stratificazione non può essere fatto utilizzando i simboli del preprocessore incorporati AFX_EXT_CLASS e AFXEXT . La tecnica descritta sopra risolve questo problema in modo non diverso che il meccanismo MFC si utilizza quando si costruisce la sua estensione OLE, Database e Network DLLs.

Non esportare la classe intera

Ancora una volta si dovrà prestare particolare attenzione quando si esportano non un'intera classe. È necessario garantire che gli elementi di dati necessari creati dalle macro MFC vengono esportati correttamente. Questo può essere fatto da ridefinendo AFX_DATA macro tua classe di specifica. Questo dovrebbe essere fatto ogni volta che si esportano non l'intera classe.

Ad esempio:

/ / ESPORTA&NO
# ifdef A_IMPL
 nbsp; # define CLASS_DECL_A _declspec(dllexport)
# else
   # define CLASS_DECL_A _declspec(dllimport)
   # endif

# undef AFX_DATA
# define AFX_DATA CLASS_DECL_A

classe CExampleA: CObject pubblica
{
   DECLARE_DYNAMIC()
   CLASS_DECL_A int SomeFunction();
   //class definizione.
   .
   .
};

# undef AFX_DATA
# define AFX_DATA

DllMain

Di seguito è riportato il codice esatto che è necessario posizionare nel file principale fonte per la DLL di estensione. Dovrebbe venire dopo lo standard comprende. Si noti che quando si utilizza la creazione guidata applicazione per creare file di avviamento per una DLL di estensione, esso fornisce una DllMain per te.

# include "Afxdllx. h"

statico AFX_EXTE&NSION_MODULE extensionDLL;

extern "C" int APIENTRY DllMain (HINSTANCE hInstance, DWORD dwReason, LPVOID)
{
 nbsp; Se (dwReason = = DLL_PROCESS_ATTACH)
   {
      / / Inizializzazione unica estensione DLL se (!AfxInitExtensionModule (
             extensionDLL, hInstance))
         return 0;

/ / TODO: eseguire altre operazioni di inizializzazione qui
   }
   else if (dwReason = = DLL_PROCESS_DETACH)
   {
      / / DLL di estensione per processo di terminazione
      AfxTermExtensionModule(extensionDLL);

/ / TODO: eseguire altre operazioni di pulitura qui
   }
   restituire 1;   / / ok
}

La chiamata a AfxInitExtensionModule acquisisce il runtime-classi di moduli (struttureCRuntimeClass ) nonché le object factory (oggettiCOleObjectFactory ) da utilizzare successivamente quando viene creato l'oggetto CDynLinkLibrary . La chiamata a AfxTermExtensionModule (opzionale) permette MFC di pulitura DLL di estensione quando ogni processo disconnette (il che accade quando il processo si chiude o quando la DLL venga scaricata come risultato di una chiamata FreeLibrary ) dalla DLL di estensione. Dal maggior estensione dll non vengono caricate in modo dinamico (di solito, essi sono collegati tramite proprie librerie di importazione), la chiamata a AfxTermExtensionModule non è solitamente necessaria.

Se l'applicazio&ne viene caricato e libera le dll di estensione in modo dinamico, assicurarsi di chiamare AfxTermExtensionModule come mostrato above.nbsp; Anche essere sicuri di utilizzare AfxLoadLibrary e AfxFreeLibrary (invece di funzioni Win32 LoadLibrary e FreeLibrary), se l'applicazione utilizza più thread. Utilizzando AfxLoadLibrary e AfxFreeLibrary assicura che il codice di avvio e di arresto che viene eseguito quando la DLL di estensione è caricati e scaricati non corrotto lo stato globale MFC.

Il file di intestazione AFXDLLX.H contiene definizioni speciali per le strutture utilizzate nelle DLL di estensione, come la definizione per AFX_EXTENSION_MODULE e CDynLinkLibrary.

Il global extensionDLL deve essere dichiarato come mostrato. A differenza della versione a 16-bit di MFC, è possibile allocare memoria e chiamare funzioni MFC durante questo periodo, dato che il MFCxx è completamente inizializzato con il tempo che si chiama il tuo DllMain.

Condivisione di risorse e classi

Le dll di estensione MFC semplice bisogno di esportare solo alcune funzioni di larghezza di banda ridotta per l'applicazione client e nulla più. Ulteriori dll intensivo di interfaccia utente potrebbe voler esportare le risorse e le classi C++ all'applicazione client.

Esportare le risorse avviene attraverso un elenco di risorse. In ogni applicazione è un elenco collegato all'unità di oggetti CDynLinkLibrary . Quando la ricerca di una risorsa, la maggior parte delle implementazioni MFC standard che carico risorse cerca innanzitutto nel modulo di risorsa corrente (AfxGetResourceHandle) e se non trovato a piedi l'elenco di oggetti CDynLinkLibrary durante il tentativo di caricare la risorsa richiesta.

Creazione dinamica di oggetti C++ assegnato un nome di classe C++ è simile. Il meccanismo di deserializzazione di oggetti MFC deve disporre di tutti gli oggetti CRuntimeClass registrati in modo che può ricostruire creando dinamicamente C++ oggetto del tipo richiesto basato su quello che era stato salvato in precedenza.

Se si desidera che l'applicazione client di utilizzare classi nell'estensione DLL che sono DECLARE_SERIAL, allora avete bisogno di esportare le classi sia visibile all'applicazione client. Anche a tale scopo l'elenco CDynLinkLibrary.

Nel caso dell'esempio MFC Advanced Concepts DLLHUSK, la lista sembra qualcosa di simile

testa - gt;   DLLHUSK.EXE - o - DLLHUSK.EXE
               |                      |
          TESTDLL2.DLL TESTDLL2.DLL
               |                      |
          OPERAZIONI VEN&GONO EFFETTUATE.DLL TESTDLL1.DLL
               |                      |
           MFCO42D.DLL                |
               |                      |
           MFCD42D.DLL                |
               |                      |
            MFC42D.DLL MFC42.DLL

Il MFCxx è solitamente l'ultimo sull'elenco delle risorse e classe. MFCxx include tutte le risorse MFC standard, tra cui stringhe pronta per tutti gli ID di comando standard. Mettendolo in coda alla lista permette di dll e l'applicazione client per non avere una propria copia delle risorse MFC standard, ma invocare le risorse condivise nella MFCxx invece.

Unire le risorse e i nomi di tutte le dll delle classi nello spazio dei nomi dell'applicazione client ha lo svantaggio che si deve fare attenzione a ciò che gli ID o scegliere nomi. È naturalmente possibile disattivare questa funzionalità non esportare o le vostre risorse o un oggetto CDynLinkLibrary all'applicazione client. La esempio DLLHUSK gestisce spazio dei nomi di risorsa condivisa utilizzando più file di intestazione. Vedi tecnica nota 35 per ulteriori suggerimenti sull'utilizzo di file di risorse condivise.

L'inizializzazione della DLL

Come sopra accennato, di solito si desidererà creare un oggetto CDynLinkLibrary per esportare le vostre classi e risorse all'applicazione client. Sarà necessario fornire un punto di ingresso esportato per inizializzare la DLL. Minimamente questo è una routine void che non accetta argomenti e restituisce nothing, ma può essere qualcosa che ti piace.

Ogni applicazione client che desideri utilizzare la DLL deve chiamare questa routine di inizializzazione, se si utilizza questo approccio. Può anche assegnare questo oggetto CDynLinkLibrary nel vostro DllMain solo dopo la chiamata a AfxInitExtensionModule.

La routine di inizializzazione è necessario creare un oggetto CDynLinkLibrary nell'heap dell'applicazione corrente, cablato fino a tua estensione informazioni DLL. Questo può essere fatto con il seguente:

extern "C" extern void WI&NAPI InitXxxDLL()
{
 nbsp; nuovo CDynLinkLibrary(extensionDLL);
}

Il nome della routine, InitXxxDLL in questo esempio, può essere tutto quello che vuoi. Essa non ha bisogno di essere extern “C” , ma facendo così fa l'elenco di esportazione più facile da mantenere.

&Notanbsp;  Se si utilizza la DLL da una DLL di estensione, è necessario esportare questa funzione di inizializzazione. Questa funzione deve essere chiamata dal DLL regolare prima di utilizzare qualsiasi estensione DLL classi o risorse.

Esportare le voci

Il modo semplice per esportare le classi è di utilizzare declspec e __declspec(dllexport) su ogni classe e funzione globale che si desidera esportare. Questo rende molto più facile, ma è meno efficiente di ciascun punto di ingresso (descritta sotto) di denominazione, dal momento che avete meno controllo su quali funzioni ottenere esportati e voi non può esportare le funzioni numero ordinale. Questo è il metodo che queste operazioni vengono effettuate sia TESTDLL2 utilizzare per esportare le loro voci.

Un metodo più efficiente (e il metodo utilizzato dal file MFCxx. dll) è quello di esportare ogni voce a mano nominando ogni voce della.File DEF. Poiché stiamo esportando selettive delle esportazioni dalla nostra DLL (cioè, non tutto), noi dobbiamo decidere quali interfacce particolare vogliamo esportare. Questo è difficile, poiché è necessario specificare i nomi storpiati al linker sotto forma di voci nella.File DEF. Non esportare qualsiasi classi C++, a meno che non davvero bisogno di avere un collegamento simbolico per esso.

Se avete provato esportando C++ classi con un.Prima, si potrebbe voler sviluppare uno strumento per generare automaticamente questo elenco di file DEF. Questo può essere fatto utilizzando un processo di collegamento di due fasi. Collegare la DLL una volta con delle esportazioni, e permettono al linker di generare una.File di mappa. I.MAPPA file può essere utilizzato per generare un elenco di funzioni che dovrebbero essere esportato, quindi con alcuni munging, può essere utilizzato per generare le voci di esportazione per la tua.File DEF. La lista di esportazione per MFCxx e OLE di dll di estensione di Database, diverse migliaia di numero, è stata generata con un tale processo (anche se non è completamente automatico e richiede qualche mano disegna ogni tanto un po ').

CWinApp vs CDynLinkLibrary

Una DLL di estensione MFC non dispone di un CWinApp-derivato oggetto della propria; invece si deve lavorare con il CWinApp-derivato oggetto dell'applicazione client. Ciò significa che l'applicazione client possiede il message pump principale, il ciclo idle e così via.

Se la DLL di estensione MFC deve mantenere dati aggiuntivi per ogni applicazione, è possibile derivare una nuova classe da CDynLinkLibrary e crearlo in routine di descrivere sopra il InitXxxDLL. Durante l'esecuzione, la DLL può controllare la lista dell'applicazione corrente di oggetti CDynLinkLibrary per trovare quello per quella particolare estensione DLL.

Utilizzo delle risorse nell'implementazione DLL

Come già accennato, il carico delle risorse predefinite guiderà l'elenco di oggetti CDynLinkLibrary cercando il primo EXE o DLL che ha la risorsa richiesta. Tutte le API di MFC, così come tutto il codice interno utilizza AfxFindResourceHandle per scorrere l'elenco delle risorse per trovare tutte le risorse, non importa dove può risiedere.

Se si desidera caricare solo le risorse da una posizione specifica, utilizzare le API AfxGetResourceHandle e AfxSetResourceHandle per salvare l'handle precedente e impostare quello nuovo. Assicurarsi di ripristinare l'handle di risorsa precedente prima di tornare all'applicazione client. L'esempio TESTDLL2 utilizza questo approccio per il caricamento in modo esplicito un menu.

L'elenco ha gli svantaggi che è leggermente più lento e richiede la gestione delle gamme di ID di risorsa. Essa ha il vantaggio che un'applicazione client che si collega a diverse DLL di estensione può utilizzare qualsiasi risorsa fornita DLL senza dover specificare l'handle di istanza della DLL. AfxFindResourceHandle è un'API utilizzata per l'elenco delle risorse per cercare una data corrispondenza. Prende il nome e il tipo di una risorsa e restituisce l'handle di risorsa cui è stato trovato in primo luogo (o NULL).

Scrittura di un'applicazione che utilizza la versione della DLL

Requisiti dell'applicazione

Un'applicazione che utilizza la versione condivisa di MFC deve seguire alcune semplici regole:

Edificio con l'ambiente di sviluppo

Se si utilizza il makefile interno con i valori predefiniti standard per la maggior parte, si può facilmente cambiare il progetto per costruire la versione della DLL.

Il passo seguente presuppone un'applicazione MFC correttamente funzionante collegata con NAFXCWD.LIB (per debug) e NAFXCW.LIB (per la vendita al dettaglio) e si desidera convertirlo per utilizzare la versione condivisa della libreria MFC. Si utilizza l'ambiente di Visual C++ e dispone di un file di progetto interno.

  1. Scegliere impostazioni dal menu. Nella pagina generale sotto le impostazioni del progetto, impostare Microsoft Foundation Classes su uso MFC in una DLL condivisa (MFCxx(d).dll).

Edificio con NMAKE

Se si utilizza la funzionalità esterne makefile di Visual C++ o utilizza NMAKE direttamente, si dovrà modificare il makefile a supporto del compilatore e opzioni del linker

Flag del compilatore richiesto:

/ /MD D_AFXDLL

/ D_AFXDLL

L'header standard MFC bisogno questo simbolo da definirsi:

/MD

L'applicazione deve utilizzare la versione della DLL della libreria di runtime di c

Tutti gli altri flag del compilatore seguire i valori di default MFC (ad esempio, debug per debug).

Modificare l'elenco del linker delle librerie. Cambiamento NAFXCWD.LIB per MFCxxD.LIB e cambiare NAFXCW.LIB per MFCxx.LIB. Aggiungi MFCOxx[U]D.LIB, MFCDxx[U]D.LIB e MFCNxx[U]D.LIB come appropriato (obbligatorio per con uso della MFC/OLE, database o classi di rete). Sostituire LIBC.LIB con MSVCRT.LIB. Come con qualsiasi altra libreria MFC è importante che MFCxxD.LIB è posto prima di eventuali librerie di runtime c.

Se lo si desidera aggiungere /D_AFXDLL a entrambi il commercio al dettaglio e debug opzioni del compilatore di risorse (quello che in realtà compila le risorse con /R). Questo rende il vostro eseguibile finale più piccoli condividendo le risorse che sono presenti in DLL MFC.

Una rigenerazione completa è necessaria dopo che tali modifiche.

Generazione degli esempi

La maggior parte dei programmi MFC campione possono essere costruita da Visual C++ o da un MAKEFILE compatibile con NMAKE condiviso dalla riga di comando.

Per convertire qualsiasi di questi campioni ad utilizzare il file MFCxx. dll, è possibile caricare la.MAK file in Visual C++ e impostare le opzioni di progetto come descritto sopra. Se si utilizza la build NMAKE, è possibile specificare "AFXDLL = 1" sulla NMAKE riga di comando e che costruirà il campione usando le librerie MFC condivise.

L'esempio MFC Advanced Concepts DLLHUSK è costruito con la versione della DLL di MFC. Questo esempio non solo viene illustrato come creare un'applicazione collegata con MFCxx, ma illustra anche altre caratteristiche dell'opzione imballaggio DLL MFC, come descritto più avanti in questa nota tecnica le dll di estensione MFC.

Note di imballaggio

La versione finale delle dll (MFCxx [U].DLL) sono liberamente redistribuibili. La versione di debug delle dll non sono liberamente redistribuibile e deve essere utilizzato solo durante lo sviluppo dell'applicazione.

Il debug le dll sono forniti con informazioni di debug. Usando il debugger di Visual C++, è possibile analizzare l'esecuzione dell'applicazione, nonché la DLL. Le dll di rilascio (MFCxx [U].DLL) non contengono informazioni di debug.

Se si personalizza o ricostruire le dll, è necessario chiamare loro qualcosa di diverso da file "MFCxx" The MFC SRC MFCDLL.MAK descrive le opzioni di compilazione e contiene la logica per la ridenominazione dei DLL. Questa regola vale anche per il MFC/OLE, database e rete le dll sono costruiti dalla MFCOLE.MAK, MFCDB.MAK e MFCNET.MAK, rispettivamente. Rinominare i file è necessario, dal momento che queste dll sono potenzialmente condivisi da diverse applicazioni MFC. Avendo la versione personalizzata di DLL MFC sostituire quelli installati sul sistema può rompere un'altra applicazione MFC usando le dll condivisa di MFC.

Ricostruzione DLL MFC non è raccomandato.

Come è implementato il file MFCxx. dll

La sezione seguente descrive come viene attuata la DLL MFC (MFCxx e MFCxxD. dll). Comprendere che i dettagli qui non sono inoltre importante se tutto quello che voglio fare è utilizzare la DLL MFC con l'applicazione. I dettagli qui non sono essenziali per la comprensione di come scrivere una DLL di estensione MFC, ma la comprensione di questa implementazione può aiutare a scrivere la DLL proprio.

Cenni preliminari sull'attuazione

La DLL MFC è davvero un caso speciale di una DLL di estensione MFC, come descritto in precedenza. Essa ha un numero molto elevato di esportazioni per un gran numero di classi. Ci sono poche cose aggiuntive che facciamo nella DLL MFC che lo rendono ancora più speciale che un'estensione DLL.

Win32 fa la maggior parte del lavoro

La versione a 16 bit di MFC aveva bisogno di un certo numero di tecniche speciali, compresi i dati di al-app sul segmento dello stack, segmenti speciali creati da qualche codice assembly di 80 x 86, contesti di eccezione per processo e altre tecniche. Win32 supporta direttamente per elaborazione dati in una DLL, che è ciò che volete la maggior parte del tempo. Per la maggior parte MFCxx è solo NAFXCW.LIB confezionato in una DLL. Se si esamina il codice sorgente MFC, troverete pochissimi # ifdef AFXDLL, visto che ci sono pochissimi casi particolari che devono essere prese. I casi particolari che sono ci sono specificamente a che fare con Win32 su Windows 3.1 (altrimenti noto come Win32s). Win32s fa non supporto per processo DLL dati direttamente così la DLL MFC devono utilizzare l'archiviazione locale di thread (TLS) API Win32 per ottenere dati locali di processo.

Impatto sulla libreria fonti, file aggiuntivi

L'impatto della versione AFXDLL sui normali fonti di biblioteca classe MFC e intestazioni è relativamente minore. C'è un versione speciale file (AFXV_DLL.H) come un file di intestazione aggiuntiva (AFXDLL_.H) inclusi i principali AFXWIN.Intestazione H. Il AFXDLL_.H intestazione include la classe CDynLinkLibrary e altri dettagli di implementazione di applicazioni AFXDLL e di dll di estensione MFC. Il AFXDLLX.Intestazione h è fornito per la costruzione di dll di estensione MFC (vedi sopra per i dettagli).

Le fonti regolare alla libreria MFC in MFC SRC hanno qualche ulteriore codice condizionale sotto il # ifdef AFXDLL . Un file di origine aggiuntivo (DLLINIT.CPP) contiene il codice di inizializzazione aggiuntivo DLL e altri colla per la versione condivisa di MFC.

Al fine di costruire la versione condivisa di MFC, vengono forniti ulteriori file. (Vedi sotto per i dettagli su come costruire la DLL).

Costruzione DLL MFC

Ricostruzione DLL MFC è intenzionalmente difficile, quindi pensa due volte (o tre volte) prima di farlo. Se capisco i potenziali problemi di imballaggio e ridistribuzione restrizioni descritte di seguito e voi ancora veramente bisogno di ricostruire la DLL MFC, è possibile.

Il MFCDLL.File MAK costruirà la DLL di Debug con CodeView info:

NMAKE /f mfcdll.mak DEBUG = 1 LIBNAME = MYMFC

Il MFCDLL.File MAK costruirà la DLL di rilascio senza CodeView info:

NMAKE /f mfcdll.mak DEBUG = 0 LIBNAME = MYMFC

(allo stesso modo, utilizzare MFCOLE.MAK, MFCDB.MAK e MFCNET.MAK per costruire il MFCOxxD. dll, MFCDxxD. dll e MFCNxxD. dll - dll che contengono la MFC/OLE, database e classi di rete)

Questo costruisce una versione privata della DLL nella directory SRC MFC con i nomi standard MFCxx e MFCxxD. dll MFC. Sarà necessario copiarle in un posto adatto sul vostro cammino di utilizzare le dll di nuove. Il MFCDLL.MAK makefile anche ricostruire le librerie di importazione (MFCxx.LIB e MFCxxD.LIB) e inserirli nella directory LIB MFC standard. Questo lo sostituirà le librerie predefinite di MFCxx.LIB e MFCxxD.LIB, quindi fate attenzione.

Se si desidera ridistribuire una versione modificata della libreria DLL MFC, assicurati di cambiare il nome della DLL nella MFCDLL.MAK makefile e i due.File DEF. Vedere il makefile MFCDLL.MAK per maggiori informazioni.

Puoi modificare la libreria e ridistribuire un dettaglio (/ release) della tua biblioteca modificata solo se si rinominarlo in qualcosa di diverso da MFCxx. Non può ridistribuire la versione di debug di entrambi il pre-costruito o personalizzato costruito debug DLL.

Queste restrizioni di ridistribuzione sono principalmente per evitare una proliferazione di non standard e potenzialmente virus contenente le dll. idealmente dovrebbe non è necessario ricostruire le dll e se si ridistribuisce l'applicazione con il MFCxx predefiniti forniti con il prodotto di Visual C++, si eviterà un sacco di problemi per voi e i vostri utenti.

Gestione della memoria

Un'applicazione che utilizza MFCxx utilizza un allocatore di memoria comuni fornito da MSVCRTxx.DLL, la DLL di runtime c condivisa. Sia l'applicazione, qualsiasi dll di estensione, nonché la DLL MFC, utilizzare questo allocatore di memoria condivisa. Utilizzando una DLL per l'allocazione di memoria condivisa, DLL MFC possibile allocare memoria, che più tardi è liberato dall'applicazione o viceversa. Poiché l'applicazione e la DLL deve utilizzare l'allocatore stesso, è non dovrebbe ignorare il C++ globale operatore new o operatore delete. Le stesse regole si applicano al resto delle routine di allocazione di memoria di runtime C (ad esempio malloc, realloc, libero, ecc.).

Ordinali e la classe __declspec(dllexport) e la denominazione DLL

Non usiamo la class __declspec(dllexport) funzionalità del compilatore C++. Invece, un elenco delle esportazioni è incluso con le origini della biblioteca di classe (MFCxx.DEF e MFCxxD.DEF). Solo questi specifico insieme di punti di ingresso (funzioni e dati) vengono esportati. Altri simboli, come funzioni MFC implementazione privato o classi, non vengono esportati tutte le esportazioni sono fatte dalla ordinale senza un nome di stringa nella tabella dei nomi residente o non residente .

Utilizzando class __declspec(dllexport) può essere una valida alternativa per la costruzione di piccoli DLLs, ma nel caso di una DLL di grandi dimensioni come MFC, esportando il meccanismo predefinito ha l'efficienza e la capacità limiti .

Questo significa che tutti è che noi possiamo pacchetto una grande quantità di funzionalità nella versione MFCxx che è solo circa 800 KByte senza compromettere molto l'esecuzione o la velocità di caricamento. MFCxx sarebbe stato più grande 100k questa tecnica non era stato utilizzato.Questo rende anche possibile aggiungere punti di ingresso supplementare alla fine dei.File DEF per consentire la semplice gestione delle versioni senza compromettere l'efficienza velocità e le dimensioni dell'esportazione di numero ordinale. Revisioni di versione principale nella libreria di classi MFC cambierà il nome della libreria. Cioè, MFC30.DLL è la DLL ridistribuibile contenente la versione 3.0 di libreria di classi MFC. Un aggiornamento di questa DLL, dire, in un ipotetico MFC 3.1, la DLL potrebbe essere chiamata MFC31.DLL invece. Ancora una volta, se si modifica il codice sorgente MFC per produrre una versione personalizzata della DLL MFC, utilizzare un nome diverso (e preferibilmente uno senza "MFC") nel nome.

&Note tecniche per numero |nbsp; Note tecniche per la categoria

Index