it-swarm.com.de

Erzeugen Sie Manifestdateien für die registrierungsfreie COM

Ich habe einige Anwendungen (einige native, einige .NET), die Manifest-Dateien verwenden, damit sie in vollständiger Isolation eingesetzt werden können , ohne dass eine globale COM-Registrierung erforderlich ist. Beispielsweise 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 das manuelle Managen dieser Manifestdateien ist ein bisschen schmerzhaft. Gibt es eine Möglichkeit, diese Dateien automatisch zu generieren? Im Idealfall möchte ich nur die Abhängigkeit der Anwendung von einer Liste von COM-Servern (sowohl native als auch .NET) angeben und den Rest dann automatisch generieren lassen. Ist es möglich?

81
Wim Coenen

Es sieht so aus, als gäbe es die perfekte Lösung noch nicht. Um einige Forschungsergebnisse zusammenzufassen:

Mache mein Manifest ( link )

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

Interessanterweise fügt dieses Tool alle Informationen zu den Abhängigkeiten in das Anwendungsmanifest ein. Das Anwendungsexe und seine Abhängigkeiten werden als eine einzelne Assembly beschrieben, die aus mehreren Dateien besteht. Mir war vorher nicht klar, dass dies möglich ist.

Sieht nach einem sehr guten Werkzeug aus, hat jedoch ab Version 0.6.6 die folgenden Einschränkungen:

  • startet nur für VB6-Anwendungen aus der VB6-Projektdatei. Schade, denn Viel von dem, was es tut, hat wirklich nichts mit Mit VB6 zu tun.
  • assistenten-Stilanwendung, nicht geeignet für die Integration in einen Build-Prozess. Dies ist kein großes Problem, wenn sich Ihre Abhängigkeiten nicht viel ändern.
  • freeware ohne Quellcode und riskant, sich darauf zu verlassen, da es jederzeit zu Verzicht auf Software werden könnte.

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

regsvr42 ( codeproject link )

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

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

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

mt.exe

Ein Teil des Windows SDK (kann von MSDN heruntergeladen werden), das Sie bereits installiert haben, wenn Sie Visual Studio installiert haben. Es ist hier dokumentiert . Man kann Manifestdateien für native COM-Bibliotheken so erstellen:

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

Sie können Manifestdateien für .NET COM-Bibliotheken folgendermaßen erstellen:

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

Es gibt jedoch einige Probleme mit diesem Tool:

  • Das erste Snippet generiert keine Progid-Attribute, wodurch Clients Beschädigt werden, die CreateObject mit Progids verwenden.
  • Das zweite Snippet generiert <runtime>- und <mvid> Elemente Die entfernt werden müssen, bevor Die Manifeste tatsächlich funktionieren.
  • Die Generierung von Clientmanifesten für -Anwendungen wird nicht unterstützt.

Möglicherweise verbessern zukünftige SDK-Versionen dieses Tool. Ich habe das im Windows SDK 6.0a (Vista) getestet.

57
Wim Coenen

Mit der MSBuild-Task GenerateApplicationManifest habe ich ein Manifest in der Befehlszeile generiert, das mit dem Manifest identisch ist, das Visual Studio generiert. Ich vermute, Visual Studio verwendet während des Builds das GenerateApplicationManifest . Im Folgenden finden Sie mein Build-Skript, das von der Befehlszeile aus mit "msbuild build.xml" ausgeführt werden kann.

Dank an Dave Templin und seinen Beitrag, der auf die GenerateApplicationManifest-Task und MSDN's weitere Dokumentation der Task hingewiesen hat.

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>
24
mcdon

Make My Manifest (MMM) ist ein schönes Werkzeug, um dies zu tun. Es ist auch möglich, ein Skript zu schreiben, um alle Ihre DLL-/OCX-Dateien zu verarbeiten, indem Sie mt.exe verwenden, um ein Manifest für jede einzelne Datei zu erstellen und sie dann zusammenzuführen. MMM ist in der Regel besser/einfacher, da es auch viele spezielle/seltsame Fälle bewältigt.

9
jdve

Sie können Unattended Make Man Manifest Spin Off verwenden, 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
#

Es läuft unter 32 oder 64 Bit Windows.

7
wqw

Um die ProgIDs einzugeben, die mt.exe nicht enthält, können Sie ProgIDFromCLSID aufrufen, um sie aus der Registry herauszufinden. Dies erfordert eine herkömmliche COM-Registrierung, bevor die Manifestdatei abgeschlossen wird. Anschließend ist die Manifestdatei jedoch autark.

Dieser C # -Code fügt die ProgIDs zu 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
Edward Brey