2011-01-10 3 views
5

La mia domanda è simile a Getting CLSID for a DLL file?, penso.Data una DLL COM, estrarre tutte le classi CLSID e il nome dell'interfaccia corrispondente

Ho una directory con alcune DLL, ognuna delle quali implementa una o più interfacce COM. Vorrei ottenere:

1) Ogni nome dell'interfaccia 2) Il CLSID della classe che implementa l'interfaccia

Per ogni DLL. È importante che tutto sia programmabile (quindi non posso usare una sorta di browser COM e cercare manualmente tali informazioni).

Successivamente cercherò il CLSID dato il nome dell'interfaccia e chiamerò alcuni metodi usando IDispatch.

Un'alternativa sembra essere la scansione del registro cercando di corrispondere al tipo, all'interfaccia e al GUID della classe e al nome file .dll. Ma sembra essere lento e non robusto.

Qualcuno ha una soluzione chiara a questo problema?

EDIT:

Con la risposta di Ben Voigt, sono venuto con il seguente codice che più adatto alle mie esigenze:

ITypeLib *typelib; 
ITypeInfo *typeinfo; 
LoadTypeLibEx(_T("c:\\mydir\\mycom1"), REGKIND_NONE, &typelib); 
for (UINT i = 0;i < typelib->GetTypeInfoCount();++i) { 
    TYPEKIND typekind; 
    typelib->GetTypeInfoType(i, &typekind); 
    if (typekind == TKIND_COCLASS) { 
     // class! 
     CComBSTR className; 
     TYPEATTR *typeattr; 
     typelib->GetTypeInfo(i, &typeinfo); 
     typeinfo->GetDocumentation(MEMBERID_NIL, &className, NULL, NULL, NULL); 
     typeinfo->GetTypeAttr(&typeattr); 
     GUID classGUID = typeattr->guid; 
     for (UINT j = 0;j < typeattr->cImplTypes;++j) { 
      // interface! 
      CComBSTR interfaceName; 
      HREFTYPE hreftype; 
      ITypeInfo *classtypeinfo; 
      typeinfo->GetRefTypeOfImplType(j, &hreftype); 
      typeinfo->GetRefTypeInfo(hreftype, &classtypeinfo); 
      classtypeinfo->GetDocumentation(MEMBERID_NIL, &interfaceName, NULL, NULL, NULL); 
      // associate interfaceName with classGUID here 
     } 
    } 
} 

risposta

7

Non si può ottenere che dal DLL COM, ma è possibile ottenere dal typelib. Sono abbastanza sicuro che il compilatore MIDL abbia un interruttore per decompilare una libreria dei tipi, ma l'analisi dell'IDL non sarebbe facile come usare l'API TypeLib.

Per complicare le cose, la libreria dei tipi viene spesso memorizzata come risorsa all'interno della DLL. Quindi estrai la risorsa e aprila con l'API TypeLib.

Inizia con LoadTypeLibEx che restituirà un puntatore si ITypeLib* interfaccia (si sapeva che stavano per avere bisogno di COM, al fine di ottenere informazioni su librerie COM, giusto?). Questo farà effettivamente il passo di estrazione delle risorse per te.

Quindi, chiamare ITypeLib::GetTypeInfoCount per scoprire quanti tipi ci sono. Chiama ITypeLib::GetTypeInfoType per ognuno per trovare le interfacce e le coclasse. E chiama ITypeLib::GetTypeInfo seguito da ITypeInfo::GetDocumentation per ottenere il nome.

Sembra che tu abbia tutto questo finora. Successivamente è necessario il GUID del tipo, ottenuto con ITypeInfo::GetTypeAttr (non ITypeLib::GetLibAttr). Questo ti dà una struttura TYPEATTR, che ha un campo guid.

Dalla stessa struttura TYPEATTR, è necessario il campo cImplTypes. Che insieme a ITypeInfo::GetRefTypeOfImplType ti permetterà di abbinare ogni coclasse alle interfacce che implementa.

Si noti che non è garantita una relazione 1: 1 tra le interfacce e le coclasse di implementazione. E l'interfaccia può trovarsi in una libreria diversa dalla coclasse.

4

Pochi avvertimenti alla risposta di Ben Voigt: non tutte le DLL COM hanno una libreria dei tipi. Nel tuo caso, sembra, lo fa; ma non è un requisito. L'unico requisito fondamentale è che la DLL esporti la funzione DllGetClassObject(), dove si passa un CLSID e si ottiene un oggetto factory.

È possibile caricare la libreria e chiamare DllGetClassObject per ogni CLSID registrato sul sistema (eseguire la scansione del registro in HKCR \ CLSID per l'elenco di quelli). Quelli su cui si ottiene un oggetto valido sono quelli supportati dalla DLL. Ora, in teoria, non è nemmeno richiesto che i CLSID supportati dalla DLL siano registrati; Posso immaginare una DLL che implementa classi di oggetti private che solo il client previsto conosce e nessun altro dovrebbe. Ma questo è uno scenario molto, molto esotico; per prima cosa, il normale meccanismo COM di cercare il percorso della DLL dal CLSID si interromperà per quelli. Il client dovrebbe caricare direttamente la DLL.

È anche possibile eseguire la scansione del registro per i CLSID in cui la DLL in esame è registrata come InprocServer32; questo, di nuovo, si interromperà in caso di lezioni private. È possibile eseguire una ricerca nel registro in regedit, cercare nei dati. Inoltre, dovresti occuparti dei problemi dei nomi dei file, dei nomi brevi e lunghi, dei collegamenti fisici, della sostituzione delle variabili d'ambiente e così via. Quindi non lo consiglierei.

EDIT: pensavo solo in un altro modo. Scarica Regmon, eseguilo e chiama regsvr32 nella DLL. Quindi guarda quali sono stati toccati dai CLSID.

+0

'DllGetClassObject' potrebbe avere effetti collaterali indesiderati, in modo da non consigliare questo. Inoltre, è del tutto possibile avere una combinazione di CLSID pubblici e privati. Poiché la DLL viene caricata con la creazione di un tipo pubblico, non è necessario caricare la DLL all'esterno dei meccanismi COM. –

+0

Bene, la * massima * analisi forense comporterebbe il disassemblaggio della DLL e il codice di DllGetClassObject(). Nell'implementazione tipica (leggi: quella ATL) ci sarebbe una struttura di dati globale che elenca ordinatamente tutti i CLSID in un unico posto. Riesco a malapena a immaginare una DLL COM in cui il set di coclassi supportate è condizionale. –

+0

Dipende da quanto è subdolo lo schema di licenza. Sicuramente posso immaginare un requisito per istanziare un oggetto gestore di licenze e usarlo prima che qualsiasi altra classe possa essere istanziata, la domanda è se l'errore dal tentativo di creare oggetti senza una licenza è "Non so quell'oggetto" o "Ho provato per creare quell'oggetto ma non è riuscito " –