windows - modificar - Generación e instalación de Typelib con WiX
metaetiqueta wix (3)
Después de preguntar qué hace Visual Studio para registrar una Biblioteca COM , quedó claro que VS hizo dos cosas para el registro COM:
- Registrado la Biblioteca COM
- Crea y registra una biblioteca de tipos
Visual Studio parece hacer este registro usando regasm.exe. Para la primera parte (el registro directo de COM) 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 tipo biblioteca. 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 el instalador de Microsoft.
Tras 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, un artículo aquí en wix tiene un ejemplo de rellenar el elemento TypeLib con elementos de interfaz .
Parece que hay al menos dos atributos obligatorios para un elemento de interfaz:
- Carné de identidad
- Nombre
Larry Osterman habla sobre las otras partes de la interfaz que deben registrarse para un TypeLib en general , y esta entrada de interfaz parece ocuparse de las partes individuales. Larry dice que necesitamos especificar el ProxyStubClassId32 como "{00020424-0000-0000-C000-000000000046}", por lo que podemos agregarlo fácilmente.
A dó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 de wcoenen parece prometedora ... Voy a intentarlo.
Actualización: Publiqué mi solución final a continuación como respuesta.
Esta es la forma de resolver este problema: Usar heat
de WiX 3.0.
Si tiene una biblioteca de tipos generada automáticamente e instalada a través de regasm, el heat
puede tomar el .tlb como argumento en
heat file c:/my/path/to/my.tlb -out tlb.wxs
Generará todos los elementos de interfaz e interfaz de línea que necesite registrar. 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.
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.
Primero, devuelva su registro a un estado donde la biblioteca de tipos no estaba registrada:
c:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/regasm.exe /tlb /u mylib.dll
Exporte este estado limpio del registro a hklm-before.reg:
c:/WINDOWS/system32/reg.exe export HKLM hklm-before.reg
Registre la biblioteca de tipos nuevamente:
c:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/regasm.exe /tlb mylib.dll
Exporte el nuevo estado del registro a hklm-after.reg:
c:/WINDOWS/system32/reg.exe export HKLM hklm-after.reg
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).
Ahora podemos convertir diff.reg en a .wxs llamando a
heat.exe
con el comandoreg
. (Requiere wix 3.5 o posterior).heat reg diff.reg -out typelib.wxs
Parece que para registrar una biblioteca de tipos, la mejor manera sería generar su propio archivo IDL u 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 que se necesita: hay ciertas claves de registro que deben establecerse. 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. Comencé un proyecto, y con algunas declaraciones de uso 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 está interactuando con recursos no administrados, así que prepárate para ser el Marshal
las cosas.
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;
Uf. 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, según lo especificado por Larry Osterman .
Por supuesto, puede evitar ese paso simplemente escribiendo su propio archivo IDL para comenzar. La elección del dolor: ¡depende de usted!