Frage Generieren Sie Manifestdateien für registrierungsfreie COM


Ich habe einige Anwendungen (einige native, einige .NET), die Manifest-Dateien verwenden, so dass sie sein können in vollständiger Isolation eingesetzt, ohne dass eine globale COM-Registrierung erforderlich ist. Zum Beispiel wird die Abhängigkeit vom com-Server dbgrid32.ocx in der Datei myapp.exe.manifest, die sich im selben Ordner wie myapp.exe befindet, wie folgt deklariert:

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

Die Datei dbgrid32.ocx wird zusammen mit ihrer eigenen Datei dbgrid32.ocx.manifest im selben Ordner bereitgestellt:

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

Dies alles funktioniert gut, aber die manuelle Verwaltung dieser Manifest-Dateien ist ein wenig schmerzhaft. Gibt es eine Möglichkeit, diese Dateien automatisch zu generieren? Idealerweise möchte ich nur die Abhängigkeit der Anwendung von einer Liste von COM-Servern (nativ und .NET) deklarieren und dann den Rest automatisch generieren lassen. Ist es möglich?


76
2018-01-21 16:07


Ursprung


Antworten:


Es sieht so aus, als ob die perfekte Lösung noch nicht existiert. Um einige Forschung zusammenzufassen:

Mache mein Manifestieren (Verknüpfung)

Dieses Tool durchsucht ein VB6-Projekt, um nach COM-Abhängigkeiten zu suchen, unterstützt jedoch auch die manuelle Deklaration von spät gebundenen COM-Abhängigkeiten (d. H. Die über CreateObject verwendeten).

Interessanterweise stellt dieses Tool alle Informationen zu den Abhängigkeiten innerhalb des Anwendungsmanifests zur Verfügung. Die Anwendung exe und ihre Abhängigkeiten werden als eine einzelne Assembly beschrieben, die aus mehreren Dateien besteht. Ich hatte vorher nicht bemerkt, dass dies möglich war.

Sieht wie ein sehr gutes Werkzeug aus, aber ab Version 0.6.6 hat es die folgenden Einschränkungen:

  • nur für VB6-Anwendungen, startet aus VB6-Projektdatei. Schade, weil vieles, was es tut, hat wirklich nichts zu tun mit VB6.
  • Wizard-Stil-Anwendung, nicht geeignet um in einen Build zu integrieren verarbeiten. Dies ist kein großes Problem, wenn Sie Abhängigkeiten ändern sich nicht viel.
  • Freeware ohne Quelle, riskant, sich darauf zu verlassen, weil sie jederzeit Abandonware werden könnte.

Ich habe nicht getestet, ob es .NET-com-Bibliotheken unterstützt.

regsvr42 (Codeprojektlink)

Dieses Befehlszeilentool generiert Manifestdateien für systemeigene COM-Bibliotheken. Es ruft DllRegisterServer auf und spioniert dann die Selbstregistrierung aus, während es Informationen in der Registrierung hinzufügt. Es kann auch ein Client-Manifest für Anwendungen generieren.

Dieses Dienstprogramm unterstützt keine .NET COM-Bibliotheken, da diese keine DllRegisterServer-Routine bereitstellen.

Das Dienstprogramm ist in C ++ geschrieben. Der Quellcode ist verfügbar.

mt.exe

Teil des Windows SDK (kann von heruntergeladen werden MSDN), die Sie bereits haben, wenn Sie Visual Studio installiert haben. Es ist dokumentiert hier. Sie können Manifestdateien für native COM-Bibliotheken damit erzeugen:

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

Sie können Manifest-Dateien für .NET-COM-Bibliotheken damit erzeugen:

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

Es gibt jedoch einige Probleme mit diesem Tool:

  • Das erste Snippet wird nicht generiert progid attributes, breaking clients die CreateObject mit progids verwenden.
  • Das zweite Snippet wird generiert <runtime>und <mvid> Elemente die vorher ausgestreift werden müssen Die Manifeste funktionieren tatsächlich.
  • Generierung von Client-Manifesten für Anwendungen werden nicht unterstützt.

Vielleicht werden zukünftige SDK-Versionen dieses Tool verbessern, ich habe das im Windows SDK 6.0a (vista) getestet.


56
2018-01-25 00:50



Mit der Aufgabe MSBuild GenerateApplicationManifest Ich habe an der Befehlszeile ein Manifest generiert, das mit dem Manifest identisch ist, das Visual Studio generiert. Ich vermute, Visual Studio verwendet die GenerateApplicationManifest während des Builds. Unten ist mein Build-Skript, das über die Befehlszeile mit dem Befehl "msbuild build.xml" ausgeführt werden kann.

Danke an Dave Templin und seine Post, der mich auf die GenerateApplicationManifest-Aufgabe hingewiesen hatund MSDNs weitere Dokumentation der Aufgabe.

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>

23
2018-06-14 15:22



Mach mein Manifest (MMM) ist ein nettes Werkzeug dafür. Es ist auch möglich, ein Skript zu schreiben, um alle Ihre DLL / OCX-Dateien mit zu verarbeiten mt.exe um für jeden einen Manifest zu generieren und sie dann alle zusammenzufügen. MMM ist normalerweise besser / einfacher, weil es auch viele spezielle / seltsame Fälle behandelt.


9
2018-01-21 16:17



Sie können verwenden Unbeaufsichtigt mach mein Manifest Spin Off, um Manifeste direkt in automatisierten Builds zu generieren. Es verwendet eine Skriptdatei, um abhängige COM-Komponenten hinzuzufügen. Dies ist ein Auszug aus dem Beispiel ini mit den verfügbaren Befehlen:

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

7
2017-10-14 19:22



Um die ProgIDs, die mt.exe nicht enthält, auszufüllen, können Sie anrufen ProgIDFromCLSID um sie von der Registrierung nachzuschlagen. Dies erfordert eine herkömmliche COM-Registrierung vor dem Ausfüllen der Manifestdatei, aber anschließend ist die Manifestdatei autark.

Dieser C # -Code fügt die ProgIDs allen COM-Klassen in einem Manifest hinzu:

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

Der Code basiert auf diesen Interop-Definitionen:

[DllImport("ole32.dll")] static extern int ProgIDFromCLSID([In] ref Guid clsid, [MarshalAs(UnmanagedType.LPWStr)] out string lplpszProgID);
const int S_OK = 0;

0
2018-04-06 02:32