2011-01-10 19 views
5

Mi pregunta es similar a Getting CLSID for a DLL file?, creo.Dado un DLL COM, extraer todas las clases CLSID y el nombre de interfaz correspondiente

Tengo un directorio con algunas DLL, cada una implementando una o más interfaces COM. Me gustaría llegar:

1) El nombre de cada interfaz 2) El CLSID de la clase que implementa la interfaz

Para cada DLL. Es importante que todo se pueda hacer programáticamente (así que no puedo usar algún tipo de navegador COM y buscar manualmente esa información).

Más tarde buscaré el CLSID dado el nombre de la interfaz y llamaré algunos métodos usando IDispatch.

Una alternativa parece ser escanear el registro tratando de coincidir con el tipo, interfaz y clase GUID y el nombre de archivo .dll. Pero eso parece ser lento y no robusto.

¿Alguien tiene una solución clara a este problema?

EDIT:

Con la respuesta de Ben Voigt, vine con el siguiente código, que se adapte a mis necesidades:

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 
     } 
    } 
} 

Respuesta

7

usted no puede conseguir que a partir de la DLL COM, pero se puede conseguir desde el typelib. Estoy bastante seguro de que el compilador MIDL tiene un interruptor para descompilar un typelib, pero analizar IDL no sería tan fácil como usar la API de TypeLib.

Para complicar las cosas, el typelib a menudo se almacena como un recurso dentro de la DLL. Entonces extraerías el recurso y lo abrirías con la API TypeLib.

Comience con LoadTypeLibEx que le devolverá un puntero de interfaz ITypeLib* (usted sabía que necesitaría COM para obtener información acerca de las bibliotecas COM, ¿verdad?). Esto realmente hará el paso de extracción de recursos para usted.

Luego, llame al ITypeLib::GetTypeInfoCount para averiguar cuántos tipos hay. Llame al ITypeLib::GetTypeInfoType para cada uno para encontrar las interfaces y coclasses. Y llame al ITypeLib::GetTypeInfo seguido de ITypeInfo::GetDocumentation para obtener el nombre.

Parece que tiene todo esto hasta ahora. A continuación, necesita el GUID del tipo, que se obtiene con ITypeInfo::GetTypeAttr (no ITypeLib::GetLibAttr). Eso le da una estructura TYPEATTR, que tiene un campo guid.

Desde la misma estructura TYPEATTR, necesitará el campo cImplTypes. Eso junto con ITypeInfo::GetRefTypeOfImplType le permitirá unir cada coclass a las interfaces que implementa.

Tenga en cuenta que no se garantiza que exista una relación 1: 1 entre interfaces y coclasses de implementación. Y la interfaz puede estar en una biblioteca diferente del coclass.

4

Algunas advertencias a la respuesta de Ben Voigt: no todas las DLL COM tienen una typelib. En tu caso, parece que sí; pero eso no es un requisito. El único requisito sólido como una roca es que la DLL exporte la función DllGetClassObject(), donde pasa un CLSID y recupera una fábrica de objetos.

Puede cargar la biblioteca y llamar a DllGetClassObject para cada CLSID registrado en el sistema (examine el registro en HKCR \ CLSID para ver la lista de ellos). Los que recuperan un objeto válido son los que admite el archivo DLL. Ahora, en teoría, ni siquiera es un requisito que los CLSID que admite el DLL estén registrados; Puedo visualizar una DLL que implementa clases de objetos privados que solo el cliente previsto conoce y nadie más debería saber. Pero este es un escenario muy, muy exótico; Por un lado, el mecanismo COM regular de buscar la ruta de la DLL por el CLSID se romperá por eso. El cliente debería cargar la DLL directamente.

También puede escanear el registro de los CLSID donde la DLL bajo consideración está registrada como InprocServer32; esto, nuevamente, se romperá en caso de clases privadas. Puede hacer una búsqueda de registro en regedit, buscar en los datos. Además, tendría que lidiar con problemas de nombres de archivos, nombres cortos contra largos, enlaces duros, sustitución de variables de entorno, etc. Entonces no lo recomendaría.

EDIT: solo pensado de otra manera. Descargue Regmon, ejecútelo y llame a regsvr32 en la DLL. Luego observe qué CLSID se tocan.

+0

'DllGetClassObject' podría tener efectos secundarios no deseados, por lo que no se recomienda este. Además, es completamente posible tener una combinación de CLSID públicos y privados. Como la DLL se carga mediante la creación de un tipo público, no hay necesidad de cargar la DLL fuera de los mecanismos COM. –

+0

Bueno, el análisis forense * ultimate * implicaría desmontar el archivo DLL y pasar por el código de DllGetClassObject(). En la implementación típica (léase: el de ATL) habría una estructura de datos global que enumera cuidadosamente todos los CLSID en un solo lugar. Difícilmente puedo imaginarme una DLL COM donde el conjunto de coclasses compatibles es condicional. –

+0

Depende de qué tan furtivo sea el esquema de licencias. Definitivamente puedo imaginar un requisito para instanciar un objeto de administrador de licencia y usarlo antes de que se puedan crear instancias de otras clases, la pregunta es si la falla al intentar crear objetos sin una licencia es "No conozco ese objeto" o "Intenté" para crear ese objeto pero falló " –

Cuestiones relacionadas