为免注册 COM 生成清单文件

Posted

技术标签:

【中文标题】为免注册 COM 生成清单文件【英文标题】:Generate manifest files for registration-free COM 【发布时间】:2010-10-02 17:26:46 【问题描述】:

我有一些使用清单文件的应用程序(一些本机,一些 .NET),因此它们可以是deployed in complete isolation,而不需要任何全局 COM 注册。例如,对 dbgrid32.ocx com 服务器的依赖在 myapp.exe.manifest 文件中声明如下,该文件与 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>

dbgrid32.ocx 连同它自己的 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>

这一切都很好,但是手动维护这些清单文件有点麻烦。有没有办法自动生成这些文件?理想情况下,我只想声明应用程序对 COM 服务器(本机和 .NET)列表的依赖关系,然后让其余的自动生成。有可能吗?

【问题讨论】:

+1 还有:重新标记 regfreecom,因为该标记对于无注册表 COM 更常见 我可以通过清单文件在我自己的安装文件夹中使用更高版本的 mstscax.dll 吗? @acewind 是的。 (您可能想发布一个包含更多详细信息的新问题。) @UuDdLrLrSs 好消息!我在这里发布一个新问题:***.com/questions/63575746/… 【参考方案1】:

看起来完美的解决方案还不存在。总结一些研究:

制作我的清单 (link)

此工具扫描 VB6 项目以查找 COM 依赖项,但它也支持手动声明后期绑定的 COM 依赖项(即通过 CreateObject 使用的那些)。

有趣的是,这个工具将所有有关依赖项的信息放入应用程序清单中。应用程序 exe 及其依赖项被描述为由多个文件组成的单个程序集。我之前没有意识到这是可能的。

看起来是一个很好的工具,但从 0.6.6 版开始,它有以下限制:

仅适用于 VB6 应用程序,启动 来自 VB6 项目文件。惭愧,因为 它所做的很多事情真的无关紧要 使用 VB6。 向导风格的应用程序,不是 适合集成在构建中 过程。这不是一个大问题,如果你 依赖项没有太大变化。 没有源代码的免费软件,依赖它有风险,因为它随时可能成为废弃软件。

我没有测试它是否支持.NET com 库。

regsvr42 (codeproject link)

此命令行工具为本地 COM 库生成清单文件。它调用 DllRegisterServer,然后在将信息添加到注册表时监视自注册。它还可以为应用程序生成客户端清单。

此实用程序不支持 .NET COM 库,因为它们不公开 DllRegisterServer 例程。

该实用程序是用 C++ 编写的。源代码可用。

mt.exe

windows SDK 的一部分(可以从MSDN 下载),如果你安装了visual studio,你就已经拥有了。它是documented here。 您可以使用它为原生 COM 库生成清单文件,如下所示:

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

您可以使用它为 .NET COM 库生成清单文件,如下所示:

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

但是,这个工具存在一些问题:

第一个 sn-p 不会生成 progid 属性,破坏客户端 将 CreateObject 与 progids 一起使用。 第二个 sn-p 将生成 &lt;runtime&gt;&lt;mvid&gt; 元素 需要先去掉 清单确实有效。 生成客户端清单 不支持应用程序。

也许未来的 SDK 版本会改进这个工具,我在 Windows SDK 6.0a (vista) 中测试过。

【讨论】:

我认为您错过了一个选项:mazecomputer.com,但我对此网站一无所知。 MMM 还将重定向非 COM(标准)DLL。我不确定其他工具可以做到这一点。 只是给紧张的一个提示:MMM 的源代码已经发布。不利的一面是,这似乎是因为作者已决定停止研究它。仍然是一个积极的信号。 MMM 的站点已不再上线,但v0.9 和v0.12 仍然可以使用放置源代码的地方。 刚刚为 .NET COM 库尝试了 mt.exe,如上所述,它无需修改使用 v7.1A 的清单即可工作。此外,MMM 的链接不起作用,但 Unattented Make My Manifest 似乎做得不错。【参考方案2】:

通过 MSBuild 任务 GenerateApplicationManifest,我在命令行中生成了与 Visual Studio 生成的清单相同的清单。我怀疑 Visual Studio 在构建过程中使用了GenerateApplicationManifest。下面是我的构建脚本,可以使用 msbuild "msbuild build.xml" 从命令行运行

感谢 Dave Templin 和他的 post that pointed me the the GenerateApplicationManifest task,以及 MSDN 的 further documentation of the task。

构建.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,你为我节省了很多工作。 我同意这是使用 Visual Studio 构建时的最佳解决方案。它可能没有被评为更高,只是因为它比其他答案发布得晚了很多 如何将其添加到 csproj 中? @jle 我认为您可以将其添加到 AfterBuild 目标中的 csproj 中。这是关于预构建和构建后事件主题的link from msdn 和another post。 注意我没有在 csproj 中测试过,但我怀疑它会起作用。 迟到了 11 年,但感谢您的提及!【参考方案3】:

Make My Manifest (MMM) 是一个很好的工具。也可以编写一个脚本来处理所有的 DLL/OCX 文件,使用mt.exe 为每个文件生成一个清单,然后将它们合并在一起。 MMM 通常更好/更容易,因为它还可以处理许多特殊/奇怪的情况。

【讨论】:

我对这个 MMM 的事情有点紧张;它只是一个博客,免费软件,但没有可用的源代码,只有一个“自解压 exe”的链接,我看到有关该实用程序导致 XP 崩溃的 cmets。嗯... 那些“崩溃”是 MMM 实用程序本身死亡。这在 0.6.5 版本中已修复,但无论如何您都需要 0.6.6,因为虽然它仍然是测试版,但它不再过期。尽管已经建议,但您始终可以使用 MT.EXE。 mt.exe 在 dbgrid32.ocx 等本地 com 服务器上使用时不会生成 progid 将 reg free COM 与 .NET 编写的组件一起使用显然会导致 XP 崩溃 - 请参阅***.com/questions/617253/…【参考方案4】:

您可以使用Unattended Make My Manifest 分拆直接在自动构建中生成清单。它使用脚本文件来添加依赖的 COM 组件。这是带有可用命令的示例 ini 的摘录:

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

它将在 32 位或 64 位 Windows 上运行。

【讨论】:

+1 很有趣,特别是因为源代码可用。我对名称相似性有点困惑,显然“使我的清单”和“无人参与的使我的清单”是不同作者的不同工具。 注意 - 截至 2017 年(8 年过去了......),该项目仍然活跃,偶尔会进行维护更新。 github.com/wqweto/UMMM/commits/master 。它运作良好,我经常使用它。【参考方案5】:

要填写 mt.exe 不包含的 ProgID,您可以调用 ProgIDFromCLSID 从注册表中查找它们。这需要在完成清单文件之前进行传统的 COM 注册,但随后,清单文件将是自给自足的。

此 C# 代码将 ProgID 添加到清单中的所有 COM 类:

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

代码依赖于这些互操作定义:

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

【讨论】:

如果您通过 -rgs: 提供 rgs 文件,mt.exe 的最新版本确实包含 ProgID

以上是关于为免注册 COM 生成清单文件的主要内容,如果未能解决你的问题,请参考以下文章

关于.net 对.manifest清单文件查找缓存的猜想

在AndroidManifest(清单文件)中注册activity(活动)及配置主活动更改App图标App名称修改隐藏标题栏

如何为 Windows 上构建的 libxml2.dll 生成清单文件?

WPF: 菜单(Menu)中添加最近打开文件清单(Recent Files)

批处生成文件目录下所有文件名清单方法

如何为闪屏生成清单文件?