Genera file manifest per COM senza registrazione


87

Ho alcune applicazioni (alcune native, alcune .NET) che utilizzano file manifest in modo che possano essere distribuite 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 viene 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>

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


+1 anche: regfreecom ricodificato poiché quel tag è più comune per COM senza registro
MarkJ

Posso usare una versione successiva mstscax.dll nella mia cartella di installazione tramite file manifest?
Acewind

@acewind yes. (Puoi pubblicare una nuova domanda con maggiori dettagli.)
UuDdLrLrSs

@UuDdLrLrSs Buone notizie! Ho posto una nuova domanda qui: stackoverflow.com/questions/63575746/...
Acewind

Risposte:


63

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

Crea il mio manifesto ( collegamento )

Questo strumento analizza un progetto VB6 per cercare le dipendenze COM, ma supporta anche la dichiarazione manuale delle dipendenze COM late-bound (cioè quelle usate tramite CreateObject).

È interessante notare che questo strumento inserisce tutte le informazioni sulle dipendenze all'interno del manifesto dell'applicazione. L'exe dell'applicazione e le sue dipendenze sono descritti come un singolo assembly costituito da più file. Non mi ero reso conto prima che questo fosse possibile.

Sembra uno strumento molto buono ma a partire dalla versione 0.6.6 ha le seguenti limitazioni:

  • solo per applicazioni VB6, parte dal file progetto VB6. Peccato, perché molto di quello che fa non ha davvero nulla a che fare con VB6.
  • applicazione in stile procedura guidata, non adatta per l'integrazione in un processo di compilazione. Questo non è un grosso problema se le tue dipendenze non cambiano molto.
  • freeware senza sorgente, rischioso affidarsi ad esso perché potrebbe diventare in ogni momento un abbandono.

Non ho verificato se supporta le librerie .NET com.

regsvr42 ( link progetto di codice )

Questo strumento da riga di comando genera file manifest per le librerie COM native. Richiama DllRegisterServer e quindi spia l'autoregistrazione mentre aggiunge informazioni nel registro. Può anche generare un manifesto client per le applicazioni.

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

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

mt.exe

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

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

Puoi generare file manifest per le librerie .NET COM con esso 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 genererà attributi progid, interrompendo i client che utilizzano CreateObject con progid.
  • Il secondo frammento genera <runtime>e <mvid>gli elementi che devono essere rimossi prima i manifesti effettivamente funzionare.
  • La generazione di manifesti client per le applicazioni non è supportata.

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


1
Penso che tu abbia perso un'opzione: mazecomputer.com ma non ne so nulla che il sito web non descrive.
Bob

MMM reindirizzerà anche le DLL non COM (standard). Non sono sicuro che gli altri strumenti lo facciano.
Bob,

Solo una nota per i nervosi: la fonte per MMM è stata rilasciata. Al rovescio della medaglia, questo sembra essere dovuto al fatto che l'autore ha deciso di smettere di lavorarci. Ancora un segnale positivo.
Gavin

2
Il sito per MMM non è più attivo, ma il luogo in cui è stato inserito il codice sorgente è ancora disponibile per v0.9 e v0.12 .
Scott Chamberlain

1
Ho appena provato mt.exe per le librerie .NET COM come descritto sopra e ha funzionato senza modifiche al manifest utilizzando v7.1A. Inoltre, i collegamenti per MMM non funzionavano, ma Unattented Make My Manifest sembra fare un lavoro decente.
bzuillsmith

28

Con l'attività di MSBuild GenerateApplicationManifest ho generato un manifest sulla riga di comando identico al manifest generato da Visual Studio. Sospetto che Visual Studio utilizzi GenerateApplicationManifest durante la compilazione. Di seguito è riportato il mio script di compilazione che può essere eseguito dalla riga di comando utilizzando msbuild "msbuild build.xml"

Grazie a Dave Templin e al suo post che mi ha indicato l'attività GenerateApplicationManifest e l' ulteriore documentazione dell'attività di MSDN .

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>

Penso che questo dovrebbe davvero essere contrassegnato come la risposta a questa domanda. Ora lo sto usando per automatizzare tutta la nostra generazione di manifest. Grazie @mcdon, mi hai risparmiato molto lavoro.
Pete Magsig

Sono d'accordo che questa sia la soluzione migliore quando si crea con Visual Studio. Probabilmente non è classificato più alto solo perché è stato pubblicato molto più tardi rispetto alle altre risposte
dschaeffer

come aggiungerlo in un csproj?
jle

@jle Penso che potresti aggiungerlo al tuo csproj nel target AfterBuild. Ecco un collegamento da msdn e un altro post sull'argomento degli eventi di prebuild e postbuild. Nota che non ho testato includendolo nel csproj, ma sospetto che funzionerebbe.
mcdon

Il manifest può essere generato per una DLL COM C #, in modo che qualsiasi exe possa utilizzarlo (piuttosto che generare un manifest su ogni exe e includere le DLL?)
GilesDMiddleton

9

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 ciascuno e quindi unirli tutti insieme. MMM di solito è migliore / più facile, perché gestisce anche molti casi speciali / strani.


3
Sono un po 'nervoso per questa cosa del MMM; è solo un blog, freeware ma nessun codice sorgente disponibile, solo un collegamento a un "file exe autoestraente" e vedo commenti sull'utilità che causa l'arresto anomalo di XP. mmm ...
Wim Coenen

Quei "crash" erano la stessa utility MMM che stava morendo. Questo problema è stato risolto nella versione 0.6.5 ma ti consigliamo comunque la 0.6.6, poiché sebbene sia ancora una beta non scade più. Puoi sempre usare MT.EXE invece come già suggerito.
Bob

mt.exe non genera progid quando lo uso su server com nativi come dbgrid32.ocx
Wim Coenen

L'uso di COM senza registrazione con componenti creati da .NET può apparentemente causare l'arresto anomalo di XP - vedere questo stackoverflow.com/questions/617253/…
MarkJ

8

È possibile utilizzare lo spin off Crea il mio manifesto automatico per generare manifesti direttamente nelle build automatiche. 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.


+1 Interessante, soprattutto perché il codice sorgente è disponibile. Sono un po 'confuso dalla somiglianza del nome, apparentemente "rendi il mio manifesto" e "rendi il mio manifesto non assistito" sono strumenti diversi di autori diversi.
Wim Coenen

2
Nota: dal 2017 (8 anni dopo ...) questo progetto è ancora attivo con aggiornamenti di manutenzione occasionali. github.com/wqweto/UMMM/commits/master . Funziona bene e lo uso regolarmente.
UuDdLrLrSs

0

Per compilare i ProgID che mt.exe non include, puoi chiamare ProgIDFromCLSIDper 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;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.