2009-02-20 10 views
20

Después asking about what Visual Studio does to register a COM Library, se hizo evidente que VS hizo dos cosas para el registro de COM:Typelib Generación e instalación con WiX

  1. registrados la Biblioteca COM
  2. crea y registra una biblioteca de tipos

Visual Studio parece hacer este registro usando regasm.exe. Para la primera parte (el registro COM directo) que usa tallow o heat (WiX 2.0 o WiX 3.0) parece que toda la información básica de registro COM es correcta.

Sin embargo, lo que el sebo/calor no parece hacer es configurar una instalación de biblioteca de tipos. Sería posible crear una acción personalizada para hacer esto con un instalador de WiX y regasm.exe, pero invocar acciones personalizadas no son las mejores prácticas cuando se trata de instaladores basados ​​en instaladores de Microsoft.

En futuras investigaciones, parece que un msi tiene la capacidad de generar la biblioteca de tipos en la instalación. De hecho, ¡WiX parece tener soporte directo para eso! En un elemento de archivo, puede agregar un elemento Typelib. De hecho, an article over here on wix tiene un ejemplo de rellenar el elemento TypeLib con elementos Interface.

Parece que hay al menos dos atributos requeridos a un elemento de interfaz:

  1. Id
  2. Nombre

Larry Osterman speaks about the other parts of the interface that need to be registered for a TypeLib in general, y esta entrada de interfaz parece hacerse cargo de las partes individuales. Larry dice que necesitamos especificar el ProxyStubClassId32 como "{00020424-0000-0000-C000-000000000046}", por lo que podemos agregarlo fácilmente.

Adónde ir desde allí y qué rellenar para los diversos elementos de la interfaz me ha dejado perplejo. He seguido adelante y he agregado el elemento TypeLib a mi archivo wix, y se compila con éxito. Aunque no tengo ni idea de cómo configurar los elementos de la interfaz. ¿Qué tenemos que hacer para completar correctamente el elemento TypeLib y qué aplicaciones o herramientas puedo usar para obtenerlo?

La respuesta a continuación por wcoenen parece prometedora ... Voy a darle una oportunidad.

Actualización: Publiqué mi solución final a continuación como respuesta.

+0

+1, me gustaría que todas las preguntas en este sitio se escribieran así ... –

+0

Heh, doy mi mejor oportunidad. :) –

Respuesta

13

Aquí está la forma de resolver este problema: Use heat de WiX 3.0.

Si tiene una biblioteca de tipos generada automáticamente y se instala a través de regasm, heat puede tomar el .tlb como un argumento en

heat file c:\my\path\to\my.tlb -out tlb.wxs 

Se va a generar todos los elementos de biblioteca de tipos y de interfaz es necesario registrarse. Esto no resolverá el problema de la necesidad de conocerlos con anticipación, y no resolverá el problema de los GUID que cambian cuando la versión del ensamblaje cambia (incluso si la interfaz no lo hace, que es la única vez que ' se supone que debe cambiarlo) pero te llevará a la mitad.

+2

+1 No sabía que podría cosechar archivos tlb con heat.exe –

+1

Aunque no creo que haya ningún GUID variable si los declara en su código .NET con un GUID [assembly: Guid ("... ")] atributo para el typelib y un atributo [Guid (" ... ")] para las interfaces COM y las clases –

+1

Para las guías COM creo que es correcto. Desafortunadamente, la biblioteca de tipos tiene diferentes guias. : | Me pregunto si hay un atributo para establecer esas guías también ... –

7

El siguiente truco puede ayudar a recolectar cualquier cambio en el registro y convertirlo en un archivo wxs, incluido el elemento typelib que está buscando.

  1. En primer lugar, llevar su registro de nuevo en un estado donde la biblioteca de tipos no estaba registrada:

    c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\regasm.exe /tlb /u mylib.dll 
    
  2. Exportación este estado de limpieza del registro de HKLM antes.reg:

    c:\WINDOWS\system32\reg.exe export HKLM hklm-before.reg 
    
  3. registrar la biblioteca de tipo nuevo:

    c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\regasm.exe /tlb mylib.dll 
    
  4. exportación el nuevo estado del registro de HKLM-after.reg:

    c:\WINDOWS\system32\reg.exe export HKLM hklm-after.reg 
    
  5. Ahora tenemos dos archivos de texto, hklm-before.reg y hklm-after.reg. Cree un archivo diff.reg que solo contenga las diferencias relevantes entre estos. Puede encontrar las diferencias fácilmente con una herramienta diferente. Me gusta usar la herramienta diff incluida en TortoiseSVN ya que la uso todos los días. (WinDiff no parece funcionar bien en este caso debido a problemas de codificación de texto.)

  6. Ahora podemos convertir en un diff.reg .wxs llamando heat.exe con el comando reg. (Requiere Wix 3.5 o posterior.)

    heat reg diff.reg -out typelib.wxs 
    
+2

Ouch. No es de extrañar que digan que la creación de WiX en este momento es un proceso manual, ¡euch! –

+1

Esto se debe a que WIX es principalmente un formato XML que se asigna a una base de datos de instalador de Windows (msi/msm/mst/pcp). Por ejemplo, hay un elemento "typelib" porque también hay una tabla "typelib". La herramienta de recolección heat.exe es un valor agregado útil, pero necesita expertos para completarla. –

+0

A partir de WiX 3.10 heat tiene un parámetro reg específicamente dedicado a la recolección de archivos de registro. –

3

Parece que para registrar una biblioteca de tipos, la mejor manera sería generar su propio archivo IDL o ODL, que contendrá sus GUID. Los Typelibs generados directamente del Assembly son [i] dependientes [/ i] en los números de versión del ensamblado: los GUID se generan en función de esa información, incluso si la interfaz no ha cambiado. Visual Studio usa regasm para registrar y generar el typelib. Debajo de eso, usa RegisterTypeLib, una llamada win32. El uso del elemento typelib parece hacer algo similar. No es bueno.

¡Sin embargo! Crear la biblioteca de tipos a mano es doloroso. Es posible obtener esos GUID de otra forma: desenterrándolos del typelib y creando los elementos usted mismo.

Larry Osterman tiene la información necesaria: hay ciertas claves de registro que deben configurarse. Puede hacer eso con la tabla del Registro (y en Wix3, eso significa elementos RegistryValue). El truco aquí es obtener los GUID: cualquier GUID antiguo no funcionará. Normalmente, obtener los GUID es simplemente una cuestión de buscar en el IDL de su biblioteca (usted escribió su propio IDL, ¿verdad? :)).

Si no escribió un archivo IDL u ODL para compilar en un typelib, todavía existen, en el archivo. Microsoft proporciona varias herramientas útiles: LoadTypeLibEx y la interfaz ITypeLib. Con estas interfaces, puede navegar por la biblioteca de tipos y obtener todo tipo de información. ¿Cómo navegamos por la biblioteca?

¡Simplemente eché un vistazo a cómo lo hizo Regasm! Un desmontaje rápido más tarde, y encontramos que regasm está escrito en C# también. Día de gloria. Empecé en marcha un proyecto, y con unos pocos mediante instrucciones y un PInvoke más tarde, tenemos:

using System.Runtime.InteropServices;   // for struct marshaling 
using System.Runtime.InteropServices.ComTypes; // for the ITypeLib + related types 

// TYPELIBATTR lives in two places: Interop and ComTypes, but the one 
// in Interop is deprecated. 
using TYPELIBATTR = System.Runtime.InteropServices.ComTypes.TYPELIBATTR; 

/// <summary> 
/// The registry kind enumeration for LoadTypeLibEx. This must be made 
/// here, since it doesn't exist anywhere else in C# afaik. This is found 
/// here: http://msdn.microsoft.com/en-us/library/ms221159.aspx 
/// </summary> 
enum REGKIND 
{ 
    REGKIND_DEFAULT, 
    REGKIND_REGISTER, 
    REGKIND_NONE 
} 

// and this is how we get the library. 
[DllImport("oleaut32.dll", CharSet = CharSet.Unicode, PreserveSig = false)] 
    private static extern void LoadTypeLibEx(string strTypeLibName, REGKIND regKind, out ITypeLib TypeLib); 

Uf! Una vez que tenemos esto, tenemos que navegar por la estructura. Esto interactúa con recursos no administrados, así que prepárate para ser Marshal.

ITypeLib lib = null; 
LoadTypeLibEx(Value, REGKIND.REGKIND_NONE, out lib); 
IntPtr libInfoPtr = IntPtr.Zero; 
lib.GetLibAttr(out libInfoPtr); 
TYPELIBATTR libInfo = 
    (TYPELIBATTR) Marshal.PtrToStructure(libInfoPtr, typeof(TYPELIBATTR)); 
int typeCount = lib.GetTypeInfoCount(); 
for (int i = 0; i < typeCount; ++i) 
{ 
    ITypeInfo info; 
    lib.GetTypeInfo(i, out info); 
    IntPtr typeDescrPtr = IntPtr.Zero; 
    info.GetTypeAttr(out typeDescrPtr); 
    TYPELIBATTR type = 
     (TYPELIBATTR)Marshal.PtrToStructure(typeDescrPtr, typeof(TYPELIBATTR)); 
    // get GUID, other info from the specific type 
} 

lib.ReleaseTLibAttr(libInfoPtr); 
libInfoPtr = IntPtr.Zero; 

Whew. Entonces, tienes que escribir un código para extraer la información. Una vez que lo haga, debe completar esa información en Registy Entries, como se especifica en By Larry Osterman.

Por supuesto, puede evitar ese paso simplemente escribiendo su propio archivo IDL para comenzar.La elección del dolor: ¡depende de usted!

+0

Releí esto un par de veces, pero estoy muy confundido. No tengo idea de lo que has logrado aquí. –

+0

El código no es la solución. Visual Studio genera toda la información que se supone que debe hacer usted mismo en un archivo IDL como parte de regasm. Esto le permite descubrir qué hizo regasm en su nombre. Lo que se supone que debes hacer es crear un archivo IDL. –

+1

Si intentabas descubrir qué regasma pone en el tlb, ¿por qué no simplemente abrir el archivo tlb generado por regasm con oleview.exe? –

Cuestiones relacionadas