Pregunta

Tengo algunas aplicaciones (algunas nativas, otras .NET) que usan archivos de manifiesto para que puedan ser desplegado en completo aislamiento, sin requerir ningún registro COM global.Por ejemplo, la dependencia del servidor com dbgrid32.ocx se declara de la siguiente manera en el archivo myapp.exe.manifest que se encuentra en la misma carpeta que myapp.exe:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
  <assemblyIdentity type="win32" name="myapp.exe" version="1.2.3.4" />
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type="win32" name="dbgrid32.ocx" version="5.1.81.4" />
    </dependentAssembly>
  </dependency>
</assembly>

El archivo dbgrid32.ocx se implementa en la misma carpeta, junto con su propio archivo dbgrid32.ocx.manifest:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
  <assemblyIdentity type="win32" name="dbgrid32.ocx" version="5.1.81.4" />
  <file name="dbgrid32.ocx">
     <typelib
        tlbid="{00028C01-0000-0000-0000-000000000046}"
        version="1.0"
        helpdir=""/>
    <comClass progid="MSDBGrid.DBGrid"
       clsid="{00028C00-0000-0000-0000-000000000046}"
       description="DBGrid  Control" />
  </file>
</assembly>

Todo esto funciona bien, pero mantener estos archivos de manifiesto manualmente es un poco complicado.¿Hay alguna manera de generar estos archivos automáticamente?Lo ideal sería declarar la dependencia de la aplicación en una lista de servidores COM (tanto nativos como .NET) y luego dejar que el resto se genere automáticamente.¿Es posible?

¿Fue útil?

Solución

Parece que la solución perfecta aún no existe.Para resumir algunas investigaciones:

hacer mi manifiesto (enlace)

Esta herramienta escanea un proyecto VB6 para buscar dependencias COM, pero también admite la declaración manual de dependencias COM de enlace tardío (es decir,aquellos utilizados a través de CreateObject).

Curiosamente, esta herramienta coloca toda la información sobre las dependencias dentro del manifiesto de la aplicación.La aplicación exe y sus dependencias se describen como un único ensamblaje que consta de varios archivos.No me había dado cuenta antes de que esto fuera posible.

Parece una muy buena herramienta pero a partir de la versión 0.6.6 tiene las siguientes limitaciones:

  • solo para aplicaciones VB6, se inicia del archivo de proyecto VB6.Vergüenza, porque Mucho de lo que hace realmente no tiene nada que ver con VB6.
  • aplicación de estilo asistente, no Adecuado para integrar en una compilación proceso.Esto no es un gran problema si su Las dependencias no cambian mucho.
  • software gratuito sin fuente, es arriesgado confiar en él porque podría convertirse en software abandonado en cualquier momento.

No probé si es compatible con bibliotecas .NET com.

regsvr42 (enlace del proyecto de código)

Esta herramienta de línea de comandos genera archivos de manifiesto para bibliotecas COM nativas.Invoca a DllRegisterServer y luego espía el autorregistro mientras agrega información al registro.También puede generar un manifiesto de cliente para aplicaciones.

Esta utilidad no admite bibliotecas COM .NET, ya que no exponen una rutina DllRegisterServer.

La utilidad está escrita en C++.El código fuente está disponible.

mt.exe

Parte del SDK de Windows (se puede descargar desde MSDN), que ya tienes si tienes Visual Studio instalado.Es documentado aquí.Puede generar archivos de manifiesto para bibliotecas COM nativas de esta manera:

mt.exe -tlb:mycomlib.ocx -dll:mycomlib.ocx -out:mycomlib.ocx.manifest

Puede generar archivos de manifiesto para bibliotecas .NET COM de esta manera:

mt.exe -managedassemblyname:netlib.dll -nodependency -out:netlib.dll.manifest

Sin embargo, existen algunos problemas con esta herramienta:

  • El primer fragmento no se generará progid atributos, rompiendo clientes que usan CreateObject con progids.
  • El segundo fragmento generará<runtime> y <mvid> Elementos que deben ser eliminados antes de Los manifiestos realmente funcionan.
  • La generación de manifiestas de clientes para aplicaciones no es compatible.

Quizás futuras versiones del SDK mejoren esta herramienta; probé la del SDK de Windows 6.0a (vista).

Otros consejos

Con la tarea MSBuild GenerateApplicationManifest generé un manifiesto con el comando línea idéntica al manifiesto que genera Visual Studio. Sospecho que Visual Studio usa el GenerateApplicationManifest durante la compilación. A continuación se muestra mi script de compilación que se puede ejecutar desde la línea de comandos usando msbuild & Quot; msbuild build.xml & Quot;

Gracias a Dave Templin y su publicación que me señaló la tarea GenerateApplicationManifest , y MSDN < a href = "http://msdn.microsoft.com/en-us/library/6wc2ccdc.aspx" rel = "noreferrer"> documentación adicional de la tarea .

build.xml

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <Target Name="Build">
        <ItemGroup>
            <File Include='MyNativeApp.exe'/>
            <ComComponent Include='Com1.ocx;Com2.ocx'/>
        </ItemGroup>
        <GenerateApplicationManifest
            AssemblyName="MyNativeApp.exe"
            AssemblyVersion="1.0.0.0"
            IsolatedComReferences="@(ComComponent)"
            Platform="x86"
            ManifestType="Native">
            <Output
                ItemName="ApplicationManifest"
                TaskParameter="OutputManifest"/>
        </GenerateApplicationManifest>
    </Target>   
</Project>

Make My Manifest (MMM) es una buena herramienta para hacerlo. También es posible escribir un script para procesar todos sus archivos DLL / OCX usando mt.exe para generar un manifiesto para cada uno y luego combinarlos todos juntos. MMM suele ser mejor / más fácil, porque también maneja muchos casos especiales / extraños.

Puede usar Desenfoque de hacer mi manifiesto para generar manifiestos directamente en compilaciones automatizadas. Utiliza un archivo de script para agregar componentes COM dependientes. Este es un extracto del ejemplo ini con los comandos disponibles:

# Unattended MMM script
#
# Command names are case-insensitive. Reference of supported commands:
#
# Command: Identity
#
#   Appends assemblyIdentity and description tags.
#
#   Parameters       <exe_file> [name] [description]
#      exe_file      file name can be quoted if containing spaces. The containing folder 
#                    of the executable sets base path for relative file names
#      name          (optional) assembly name. Defaults to MyAssembly
#      description   (optional) description of assembly
#
# Command: Dependency
#
#   Appends dependency tag for referencing dependent assemblies like Common Controls 6.0, 
#     VC run-time or MFC
#
#   Parameters       {<lib_name>|<assembly_file>} [version] [/update]
#     lib_name       one of { comctl, vc90crt, vc90mfc }
#     assembly_file  file name of .NET DLL exporting COM classes
#     version        (optional) required assembly version. Multiple version of vc90crt can
#                    be required by a single manifest
#     /update        (optional) updates assembly_file assembly manifest. Spawns mt.exe
#
# Command: File
#
#   Appends file tag and collects information about coclasses and interfaces exposed by 
#     the referenced COM component typelib.
#
#   Parameters       <file_name> [interfaces]
#     file_name      file containing typelib. Can be relative to base path
#     interfaces     (optional) pipe (|) separated interfaces with or w/o leading 
#                    underscore
#
# Command: Interface
#
#   Appends comInterfaceExternalProxyStub tag for inter-thread marshaling of interfaces
#
#   Parameters       <file_name> <interfaces>
#     file_name      file containing typelib. Can be relative to base path
#     interfaces     pipe (|) separated interfaces with or w/o leading underscore
#
# Command: TrustInfo
#
#   Appends trustInfo tag for UAC user-rights elevation on Vista and above
#
#   Parameters       [level] [uiaccess]
#     level          (optional) one of { 1, 2, 3 } corresponding to { asInvoker, 
#                    highestAvailable, requireAdministrator }. Default is 1
#     uiaccess       (optional) true/false or 0/1. Allows application to gain access to 
#                    the protected system UI. Default is 0
#
# Command: DpiAware
#
#   Appends dpiAware tag for custom DPI aware applications
#
#   Parameters       [on_off]
#     on_off         (optional) true/false or 0/1. Default is 0
#
# Command: SupportedOS
#
#   Appends supportedOS tag
#
#   Parameters       <os_type>
#     os_type        one of { vista, win7 }. Multiple OSes can be supported by a single 
#                    manifest
#

Se ejecutará en Windows de 32 o 64 bits.

Para completar los ProgID que mt.exe no incluye, puede llamar a ProgIDFromCLSID para buscarlos desde el registro. Esto requiere el registro COM tradicional antes de completar el archivo de manifiesto, pero posteriormente, el archivo de manifiesto será autosuficiente.

Este código C # agrega los ProgID a todas las clases COM en un manifiesto:

var manifest = XDocument.Load(fileName);
var namespaceManager = new XmlNamespaceManager(new NameTable());
namespaceManager.AddNamespace("s", "urn:schemas-microsoft-com:asm.v1");
foreach (var classElement in manifest.XPathSelectElements("s:assembly/s:file/s:comClass", namespaceManager)) {
    var clsid = Guid.Parse(classElement.Attribute("clsid").Value);
    int result = ProgIDFromCLSID(ref clsid, out string progId); if (result != S_OK) throw new COMException($"ProgID lookup failed for {clsid}.", result);
    classElement.SetAttributeValue("progid", progId);
}
manifest.Save(fileName);

El código se basa en estas definiciones de interoperabilidad:

[DllImport("ole32.dll")] static extern int ProgIDFromCLSID([In] ref Guid clsid, [MarshalAs(UnmanagedType.LPWStr)] out string lplpszProgID);
const int S_OK = 0;
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top