Condividi tramite


Importazioni reciproche

Aggiornamento: novembre 2007

L'esportazione o l'importazione in un altro file eseguibile presenta alcune complicazioni quando le importazioni sono reciproche, ovvero circolari. Un esempio è dato da due DLL che importano simboli l'una dall'altra, analogamente alle funzioni ricorsive reciproche.

Il problema dei file eseguibili a importazione reciproca, di solito DLL, è dato dal fatto che non è possibile generare un file senza generare prima l'altro. Ciascun processo di generazione richiede, come input, una libreria di importazione prodotta dall'altro processo di generazione.

La soluzione consiste nell'impiego dell'utilità LIB con l'opzione /DEF, che produce una libreria di importazione senza generare l'eseguibile. Questa utilità consente di generare tutte le librerie di importazione necessarie, indipendentemente dal numero di DLL coinvolte o dal grado di complessità delle dipendenze.

La soluzione generale per gestire le importazioni reciproche è descritta di seguito.

  1. Prendere ciascuna DLL a turno. L'ordine non è importante, anche se alcune soluzioni sono ottimali. Se tutte le librerie di importazione necessarie sono attualmente disponibili, eseguire LINK per generare il file eseguibile (DLL). Viene creata una libreria di importazione. In caso contrario, eseguire LIB per creare una libreria di importazione.

    L'esecuzione di LIB con l'opzione /DEF produce un file aggiuntivo con estensione exp, che deve essere utilizzato successivamente per generare l'eseguibile.

  2. Dopo avere utilizzato LINK o LIB per generare tutte le librerie di importazione, tornare indietro ed eseguire LINK per generare i file eseguibili che non sono stati generati nel passaggio precedente. Tenere presente che il file exp corrispondente deve essere specificato sulla riga LINK.

    Se è stata eseguita l'utilità LIB per creare una libreria di importazione per DLL1, dovrebbe essere stato prodotto anche il file DLL1.exp. È necessario utilizzare DLL1.exp come input per LINK al momento della generazione di DLL1.dll.

Nell'esempio riportato di seguito viene illustrata una soluzione per due DLL di importazione reciproche, DLL1 e DLL2. Il passaggio 1 prevede l'esecuzione di LIB, con l'opzione /DEF impostata, su DLL1. Questo passaggio produce la libreria di importazione DLL1.lib e il file DLL1.exp. Nel passaggio 2 la libreria di importazione viene utilizzata per generare DLL2, che produce a sua volta una libreria di importazione per i simboli di DLL2. Il passaggio 3 genera DLL1, utilizzando come input DLL1.exp e DLL2.lib. Tenere presente che non è necessario un file exp per DLL2, poiché non è stata utilizzata l'utilità LIB per generare la libreria di importazione di DLL2.

Collegamento di due DLL con importazioni reciproche

Importazioni reciproche di due DLL collegate

Limitazioni di _AFXEXT

È possibile utilizzare il simbolo del preprocessore _AFXEXT 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 potrebbe esportare nuove classi o importare altre classi da un'altra DLL di estensione. Per risolvere il problema, è possibile utilizzare uno speciale simbolo del preprocessore per indicare se si sta generando la DLL o utilizzando la DLL. Si supponga, ad esempio, che esistano due estensioni DLL, A.dll e B.dll, ciascuna delle quali esporta alcune classi rispettivamente in A.h e B.h. B.dll utilizza le classi da A.dll. Di seguito è indicato il possibile aspetto dei file di intestazione:

/* 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 ... };
...

A.dll viene generata con /D A_IMPL e B.dll viene generata con /D B_IMPL. Utilizzando simboli distinti per ciascuna DLL, durante la generazione di B.dll la classe CExampleB viene esportata e la classe CExampleA viene importata. Al contrario, la classe CExampleA viene esportata durante la generazione di A.dll e importata quando viene utilizzata da B.dll (o da qualche altro client).

Questo tipo di disposizione su più livelli non può essere realizzato quando si utilizzano i simboli del preprocessore incorporati AFX_EXT_CLASS e _AFXEXT. La tecnica sopra descritta risolve il problema in modo non dissimile dal meccanismo utilizzato da MFC nella generazione delle proprie DLL di estensione per la tecnologia Active, i database e la rete.

Esportazione di porzioni di classi

Quando si esportano porzioni di classi, occorre accertarsi che gli elementi di dati necessari creati dalle macro MFC vengano esportati correttamente. A tal fine, è possibile ridefinire AFX_DATA in base alla macro della classe specifica. 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

Scegliere l'argomento con cui si desidera procedere

Scegliere l'argomento su cui visualizzare maggiori informazioni

Vedere anche

Concetti

Importazione ed esportazione