Implementare una raccolta Basata STL
ATL fornisce l'interfaccia ICollectionOnSTLImpl per consentire di distribuire rapidamente le interfacce di raccolte basate di (STL) della libreria di modelli standard negli oggetti.Per comprendere il funzionamento di questa classe, si funzioneranno con un semplice esempio (in) che utilizza questa classe implementare i client di automazione operazioni su una raccolta di sola lettura.
Il codice di esempio proviene da Esempio ATLCollections.
Per completare questa procedura, è necessario:
Creare un nuovo oggetto semplice.
Modificare il file IDL per l'interfaccia generata un'eccezione.
Creare cinque typedef che viene descritto come gli elementi della raccolta vengono archiviati e come verranno esposti ai client tramite le interfacce COM.
Creare due typedef per le classi criteri di copia.
Creare i typedef per le implementazioni di raccolta e dell'enumeratore.
Modificare il codice C++ generato mediante procedura guidata per utilizzare il typedef di raccolta.
Aggiungere il codice per popolare la raccolta.
Generazione dell'oggetto semplice nuovo
Creare un nuovo progetto, garantendo l'installazione della casella di attributi nelle impostazioni dell'applicazione sia deselezionata.Utilizzare ATL aggiunge la finestra di dialogo della classe e aggiungere la procedura guidata semplice dell'oggetto per generare un oggetto semplice denominato Words.Assicurarsi che un'interfaccia duale chiamata IWords venga generata un'eccezione.Gli oggetti della classe generata verranno utilizzati per rappresentare una raccolta di parole ovvero stringhe).
Modificare il file IDL
Ora, aprire il file IDL e aggiungere le tre proprietà necessarie per trasformare IWords in un'interfaccia di raccolta di sola lettura, come illustrato di seguito:
[
object,
uuid(7B3AC376-509F-4068-87BA-03B73ADC359B),
dual, // (1)
nonextensible, // (2)
pointer_default(unique)
]
interface IWords : IDispatch
{
[id(DISPID_NEWENUM), propget] // (3)
HRESULT _NewEnum([out, retval] IUnknown** ppUnk);
[id(DISPID_VALUE), propget] // (4)
HRESULT Item([in] long Index, [out, retval] BSTR* pVal); // (5)
[id(0x00000001), propget] // (6)
HRESULT Count([out, retval] long* pVal);
};
È il formato standard per un'interfaccia di raccolta di sola lettura progettata con i client di automazione di base.I commenti numerate nella definizione di interfaccia corrispondono ai commenti di seguito:
Le interfacce di raccolta sono generalmente doppie poiché i client di automazione accede alla proprietà _NewEnum via IDispatch::Invoke.Tuttavia, i client di automazione possono accedere ai metodi rimanenti tramite il puntatore vtable, pertanto le interfacce duali sono preferibili le interfacce dispatch.
Se un'interfaccia duale o un'interfaccia dispatch non viene estesa in fase di esecuzione (ovvero non forniscono metodi aggiuntivi o le proprietà mediante IDispatch::Invoke), è necessario applicare l'attributo nonextensible alla definizione.Questo attributo consente ai client di automazione per eseguire la verifica di codice completo in fase di compilazione.In questo caso, l'interfaccia non deve essere estesa.
Il DISPID corretto è importante se si desidera che i client di automazione per poter utilizzare questa proprietà.Notare che esiste solo un carattere di sottolineatura in DISPID_NEWENUM).
È possibile specificare qualsiasi valore come il DISPID della proprietà Elemento.Tuttavia, Elemento utilizza in genere DISPID_VALUE per selezionarla nella proprietà predefinita della raccolta.Ciò consente ai client di automazione fanno riferimento a proprietà senza denominarla in modo esplicito.
Il tipo di dati utilizzato per il valore restituito della proprietà Elemento è il tipo di elemento archiviato nella libreria per quanto i client COM.L'interfaccia restituisce le stringhe, pertanto è necessario utilizzare COM standard si insieme il tipo, BSTR.È possibile archiviare dati in un formato diverso internamente come illustrato in precedenza.
Il valore utilizzato per il DISPID della proprietà Conteggio è completamente arbitrario.Non esiste alcun DISPID standard per questa proprietà.
Creare i typedef per l'archiviazione e rischi
Una volta che l'interfaccia di raccolta è definita, è necessario decidere come i dati verranno archiviati e sui dati saranno esposti tramite enumeratore.
Risposte alle domande possono essere fornite sotto forma di una serie di typedef, che è possibile aggiungere nella parte superiore del file di intestazione per la classe appena creata:
// Store the data in a vector of std::strings
typedef std::vector< std::string > ContainerType;
// The collection interface exposes the data as BSTRs
typedef BSTR CollectionExposedType;
typedef IWords CollectionInterface;
// Use IEnumVARIANT as the enumerator for VB compatibility
typedef VARIANT EnumeratorExposedType;
typedef IEnumVARIANT EnumeratorInterface;
In questo caso, verranno memorizzati i dati come std::vectorstd::stringS.std::vector è una classe di contenitori STL che si comporta come una matrice gestita.std::string è la classe della stringa della libreria C++ standard.Queste classi semplificano l'utilizzo di una raccolta di stringhe.
Poiché il supporto in Visual Basic è vitale al termine di questa interfaccia, l'enumeratore restituito dalla proprietà _NewEnum deve supportare l'interfaccia IEnumVARIANT.Questo è l'unico l'enumeratore capita da Visual Basic.
Creare i typedef per le classi criteri di copia
I typedef creata fino forniscono tutte le informazioni è necessario creare ulteriori typedef per le classi di copia che verranno utilizzate dall'enumeratore e dalla raccolta:
// Typedef the copy classes using existing typedefs
typedef VCUE::GenericCopy<EnumeratorExposedType, ContainerType::value_type> EnumeratorCopyType;
typedef VCUE::GenericCopy<CollectionExposedType, ContainerType::value_type> CollectionCopyType;
In questo esempio, è possibile utilizzare la classe GenericCopy personalizzate definita in VCUE_Copy.h e VCUE_CopyString.hesempio ATLCollections.È possibile utilizzare la classe in un altro codice, ma è necessario definire ulteriori specializzazioni GenericCopy per supportare i tipi di dati utilizzati nelle proprie raccolte.Per ulteriori informazioni, vedere Classi criteri di copia ATL.
Creare i typedef per l'enumerazione e raccolta
Ora tutti i parametri di modello necessari per specializzare le classi ICollectionOnSTLImpl e CComEnumOnSTL per questa situazione sono stati forniti sotto forma di typedef.Per semplificare l'utilizzo delle specializzazioni, creare due nuovi typedef come illustrato di seguito:
typedef CComEnumOnSTL< EnumeratorInterface, &__uuidof(EnumeratorInterface), EnumeratorExposedType, EnumeratorCopyType, ContainerType > EnumeratorType;
typedef ICollectionOnSTLImpl< CollectionInterface, ContainerType, CollectionExposedType, CollectionCopyType, EnumeratorType > CollectionType;
Ora CollectionType è sinonimo di una specializzazione ICollectionOnSTLImpl che implementa l'interfaccia IWords definita in precedenza e fornisce un enumeratore che supporta IEnumVARIANT.
Modificare il codice generato dalla creazione guidata
Ora è necessario derivare CWords dall'interfaccia rappresentata dal typedef CollectionType anziché IWords, come illustrato di seguito:
class ATL_NO_VTABLE CWords :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CWords, &CLSID_Words>,
// 'CollectionType' replaces 'IWords' in next line
public IDispatchImpl<CollectionType, &IID_IWords, &LIBID_NVC_ATL_COMLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
public:
DECLARE_REGISTRY_RESOURCEID(IDR_WORDS)
BEGIN_COM_MAP(CWords)
COM_INTERFACE_ENTRY(IWords)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()
// Remainder of class declaration omitted.
Aggiunta di codice per popolare la raccolta
L'unica differenza che rimane è di popolare il vettore con i dati.In questo esempio, è possibile aggiungere alcune parole alla raccolta nel costruttore della classe:
CWords()
{
m_coll.push_back("this");
m_coll.push_back("is");
m_coll.push_back("a");
m_coll.push_back("test");
}
A questo punto, è possibile testare il codice con il client scelto.