Générer des fichiers manifestes pour COM sans inscription

87

J'ai des applications (certaines natives, d'autres .NET) qui utilisent des fichiers manifestes afin de pouvoir être déployées de manière totalement isolée , sans nécessiter d'enregistrement COM global. Par exemple, la dépendance sur le serveur dbgrid32.ocx com est déclarée comme suit dans le fichier myapp.exe.manifest qui se trouve dans le même dossier 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>

Le dbgrid32.ocx est déployé dans le même dossier, avec son propre fichier 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>

Tout cela fonctionne bien, mais la maintenance manuelle de ces fichiers manifestes est un peu pénible. Existe-t-il un moyen de générer ces fichiers automatiquement? Idéalement, je voudrais simplement déclarer la dépendance de l'application sur une liste de serveurs COM (natifs et .NET), puis laisser le reste être généré automatiquement. C'est possible?

Wim Coenen
la source
+1 également: regfreecom repensé car cette balise est plus courante pour le registre gratuit COM
MarkJ
Puis-je utiliser une version supérieure de mstscax.dll dans mon propre dossier d'installation par fichier manifeste?
Acewind
@acewind oui. (Vous voudrez peut-être publier une nouvelle question avec plus de détails.)
UuDdLrLrSs
@UuDdLrLrSs Bonne nouvelle! Je poste une nouvelle question ici: stackoverflow.com/questions/63575746/…
Acewind

Réponses:

63

Il semble que la solution parfaite n'existe pas encore. Pour résumer quelques recherches:

Créer mon manifeste ( lien )

Cet outil analyse un projet VB6 pour rechercher les dépendances COM, mais il prend également en charge la déclaration manuelle des dépendances COM à liaison tardive (c'est-à-dire celles utilisées via CreateObject).

Fait intéressant, cet outil met toutes les informations sur les dépendances dans le manifeste de l'application. L'exe d'application et ses dépendances sont décrits comme un seul assembly composé de plusieurs fichiers. Je n'avais pas réalisé avant que c'était possible.

Cela semble être un très bon outil, mais à partir de la version 0.6.6, il présente les limitations suivantes:

  • uniquement pour les applications VB6, démarre à partir du fichier de projet VB6. Dommage, car une grande partie de ce qu'il fait n'a vraiment rien à voir avec le VB6.
  • application de style assistant, ne convient pas à l'intégration dans un processus de construction. Ce n'est pas un gros problème si vos dépendances ne changent pas beaucoup.
  • freeware sans source, risqué de s'y fier car il pourrait devenir abandonware à tout moment.

Je n'ai pas testé s'il prend en charge les bibliothèques .NET com.

regsvr42 ( lien codeproject )

Cet outil de ligne de commande génère des fichiers manifestes pour les bibliothèques COM natives. Il invoque DllRegisterServer, puis espionne l'auto-enregistrement à mesure qu'il ajoute des informations dans le registre. Il peut également générer un manifeste client pour les applications.

Cet utilitaire ne prend pas en charge les bibliothèques .NET COM, car elles n'exposent pas une routine DllRegisterServer.

L'utilitaire est écrit en C ++. Le code source est disponible.

mt.exe

Une partie du SDK Windows (peut être téléchargé à partir de MSDN ), que vous avez déjà si vous avez installé Visual Studio. Il est documenté ici . Vous pouvez générer des fichiers manifestes pour les bibliothèques COM natives avec comme ceci:

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

Vous pouvez générer des fichiers manifestes pour les bibliothèques .NET COM comme ceci:

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

Cependant, il y a quelques problèmes avec cet outil:

  • Le premier extrait de code ne générera pas d'attributs prog, interrompant les clients qui utilisent CreateObject avec progids.
  • Le deuxième extrait va générer <runtime>et des <mvid>éléments qui doivent être dépouillés avant que les manifestes fonctionnent réellement.
  • La génération de manifestes client pour les applications n'est pas prise en charge.

Peut-être que les futures versions du SDK amélioreront cet outil, j'ai testé celui du SDK Windows 6.0a (vista).

Wim Coenen
la source
1
Je pense que vous avez manqué une option: mazecomputer.com mais je ne sais rien à ce sujet que le site Web ne décrit pas.
Bob
MMM redirigera également les DLL non COM (standard). Je ne suis pas sûr que les autres outils le fassent.
Bob
Juste une note pour les nerveux: la source de MMM a été publiée. Par contre, cela semble être dû au fait que l'auteur a décidé d'arrêter de travailler dessus. Encore un signe positif.
Gavin
2
Le site pour MMM n'est plus en place mais l'endroit où le code source a été placé est toujours disponible pour les v0.9 et v0.12 .
Scott Chamberlain
1
Je viens d'essayer mt.exe pour les bibliothèques .NET COM comme décrit ci-dessus et cela a fonctionné sans modification du manifeste en utilisant la version 7.1A. De plus, les liens pour MMM ne fonctionnaient pas mais Make My Manifest sans surveillance semble faire un travail décent.
bzuillsmith
28

Avec la tâche MSBuild GenerateApplicationManifest, j'ai généré un manifeste sur la ligne de commande identique au manifeste généré par Visual Studio. Je soupçonne que Visual Studio utilise le GenerateApplicationManifest pendant la génération. Voici mon script de construction qui peut être exécuté à partir de la ligne de commande en utilisant msbuild "msbuild build.xml"

Merci à Dave Templin et à son message qui m'a indiqué la tâche GenerateApplicationManifest et la documentation supplémentaire de MSDN sur la tâche .

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>
Mcdon
la source
Je pense que cela devrait vraiment être marqué comme la réponse à cette question. J'utilise maintenant cela pour automatiser toute notre génération de manifestes. Merci @mcdon, vous m'avez économisé beaucoup de travail.
Pete Magsig
Je conviens que c'est la meilleure solution lors de la création avec Visual Studio. Il n'est probablement pas mieux noté uniquement parce qu'il a été publié beaucoup plus tard que les autres réponses
dschaeffer
comment ajouter cela dans un csproj?
jle
@jle Je pense que vous pourriez l'ajouter à votre csproj dans la cible AfterBuild. Voici un lien de msdn et un autre article sur le sujet des événements de pré-construction et de post-construction. Remarque Je n'ai pas testé l'inclusion de cela dans le csproj, mais je pense que cela fonctionnerait.
mcdon
Le manifeste peut-il être généré pour une DLL C # COM, afin que n'importe quel exe puisse le consommer (plutôt que de générer un manifeste sur chaque exe, et y compris les DLL?)
GilesDMiddleton
9

Make My Manifest (MMM) est un bon outil pour ce faire. Il est également possible d'écrire un script pour traiter tous vos fichiers DLL / OCX à l'aide de mt.exe pour générer un manifeste pour chacun d'eux, puis les fusionner tous ensemble. MMM est généralement meilleur / plus facile, car il gère également de nombreux cas spéciaux / étranges.

jdve
la source
3
Je suis un peu nerveux à propos de ce truc MMM; c'est juste un blog, freeware mais pas de code source disponible, seulement un lien vers un "exe auto-extractible" et je vois des commentaires sur l'utilitaire provoquant le crash de XP. mmm ...
Wim Coenen
Ces "plantages" étaient l'utilitaire MMM lui-même mourant. Cela a été corrigé dans la version 0.6.5, mais vous voudrez quand même la 0.6.6, car bien qu'elle soit encore une version bêta, elle n'expire plus. Vous pouvez toujours utiliser MT.EXE à la place, comme déjà suggéré.
Bob
mt.exe ne génère pas de programme lorsque je l'utilise sur des serveurs com natifs comme dbgrid32.ocx
Wim Coenen
L'utilisation de COM sans reg avec des composants créés par .NET peut apparemment provoquer le plantage de XP - voir ce stackoverflow.com/questions/617253/…
MarkJ
8

Vous pouvez utiliser le spin off Unattended Make My Manifest pour générer des manifestes directement dans des builds automatisés. Il utilise un fichier de script pour ajouter des composants COM dépendants. Ceci est un extrait de l'exemple d'ini avec les commandes 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
#

Il fonctionnera sous Windows 32 ou 64 bits.

wqw
la source
+1 Intéressant, surtout parce que le code source est disponible. Je suis un peu confus par la similitude de nom, apparemment "rendre mon manifeste" et "rendre mon manifeste sans surveillance" sont des outils différents par différents auteurs.
Wim Coenen
2
Remarque - à partir de 2017 (8 ans après ...), ce projet est toujours actif avec des mises à jour de maintenance occasionnelles. github.com/wqweto/UMMM/commits/master . Cela fonctionne bien et je l'utilise régulièrement.
UuDdLrLrSs
0

Pour remplir les ProgID que mt.exe n'inclut pas, vous pouvez appeler ProgIDFromCLSIDpour les rechercher dans le registre. Cela nécessite une inscription COM traditionnelle avant de terminer le fichier manifeste, mais par la suite, le fichier manifeste sera autonome.

Ce code C # ajoute les ProgID à toutes les classes COM dans un manifeste:

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

Le code repose sur ces définitions d'interopérabilité:

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