Share via


TN033: Versione DLL di MFC

Questa nota viene illustrato come utilizzare le librerie a collegamento dinamico condivise di MFCxxD.DLL e di versione (dove x rappresenta il numero di versione MFC) con le applicazioni e le DLL di estensione MFC.Per ulteriori informazioni sulle DLL regolari, vedere Utilizzo di MFC come parte di una DLL.

Questa nota tecnica vengono descritti tre aspetti delle DLL.Gli ultimi due sono per gli utenti più avanzati:

  • Come si compila una DLL di estensione MFC

  • La compilazione di un'applicazione MFC che utilizza la versione DLL di MFC

  • Come le librerie a collegamento dinamico condivise MFC vengono implementate

Se si esegue costruzione interessato da una DLL utilizzando MFC che può essere utilizzato con non MFC le applicazioni (questo è noto come DLL regolare), fare riferimento a nota tecnica 11.

Cenni preliminari sul supporto di versione: terminologia e file

Regular DLL: Utilizzare una DLL regolare per compilare una DLL autonomo utilizzando alcune delle classi MFC.Le interfacce attraverso il limite di App/DLL sono interfacce “c„ e l'applicazione client non sia un'applicazione MFC.

L'esempio è la versione del supporto di DLL supportata in MFC 1,0.Viene descritto in nota tecnica 11 e i concetti avanzati MFC illustrati DLLScreenCap.

[!NOTA]

A partire da Visual C++ versione 4,0, il termine USRDLL è obsoleto e è stato sostituito da una DLL regolare con collegamento statico a MFC.È anche possibile compilare una DLL regolare collegata a MFC in modo dinamico.

MFC 3,0 (e in) supporta le DLL regolari con qualsiasi nuova funzionalità incluse in OLE e le classi di database.

AFXDLL: Ciò è anche detto la versione condivisa delle librerie MFC.Si tratta del nuovo supporto di DLL aggiunto in MFC 2,0.La libreria MFC stessa è in alcune DLL (descritti di seguito) e un'applicazione client o una DLL collegata in modo dinamico le DLL necessarie.Le interfacce attraverso il limite di application/DLL sono interfacce di classe di C++/MFC.L'applicazione client DEVE essere un'applicazione MFC.Questo supporta tutte le funzionalità di MFC 3,0 (eccezione: UNICODE non è supportato per le classi di database).

[!NOTA]

A partire da Visual C++ versione 4,0, questo tipo di DLL è nota come “DLL di estensione.„

Questa nota utilizzerà questo file per fare riferimento all'intero set di DLL MFC, che include:

  • Debug: MFCxxD.DLL (combinato) e MFCSxxD.LIB (statici).

  • Versione: MFCxx.DLL (combinato) e MFCSxx.LIB (statici).

  • Unicode Debug: MFCxxUD.DLL (combinato) e MFCSxxD.LIB (statici).

  • Versione Unicode: MFCxxU.DLL (combinato) e MFCSxxU.LIB (statici).

[!NOTA]

Le librerie di MFCSxx [U] [D] .LIB sono utilizzate insieme alle DLL condivise MFC.Queste librerie contengono il codice che deve essere collegato staticamente all'applicazione o alla DLL.

Si collega alle librerie di importazione corrispondenti:

  • Debug: MFCxxD.LIB

  • Versione: MFCxx.LIB

  • Unicode Debug: MFCxxUD.LIB

  • Versione Unicode: MFCxxU.LIB

“Una DLL di estensione MFC„ è una DLL compilato su file (e/o gli altri DLL condivisa MFC).Qui l'architettura componente MFC vengono fornite delle compilazioni in.Se si deriva una classe utile per una classe MFC, o si compila un altro toolkit del tipo di MFC, è possibile posizionarlo in una DLL.Che la DLL utilizza questo file, come nell'applicazione client finale.Questo consente alle classi riutilizzabili foglia, le classi di base riutilizzabili e le classi riutilizzabili documento/visualizzazione.

Pro e contro

Poiché è necessario utilizzare la versione condivisa di MFC?

  • Utilizzo della libreria condivisa può determinare le dimensioni minori applicazioni (un'applicazione minima che utilizza più della libreria MFC è inferiore a 10K).

  • La versione condivisa delle DLL e le DLL regolari di estensione di MFC supporta MFC.

  • Compilare un'applicazione che utilizza le librerie condivise MFC è più veloce alla compilazione di un'applicazione collegata in modo statico MFC in quanto non occorre collegare la libreria MFC.Ciò è particolarmente evidente nelle build di DEBUG in cui il linker deve comprimere le informazioni di debug — collegamento a una DLL che già contiene le informazioni di debug, si avranno meno informazioni di debug da includere nell'applicazione.

Poiché è consigliabile non utilizzare la versione condivisa di MFC:

  • Fornire un'applicazione che utilizza la libreria condivisa è necessario fornire la raccolta altri e (MFCxx.DLL) con il programma.MFCxx.DLL è liberamente ridistribuibili come molti file DLL, ma è comunque necessario installare la DLL nel programma di installazione.Inoltre, è necessario fornire il MSVCRTxx.DLL, che contiene la libreria di runtime C utilizzata sia dal programma che dalle DLL MFC.

Come scrivere una DLL di estensione MFC

Una DLL di estensione MFC è una DLL che contiene le classi e le funzioni scritte per abbellire la funzionalità delle classi MFC.Una DLL di estensione MFC utilizza le DLL MFC condivise allo stesso modo in cui un'applicazione utilizza, con alcune considerazioni aggiuntive:

  • Il processo di compilazione è simile alla compilazione di un'applicazione che utilizza le librerie condivise MFC con gli altri compilatore aggiuntivo e opzioni del linker.

  • Una DLL di estensione MFC non ha CWinAppclasse derivata da.

  • Una DLL di estensione MFC deve fornire DllMainspeciale.AppWizard fornisce una funzione di DllMain che è possibile modificare.

  • Una DLL di estensione MFC in genere fornirà una procedura di inizializzazione per creare CDynLinkLibrary se la DLL di estensione desidera esportare CRuntimeClasses o risorse all'applicazione.Una classe derivata di CDynLinkLibrary può essere utilizzata se i dati dell'applicazione devono essere gestiti dalla DLL di estensione.

Queste considerazioni sono descritte più dettagliatamente di seguito.È inoltre necessario fare riferimento a DLLHUSK di concetti avanzati MFC poiché illustrato quanto segue:

  • Compilare un'applicazione utilizzando le librerie condivise.(DLLHUSK.EXE è un'applicazione MFC con collegamento dinamico alle librerie MFC nonché altri DLL).

  • Compilare una DLL di estensione MFC.(Si noti che i flag speciali come _AFXEXT in costruzione utilizzata una DLL di estensione)

  • Due esempi di DLL di estensione MFC.Viene illustrata la struttura di base di una DLL di estensione MFC con le esportazioni limitate (TESTDLL1) e l'altro che mostra esportare un'intera interfaccia della classe (TESTDLL2).

Sia l'applicazione client che tutte le DLL di estensione devono utilizzare la stessa versione di versione.È necessario utilizzare la convenzione della DLL MFC e fornire sia debug che la versione finale (/release) della DLL di estensione.In questo modo i programmi client di compilare entrambe le configurazioni debug e della vendita al dettaglio le versioni delle applicazioni e di collegarle al debug appropriato o la versione finale di tutte le DLL.

[!NOTA]

Poiché l'applicazione del nome C++ e problemi di esportazione, l'elenco di esportazione da una DLL di estensione possono essere diversi tra versioni finali o di debug dello stesso DLL e DLL per le piattaforme diverse.La versione finale e ha circa 2000 punti di ingresso esportati; debug MFCxxD.DLL ha circa 3000 punti di ingresso esportati.

hw85e4bb.collapse_all(it-it,VS.110).gifNota rapida sulla gestione della memoria

La sezione relativa alla gestione della memoria,„ verso la fine di questa nota tecnica, descritta l'implementazione del file con la versione condivisa di MFC.Le informazioni che è necessario conoscere per distribuire solo una DLL di estensione sono descritte qui.

MFCxx.DLL e tutte le DLL di estensione caricate nello spazio degli indirizzi di un'applicazione client utilizzeranno lo stesso allocatore di memoria, il caricamento delle risorse e altri stati globali “„ MFC come se fossero nella stessa applicazione.Ciò è significativo poiché le librerie e le DLL regolari DLL non MFC collegate a MFC in modo statico si comportano opposto e ciascuna DLL che alloca dal proprio pool di memoria.

Se una DLL di estensione alloca memoria, la memoria può liberamente mescolarsi con qualsiasi altro oggetto allocato dall'applicazione.Inoltre, se un'applicazione che utilizza le librerie condivise MFC si arresta in modo anomalo, la protezione del sistema operativo gestirà l'integrità di qualsiasi altra applicazione MFC che condivide la DLL.

Analogamente altri stati globali “„ mfc, ad esempio il file eseguibile corrente per caricare le risorse, vengono condivisi tra l'applicazione client e tutte le DLL di estensione MFC nonché MFCxx.DLL stessa.

hw85e4bb.collapse_all(it-it,VS.110).gifCompilare una DLL di estensione

È possibile utilizzare AppWizard per creare un progetto DLL di estensione MFC e verrà generato automaticamente le impostazioni appropriate del compilatore e del linker.È inoltre generata una funzione di DllMain che è possibile modificare.

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

  • Aggiungere /D_AFXEXT ai flag del compilatore.Nella finestra di dialogo delle proprietà del progetto, selezionare il nodo C/C++.Selezionare la categoria del preprocessore.Aggiungere _AFXEXT alle macro di definizione campo, separando ogni elemento con punti e virgola.

  • Rimuovere l'opzione del compilatore di /Gy .Nella finestra di dialogo delle proprietà del progetto, selezionare il nodo C/C++.Selezionare la categoria della generazione di codice.Assicurarsi che “abilitazione„ dell'opzione di collegamento a livello di funzione non è abilitato.Ciò faciliterà esportare le classi poiché il linker non rimuoverà le funzioni senza riferimenti.Se il progetto originale viene utilizzato per compilare una DLL regolare collegata a MFC in modo statico, modificare l'opzione del compilatore di /MT[d] a /MD[d].

  • Compilare una raccolta di esportazione con l'opzione di /DLL LINK.Verrà impostata quando si crea un nuovo di destinazione, specificando la libreria a collegamento dinamico Win32 come tipo di destinazione.

hw85e4bb.collapse_all(it-it,VS.110).gifModificare i file di intestazione

L'obiettivo di una DLL di estensione è in genere di esportare alcune funzionalità comuni a una o più applicazioni che possono utilizzare tale funzionalità.In questo modo è possibile ridurre a esportare le classi e le funzioni globali disponibili per le applicazioni client.

A tale scopo è necessario assicurarsi che tutte le funzioni membro sia contrassegnata come importare o esportare in base alle proprie esigenze.Ciò richiede dichiarazioni speciali: __declspec(dllexport) e __declspec(dllimport).Quando le classi utilizzate dalle applicazioni client, si desidera da dichiarare come __declspec(dllimport).Quando la DLL di estensione stesso viene compilato, devono essere dichiarate come __declspec(dllexport).Inoltre, le funzioni devono risultare esportate, in modo che i programmi client si esegue l'associazione a relativi al momento del caricamento.

Per esportare dell'intera classe, utilizzare AFX_EXT_CLASS nella definizione della classe.Questa macro viene definita dal framework come __declspec(dllexport) quando _AFXDLL e _AFXEXT viene definita, ma definita come __declspec(dllimport) quando _AFXEXT non è definito._AFXEXT come descritto in precedenza, viene definito solo quando si compila la DLL di estensione.Di seguito è riportato un esempio:

class AFX_EXT_CLASS CExampleExport : public CObject
{ ... class definition ... };

hw85e4bb.collapse_all(it-it,VS.110).gifEsportazione di porzioni di classi

In alcuni casi è necessario esportare solo i singoli membri obbligatori della classe.Se si esporta, ad esempio, una classe derivata da CDialog, può essere sufficiente esportare il costruttore e la chiamata DoModal.È possibile esportare questi membri utilizzando il file di .DEF della DLL, ma è anche possibile utilizzare AFX_EXT_CLASS nello stesso modo sui singoli membri da esportare.

Di seguito è riportato un esempio:

class CExampleDialog : public CDialog
{
public:
   AFX_EXT_CLASS CExampleDialog();
   AFX_EXT_CLASS int DoModal();
   // rest of class definition
   .
   .
   .
};

In questo caso, è possibile che si verifichino in un problema aggiuntivo poiché in non si esportano tutti i membri della classe.Il problema ingombra di lavoro di macro MFC.Molte macro di supporto MFC dichiarano o definiscono in realtà membri dati.Di conseguenza, questi membri dati anche devono essere esportati dalla DLL.

La macro DECLARE_DYNAMIC, ad esempio, viene definita nel modo seguente quando si compila una DLL di estensione:

#define DECLARE_DYNAMIC(class_name) \
protected: \
   static CRuntimeClass* PASCAL _GetBaseClass(); \
   public: \
   static AFX_DATA CRuntimeClass class##class_name; \
   virtual CRuntimeClass* GetRuntimeClass() const; \

La riga che inizia “ AFX_DATAstatic„ sta dichiarando un oggetto static all'interno della classe.Per esportare correttamente questa classe e accedere alle informazioni di runtime di un client file EXE, è necessario esportare questo oggetto statico.Poiché l'oggetto static viene dichiarato con il modificatore AFX_DATA, è sufficiente definire AFX_DATA come __declspec(dllexport) quando si compila la DLL e come __declspec(dllimport) quando si compila l'eseguibile client.

Come descritto in precedenza, AFX_EXT_CLASS è già definito in questo modo.È sufficiente ridefinire AFX_DATA dello stesso di AFX_EXT_CLASS intorno alla definizione della classe.

Di seguito è riportato un esempio:

   #undef  AFX_DATA
   #define AFX_DATA AFX_EXT_CLASS
   class CExampleView : public CView
   {
     DECLARE_DYNAMIC()
     // ... class definition ...
   };
   #undef  AFX_DATA
   #define AFX_DATA

MFC utilizza sempre Il simbolo di AFX_DATA sugli elementi di dati che definisce all'interno delle macro, questa tecnica può essere utilizzata per tutti gli scenari di questo tipo.Ad esempio, verrà eseguito per DECLARE_MESSAGE_MAP.

[!NOTA]

Se si esporta l'intera classe anziché alcuni membri di essa, i membri dati statici vengono esportati automaticamente.

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

#undef AFX_API
#define AFX_API AFX_EXT_CLASS

<your class declarations here>

#undef AFX_API
#define AFX_API

hw85e4bb.collapse_all(it-it,VS.110).gifLimitazioni di _AFXEXT

È possibile utilizzare il simbolo del preprocessore diAFXEXT _per le DLL di estensione purché non siano presenti più livelli di DLL di estensione.Se si hanno DLL di estensione che chiamano o derivano da classi nelle relative DLL di estensione, derivando quindi dalle classi MFC, è necessario utilizzare il proprio simbolo del preprocessore per evitare ambiguità.

Il problema è dato dal fatto che in Win32 è necessario dichiarare i dati in modo esplicito come __declspec(dllexport) se devono essere esportati da una DLL e come __declspec(dllimport) se devono essere importati da una DLL.Quando si definisce _AFXEXT, le intestazioni MFC assicurano la corretta definizione di AFX_EXT_CLASS.

Quando sono presenti più livelli, un simbolo come AFX_EXT_CLASS non è sufficiente, poiché una DLL di estensione può esportare nuove classi o importare altre classi da un'altra DLL di estensione.Per risolvere questo problema, utilizzare uno speciale simbolo del preprocessore per indicare che si compila la DLL o utilizzando la DLL.Ad esempio, si immaginino due DLL di estensione, A.DLL e B.DLL.A ogni esportazione alcune classi in A.H e in B.H, rispettivamente.B.DLL utilizza le classi di A.DLL.I file di intestazione potrebbero essere analoghi al seguente:

/* A.H */
#ifdef A_IMPL
   #define CLASS_DECL_A   __declspec(dllexport)
#else
   #define CLASS_DECL_A   __declspec(dllimport)
#endif

class CLASS_DECL_A CExampleA : public CObject
{ ... class definition ... };

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

class CLASS_DECL_B CExampleB : public CExampleA
{ ... class definition .. };

Quando A.DLL viene compilato, viene compilato con /D A_IMPL e quando B.DLL viene compilato, viene compilato con /D B_IMPL.Utilizzando i simboli distinti per ogni DLL, CExampleB viene esportato e CExampleA è incluso nella compilazione B.DLL.CExampleA viene esportato durante la compilazione A.DLL e importato quando viene utilizzato da B.DLL (o da un altro client).

Questo tipo di sovrapposizione non può essere realizzato quando si utilizzano AFX_EXT_CLASS e i simboli del preprocessore incorporati di _AFXEXT .La tecnica sopra descritta risolve il problema in modo non dissimile dal meccanismo utilizzato da MFC nella compilazione i relativi DLL di estensione OLE, database e della rete.

hw85e4bb.collapse_all(it-it,VS.110).gifEsportazione di porzioni di classi

Nuovamente, è necessario prendere molta attenzione quando si esportano porzioni di classi.È necessario assicurarsi che gli elementi di dati necessari creati dalle macro MFC vengono esportati correttamente.Questa operazione può essere eseguita mediante la ridefinizione dell'AFX_DATA alla macro specifica delle classi.Eseguire questa operazione ogni volta che non si esporta l'intera classe.

Di seguito è riportato un esempio:

// A.H
#ifdef A_IMPL
   #define CLASS_DECL_A  _declspec(dllexport)
#else
   #define CLASS_DECL_A  _declspec(dllimport)
   #endif

#undef  AFX_DATA
#define AFX_DATA CLASS_DECL_A

class CExampleA : public CObject
{
   DECLARE_DYNAMIC()
   CLASS_DECL_A int SomeFunction();
   //class definition 
   .
   .
   .
};

#undef AFX_DATA
#define AFX_DATA

hw85e4bb.collapse_all(it-it,VS.110).gifDllMain

Ecco il codice esatto è necessario inserire nel file di origine principale per la DLL di estensione.Deve essere scritto dopo che lo standard inclusi in.Si noti che quando si utilizza AppWizard per creare i file iniziali per una DLL di estensione, fornisce DllMain automaticamente.

#include "afxdllx.h"

static AFX_EXTENSION_MODULE extensionDLL;

extern "C" int APIENTRY 
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID)
{
   if (dwReason == DLL_PROCESS_ATTACH)
   {
      // Extension DLL one-time initialization 
      if (!AfxInitExtensionModule(
             extensionDLL, hInstance))
         return 0;

      // TODO: perform other initialization tasks here
   }
   else if (dwReason == DLL_PROCESS_DETACH)
   {
      // Extension DLL per-process termination
      AfxTermExtensionModule(extensionDLL);

          // TODO: perform other cleanup tasks here
   }
   return 1;   // ok
}

La chiamata a AfxInitExtensionModule acquisisce le classi di runtime dei moduli (strutture diCRuntimeClass ) nonché le object factory (oggetti diCOleObjectFactory ) da utilizzare in un secondo momento quando l'oggetto di CDynLinkLibrary viene creato.La chiamata (facoltativo) in AfxTermExtensionModule concede a MFC alla pulizia la DLL di estensione durante ogni processo rimuove (che si verifica quando il processo, o quando la DLL viene scaricata in seguito a una chiamata di FreeLibrary ) dalla DLL di estensione.Poiché la maggior parte delle DLL di estensione non vengono caricati dinamicamente (in genere, vengono collegati tramite le librerie di importazione), la chiamata a AfxTermExtensionModule non è necessaria normalmente.

Se l'applicazione viene caricata in modo dinamico e libera DLL di estensione, assicurarsi di chiamare AfxTermExtensionModule come illustrato in precedenza.Anche accertarsi di utilizzare AfxLoadLibrary e AfxFreeLibrary (anziché le funzioni Win32 LoadLibrary e FreeLibrary) se l'applicazione utilizza più thread o se viene caricata in modo dinamico una DLL di estensione.Utilizzando AfxLoadLibrary e di AfxFreeLibrary assicura che nel codice di avvio e di chiusura eseguito quando la DLL di estensione viene caricato e scaricato non vi sia nulla che danneggi lo stato MFC globale.

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 extensionDLL globale deve essere dichiarato come illustrato.A differenza della versione a 16 bit di MFC, è possibile allocare la memoria e chiamare le funzioni MFC durante questo periodo, poiché MFCxx.DLL è completamente inizializzato prima del DllMain venga chiamato.

hw85e4bb.collapse_all(it-it,VS.110).gifCondivisione di risorse e classi

Le DLL di estensione semplici MFC devono unicamente esportare alcune funzioni di con larghezza di banda limitata all'applicazione client e non di più.Più DLL complessi dell'interfaccia utente possono essere necessario esportare le risorse e le classi C++ all'applicazione client.

L'esportazione delle risorse viene effettuata tramite un elenco di risorse.In ogni applicazione è singolarmente un elenco collegato di oggetti di CDynLinkLibrary .In individuare una risorsa, la maggior parte delle implementazioni MFC standard che caricano le risorse cerca innanzitutto il modulo di risorse corrente (AfxGetResourceHandle) e se non trovata la verifica che l'elenco di CDynLinkLibrary oggetti tentare di caricare la risorsa richiesta.

La creazione dinamica di oggetti C++ fornite il nome della classe C++ è simile.Il meccanismo di deserializzazione degli oggetti MFC deve disporre di tutti gli oggetti di CRuntimeClass registrati in modo da poter compilare nuovamente in modo dinamico creando un oggetto C++ di tipo richiesto in base a quanto memorizzato in precedenza.

Se si desidera che l'applicazione client utilizzare le classi nella DLL di estensione che sono DECLARE_SERIAL, sarà necessario esportare le classi per essere visibile all'applicazione client.Questa operazione viene eseguita mediante scorrere l'elenco di CDynLinkLibrary .

Nel caso dei concetti avanzati MFC campionamento DLLHUSK, l'elenco è simile al seguente:

head ->   DLLHUSK.EXE   - or -   DLLHUSK.EXE
               |                      |
          TESTDLL2.DLL           TESTDLL2.DLL
               |                      |
          TESTDLL1.DLL           TESTDLL1.DLL
               |                      |
               |                      |
            MFC90D.DLL            MFC90.DLL

MFCxx.DLL è in genere l'ultimo file nell'elenco delle classi e delle risorse.Questo file include tutte le risorse MFC standard, incluse le stringhe di richiesta per tutti gli ID di comando standard.Inserendolo all'elemento tail consente le DLL e l'applicazione client non avere la propria copia delle risorse MFC standard, ma utilizzare le risorse condivise nel file anziché.

L'unione delle risorse e i nomi di classe di tutte le DLL nello spazio dei nomi dell'applicazione client presenta lo svantaggio che è necessario prestare attenzione affinché gli ID o dei nomi.È tuttavia possibile disabilitare questa funzionalità non è necessario esportare le risorse o un oggetto di CDynLinkLibrary applicazione client.Nell'esempio DLLHUSK viene illustrata la gestione dello spazio dei nomi di risorse condiviso mediante più file di intestazione.Vedere nota tecnica 35 per ulteriori suggerimenti sull'utilizzo dei file di risorse condivisi.

hw85e4bb.collapse_all(it-it,VS.110).gifInizializzare la DLL

Come accennato in precedenza, in genere si desidera creare un oggetto di CDynLinkLibrary per esportare le risorse e classi all'applicazione client.È necessario fornire un punto di ingresso esportato per inizializzare la DLL.Come minimo, si tratta di una routine void che non accetta argomenti e non restituisce alcun risultato, ma può essere qualsiasi nome.

Ogni applicazione client che intenda utilizzare la DLL deve chiamare la routine di inizializzazione, se si utilizza questo approccio.È inoltre possibile allocare questo oggetto di CDynLinkLibrary nel DllMain immediatamente dopo la chiamata AfxInitExtensionModule.

La procedura di inizializzazione necessario creare un oggetto di CDynLinkLibrary nell'heap dell'applicazione corrente, cablata fino alle informazioni di DLL di estensione.Questa operazione può essere eseguita con quanto segue:

extern "C" extern void WINAPI InitXxxDLL()
{
   new CDynLinkLibrary(extensionDLL);
}

Il nome della routine, InitXxxDLL in questo esempio, può essere qualsiasi elemento desiderati.Non deve essere extern "C", questa operazione rende l'elenco di esportazione più facile da gestire.

[!NOTA]

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

hw85e4bb.collapse_all(it-it,VS.110).gifEsportare le voci

La modalità semplice per esportare le classi è utilizzare __declspec(dllimport) e __declspec(dllexport) su ogni classe e funzione globale che si desidera esportare.In questo modo la personalizzazione molto più semplice, ma è meno efficiente di denominazione ogni punto di ingresso (illustrato di seguito) poiché è meno controllo sulle funzioni esportate e non è possibile esportare le funzioni per ordinale.TESTDLL1 e TESTDLL2 utilizzano questo metodo per esportare i relativi elementi.

Un metodo più efficace (e il metodo utilizzato da MFCxx.DLL) consente di esportare manualmente ogni voce di denominazione ogni voce nel file def.In quanto si esportano le esportazioni selettive dal file DLL (ovvero non tutti), è necessario decidere quali interfacce di particolare si desidera esportare.Ciò è difficile poiché è necessario specificare i nomi modificati al linker sotto forma di voci nel file DEF.Non esportare alcune classi C++ a meno che non sia effettivamente necessario disporre di un collegamento di token per.

Se si è cercato esportare C++ di classi con un file def prima, è possibile sviluppare uno strumento per compilare questo elenco automaticamente.Questa operazione può essere eseguita tramite un processo di collegamento in due fasi.Collegare una volta la DLL senza le esportazioni e che consentono al linker generi un file di .MAP.Il file di .MAP può essere utilizzato per generare un elenco delle funzioni che devono essere esportati, pertanto con un determinato riordinare, può essere utilizzato per generare le voci di esportazione per il file def.L'elenco di esportazione per MFCxx.DLL e OLE e le DLL di estensione del database, diverse migliaia di numero, è stato compilato con tale processo (anche se non è stato completamente automatico e non richiede una certa mano che ottimizza ogni parte consistente).

hw85e4bb.collapse_all(it-it,VS.110).gifCWinApp suCDynLinkLibrary

Una DLL di estensione MFC non ha CWinAppoggetto derivato da specifici; è invece necessario utilizzare CWinAppoggetto derivato da dell'applicazione client.Ciò significa che l'applicazione client possiede il message pump principale, il ciclo inattivo e così via.

Se la DLL di estensione MFC deve gestire dati aggiuntivi per ciascuna applicazione, è possibile derivare una nuova classe da CDynLinkLibrary e crearla nella routine di InitXxxDLL descrivere in precedenza.Durante l'esecuzione, la DLL può cercare nell'elenco di oggetti CDynLinkLibrary dell'applicazione corrente quello relativo alla DLL di estensione specifica.

hw85e4bb.collapse_all(it-it,VS.110).gifUtilizzo di risorse nell'implementazione di DLL

Come accennato in precedenza, il caricamento predefinito delle risorse verificherà l'elenco di oggetti CDynLinkLibrary a cercare il primo file EXE o DLL che dispone di implementare richiesto.Qualsiasi MFC API nonché tutti gli utilizzi AfxFindResourceHandle del codice interno scorrere l'elenco delle risorse per cercare qualsiasi risorsa, ovunque possa trovarsi.

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

La consultazione dell'elenco è un'operazione lenta e richiede la gestione degli intervalli di ID delle risorse.Offre il vantaggio che un'applicazione client che si collega a diverse DLL di estensione può utilizzare una qualsiasi risorsa fornita dalla DLL senza dover specificare l'handle di istanza della DLL.AfxFindResourceHandle è un'API utilizzata per scorrere l'elenco di risorse allo scopo di individuare una data corrispondenza.Utilizza il nome e il tipo di una risorsa e restituisce l'handle della risorsa nella posizione in cui viene trovato la prima volta oppure il valore NULL.

Scrive un'applicazione che utilizza la versione DLL

hw85e4bb.collapse_all(it-it,VS.110).gifRequisiti dell'applicazione

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

  • Deve avere un oggetto di CWinApp e seguire lo standard allo scopo di un message pump.

  • Deve essere compilato con un set di flag di associazione del compilatore (vedere di seguito).

  • Deve collegarsi alle librerie di importazione di MFCxx.Impostare i flag di associazione del compilatore, le intestazioni MFC determinano in fase di collegamento cui la raccolta l'applicazione deve effettuare il collegamento con.

  • Per eseguire il file eseguibile, questo file deve essere presente nel percorso nella directory di sistema di Windows.

hw85e4bb.collapse_all(it-it,VS.110).gifCompilazione con l'ambiente di sviluppo

Se si utilizza un makefile interne con la maggior parte delle impostazioni predefinite standard, è possibile modificare facilmente il progetto per compilare la versione DLL.

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

  1. Scegliere dal menu di Progetti , fare clic su Proprietà.Nella pagina di Generale in Project Defaults, impostare le classi MFC (Microsoft Foundation classes) a Use MFC in a Shared DLL (MFCxx (d) con estensione dll).

hw85e4bb.collapse_all(it-it,VS.110).gifCompilazione con NMAKE

Se si utilizza la funzionalità esterna di un makefile di Visual C++, se si utilizza NMAKE direttamente, sarà necessario modificare i makefile per supportare il compilatore e le opzioni del linker

Flag di associazione del compilatore:

  • /D_AFXDLL /MD
    /D_AFXDLL

Le intestazioni MFC standard necessitano di questo simbolo di essere definito:

  • /MD
    L'applicazione deve utilizzare la versione DLL della libreria di runtime del linguaggio C

Tutti gli altri flag del compilatore seguono le impostazioni predefinite MFC, ad esempio _DEBUG di debug.

Modificare l'elenco del linker delle librerie.Modificare NAFXCWD.LIB a MFCxxD.LIB e modificare NAFXCW.LIB a MFCxx.LIB.Sostituire LIBC.LIB con MSVCRT.LIB.Come con qualsiasi altra libreria MFC è importante che MFCxxD.LIB è before posizionato tutte le librerie di runtime C.

Facoltativamente aggiungere /D_AFXDLL sia alla versione finale del debug le opzioni del compilatore di risorse (che effettivamente compilano le risorse con /R).In questo modo il più piccolo eseguibile finale condivisione delle risorse presenti nelle DLL MFC.

Una ricompilazione completa è richiesta dopo che tali modifiche.

hw85e4bb.collapse_all(it-it,VS.110).gifCompilare gli esempi

La maggior parte dei programmi di esempio MFC possono essere compilati da Visual C++ o da MAKEFILE NMAKE-compatibili condivise dalla riga di comando.

Per convertire uno di questi esempi per utilizzare questo file, è possibile caricare il file di .MAK in Visual C++ e impostare le opzioni del progetto come descritto in precedenza.Se si utilizza la compilazione di NMAKE, è possibile specificare “AFXDLL=1„ nella riga di comando di NMAKE e che verrà compilato nell'esempio l'utilizzo di librerie condivise MFC.

L'esempio DLLHUSK di concetti avanzati MFC viene compilato con la versione DLL di MFC.Questo esempio non solo illustrato come compilare un'applicazione collegata con versione, ma viene illustrato anche altre funzionalità della DLL MFC che assembla l'opzione come DLL di estensione MFC descritti più avanti in questa nota tecnica.

hw85e4bb.collapse_all(it-it,VS.110).gifComprimere le note

La versione finale delle DLL (MFCxx [U] è tuttavia consigliabile) è liberamente ridistribuibili.La versione di debug delle DLL non è liberamente ridistribuibili e deve essere utilizzata solo durante lo sviluppo dell'applicazione.

Debug di DLL vengono forniti con informazioni di debug.Utilizzando il debugger di Visual C++, è possibile tracciare l'esecuzione dell'applicazione nonché della DLL.Le DLL di versione (ovvero MFCxx [U] è tuttavia consigliabile) non contengono informazioni di debug.

Se si personalizza o si ricompila le DLL, è necessario chiamare tali metodi da un'etichetta diversa da “di MFCxx„ che il file MFCDLL.MAK MFC SRC vengono descritte le opzioni di compilazione e che contiene la logica per rinominare la DLL.Rinominare i file è necessario, poiché queste DLL potenzialmente condivisi da più applicazioni MFC.Trasformare una versione personalizzata delle DLL MFC sostituire quelli installati nel sistema possibile interrompere un'altra applicazione MFC l'utilizzo di DLL MFC condivise.

Ricompila le DLL MFC non è consigliato.

Come MFCxx.DLL è distribuito

La seguente sezione viene descritto come la DLL MFC (MFCxx.DLL e MFCxxD.DLL) viene distribuito.La conoscenza dei dettagli di seguito non è importante se si desidera solo consiste nell'utilizzare la DLL MFC con l'applicazione.I dettagli di seguito non sono indispensabili per comprendere come scrivere una DLL di estensione MFC, ma comprendere ciò consente di scrivere DLL.

hw85e4bb.collapse_all(it-it,VS.110).gifCenni preliminari sull'implementazione

La DLL MFC in realtà è un caso speciale di una DLL di estensione MFC come descritto in precedenza.Dispone di numerose numero di esportazioni per numerose classi.Esistono alcune operazioni aggiuntive che facciamo nella DLL MFC che gli rendono ancora più speciale che una DLL regolare di estensione.

hw85e4bb.collapse_all(it-it,VS.110).gifIn Win32 esegue la maggior parte del lavoro

La versione a 16 bit di MFC necessaria una serie di tecniche speciali inclusi i dati dell'applicazione nel segmento dello stack, i segmenti speciali creati dal codice assembly qualsiasi 80x86, sui contesti di eccezione per processo e altre tecniche.In Win32 supporta direttamente i dati di processo in una DLL, cioé quello desiderato per la maggior parte dei casi.In genere questo file è semplicemente NAFXCW.LIB compresso in una DLL.Se si esamina il codice sorgente MFC, si trova il _AFXDLL poche #ifdef, poiché molti casi speciali di che devono essere trattati.I casi speciali che sono presenti in modo specifico della gestione di Win32 in Windows 3.1 (altrimenti nota come Win32.I Win32 non supporta direttamente i dati di DLL per processo in modo dalla DLL MFC deve utilizzare l'archiviazione locale di thread (TLS) API Win32 per ottenere i dati locali dei processi.

hw85e4bb.collapse_all(it-it,VS.110).gifImpatto sui database di origine della libreria, file aggiuntivi

L'impatto della versione di _AFXDLL su database di origine e sulle intestazioni standard della libreria di classi MFC è relativamente secondario.Esiste un file speciale della versione (AFXV_DLL.H nonché un file di intestazione aggiuntivo (AFXDLL_.H) incluso nell'intestazione principale di AFXWIN.H.L'intestazione di AFXDLL_.H include la classe di CDynLinkLibrary e altri dettagli di implementazione sia di applicazioni di _AFXDLL di DLL di estensione MFC.L'intestazione di AFXDLLX.H viene fornita per compilare DLL di estensione MFC (vedere la sezione precedente per i dettagli).

I database di origine normali alla libreria MFC in MFC SRC dispone di un codice condizionale aggiuntivo con #ifdef di _AFXDLL .Un file di origine aggiuntivo (DLLINIT.CPP) contiene il codice di inizializzazione di DLL e l'altra colla per la versione condivisa di MFC.

Per compilare la versione condivisa di MFC, i file aggiuntivi vengono forniti.(Vedere di seguito per informazioni dettagliate su come compilare la DLL).

  • Due file def vengono utilizzati per esportare punti di ingresso DLL MFC per il debug (MFCxxD.DEF) e le versioni della versione (MFCxx.DEF) della DLL.

  • Un file RC (MFCDLL.RC) contiene tutte le risorse MFC standard e una risorsa di VERSIONINFO per la DLL.

  • Un file di .CLW (MFCDLL.CLW) viene fornito per consentire esplorare le classi MFC utilizzando ClassWizard.Nota: questa funzionalità non è specifico della versione DLL di MFC.

hw85e4bb.collapse_all(it-it,VS.110).gifGestione della memoria

Un'applicazione utilizzando questo file viene utilizzato un allocatore di memoria ordinaria fornito da MSVCRTxx.DLL, la DLL condivisa di runtime C.L'applicazione, tutte le DLL di estensione e form come le DLL MFC stessa utilizza questo allocatore di memoria condivisi.Utilizzando una DLL condiviso per l'allocazione della memoria, le DLL MFC possono allocare memoria che successivamente viene liberata dall'applicazione o viceversa.Poiché sia l'applicazione e la DLL devono utilizzare lo stesso allocatore, non è necessario eseguire l'override di C++ operator new globale o operator delete.Le stesse regole vengono applicate al resto delle routine di allocazione della memoria di runtime del linguaggio C (come malloc, realloc, freee altre).

hw85e4bb.collapse_all(it-it,VS.110).gifOrdinali e della classe __declspec (dllexport) e denominare di DLL

Non utilizzare la funzionalità di class**__declspec(dllexport)** del compilatore C++.Al contrario, un elenco di esportazione è incluso tra i database di origine libreria di classi (MFCxx.DEF e MFCxxD.DEF).Questo set più ristretto di punti di ingresso (funzioni e dati) viene esportato solo.Altri simboli, quali le funzioni o classi private di implementazione MFC, non vengono esportati tutte le esportazioni vengono eseguiti in base al valore ordinale senza nome della stringa nella tabella dei nomi residente o non residente.

Utilizzando class**__declspec(dllexport)** può essere rappresenta una valida alternativa per compilare più piccoli DLL, ma in caso di grandi dimensioni DLL come MFC, il meccanismo di esportazione predefinito ha limiti della capacità e di efficienza.

Cosa questo qualsiasi utilizzo è che è possibile comprimere un gran numero di funzionalità della versione e che è solo circa 800 KB senza compromettere molta esecuzione o caricare la velocità.MFCxx.DLL sarebbe stato della maggiore questa tecnica non era stato utilizzato.Consente inoltre di aggiungere punti di ingresso aggiuntivi alla fine del file def per consentire il controllo delle versioni semplice senza compromettere l'efficienza di dimensione e della velocità di esportare in base al valore ordinale.Le revisioni di versione principale nella libreria di classi MFC modificheranno il nome della libreria.Ovvero MFC30.DLL è la DLL ridistribuibile che contiene la versione 3,0 della libreria di classi MFC.Un aggiornamento di questa DLL ad esempio in un ipotetico MFC 3,1, la DLL sarebbe denominato MFC31.DLL anziché., Se si modifica il codice sorgente di MFC per produrre una versione personalizzata della DLL MFC, utilizzare di nuovo un nome diverso (e possibilmente uno senza “MFC„ nel nome).

Vedere anche

Altre risorse

Note tecniche del numero

Note tecniche per categoria