Domanda

Ho alcune applicazioni (alcune native, altre .NET) che usano file manifest in modo che possano essere distribuito in completo isolamento , senza richiedere alcuna registrazione COM globale. Ad esempio, la dipendenza dal server com dbgrid32.ocx è dichiarata come segue nel file myapp.exe.manifest che si trova nella stessa cartella di 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>

Il dbgrid32.ocx è distribuito nella stessa cartella, insieme al proprio file 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>

Tutto funziona bene, ma mantenere questi file manifest manualmente è un po 'una seccatura. C'è un modo per generare automaticamente questi file? Idealmente, vorrei solo dichiarare la dipendenza dell'applicazione da un elenco di server COM (sia nativi che .NET) e quindi lasciare che il resto venga generato automaticamente. È possibile?

È stato utile?

Soluzione

Sembra che la soluzione perfetta non esista ancora. Riassumendo alcune ricerche:

Make My Manifest ( link )

Questo strumento esegue la scansione di un progetto VB6 alla ricerca di dipendenze COM, ma supporta anche la dichiarazione manuale delle dipendenze COM in ritardo (ovvero quelle utilizzate tramite CreateObject).

È interessante notare che questo strumento mette tutte le informazioni sulle dipendenze all'interno del manifest dell'applicazione. L'esempio dell'applicazione e le sue dipendenze sono descritte come un singolo assembly costituito da più file. Non mi ero reso conto prima che ciò fosse possibile.

Sembra un ottimo strumento ma dalla versione 0.6.6 presenta i seguenti limiti:

  • solo per applicazioni VB6, avvia dal file di progetto VB6. Peccato, perché molto di ciò che fa non ha davvero nulla da fare con VB6.
  • applicazione in stile procedura guidata, no adatto per l'integrazione in una build processi. Questo non è un grosso problema se il tuo le dipendenze non cambiano molto.
  • freeware senza sorgente, rischioso di fare affidamento su di esso perché potrebbe diventareandonware in qualsiasi momento.

Non ho verificato se supporta le librerie .NET.

regsvr42 ( collegamento codeproject )

Questo strumento da riga di comando genera file manifest per le librerie COM native. Invoca DllRegisterServer e quindi spie sull'auto-registrazione mentre aggiunge informazioni al registro. Può anche generare un manifest client per le applicazioni.

Questa utility non supporta le librerie COM .NET, poiché non espongono una routine DllRegisterServer.

L'utilità è scritta in C ++. Il codice sorgente è disponibile.

Mt.exe

Parte dell'SDK di Windows (può essere scaricato da MSDN ), che hai già se hai installato Visual Studio. È documentato qui . È possibile generare file manifest per le librerie COM native con esso in questo modo:

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

È possibile generare file manifest per le librerie COM .NET in questo modo:

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

Tuttavia, ci sono alcuni problemi con questo strumento:

  • Il primo frammento non verrà generato attributi progid, rompendo i clienti che usano CreateObject con progids.
  • Verrà generato il secondo frammento <runtime> e <mvid> elementi che devono essere rimossi prima i manifest funzionano davvero.
  • Generazione di manifest client per le applicazioni non sono supportate.

Forse le future versioni dell'SDK miglioreranno questo strumento, ho testato quello in Windows SDK 6.0a (vista).

Altri suggerimenti

Con l'attività MSBuild GenerateApplicationManifest ho generato un manifest al comando linea identica al file manifest di Visual Studio. Sospetto che Visual Studio utilizzi il GenerateApplicationManifest durante la compilazione. Di seguito è riportato il mio script build che può essere eseguito dalla riga di comando usando msbuild & Quot; msbuild build.xml & Quot;

Grazie a Dave Templin e al suo che mi hanno indicato l'attività GenerateApplicationManifest e MSDN < a href = "http://msdn.microsoft.com/en-us/library/6wc2ccdc.aspx" rel = "noreferrer"> ulteriore documentazione dell'attività .

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) è un ottimo strumento per farlo. È anche possibile scrivere uno script per elaborare tutti i file DLL / OCX utilizzando mt.exe per generare un manifest per ognuno e poi unirli tutti insieme. MMM è generalmente migliore / più facile, perché gestisce anche molti casi speciali / strani.

Puoi utilizzare Unattended Make My Manifest per generare manifest direttamente nelle build automatizzate. Utilizza un file di script per aggiungere componenti COM dipendenti. Questo è un estratto dall'ini di esempio con i comandi disponibili:

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

Funzionerà su Windows a 32 o 64 bit.

Per compilare i ProgID che mt.exe non include, è possibile chiamare ProgIDFromCLSID per cercarli dal registro. Ciò richiede la registrazione COM tradizionale prima di completare il file manifest, ma successivamente il file manifest sarà autosufficiente.

Questo codice C # aggiunge i ProgID a tutte le classi COM in un manifest:

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);

Il codice si basa su queste definizioni di interoperabilità:

[DllImport("ole32.dll")] static extern int ProgIDFromCLSID([In] ref Guid clsid, [MarshalAs(UnmanagedType.LPWStr)] out string lplpszProgID);
const int S_OK = 0;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top