首页 文章

为免注册COM生成清单文件

提问于
浏览
81

我有一些应用程序(一些本机,一些.NET)使用清单文件,因此它们可以是deployed in complete isolation,无需任何全局COM注册 . 例如,在myapp.exe.manifest文件中声明对dbgrid32.ocx com服务器的依赖关系如下,该文件与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)的依赖关系,然后自动生成其余部分 . 可能吗?

5 回答

  • 25

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

    Make My Manifestlink

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

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

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

    • 仅适用于VB6应用程序,从VB6项目文件开始 . 很遗憾,因为它的很多功能与VB6无关 .

    • 向导样式应用程序,不适合在构建过程中集成 . 如果您的依赖关系不会发生很大变化,这不是一个大问题 .
      没有来源的

    • 免费软件,有可能依赖它,因为它可能随时变成放弃软件 .

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

    regsvr42codeproject 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
    

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

    • 第一个片段不会生成progid属性,从而破坏了使用带有progid的CreateObject的客户端 .

    • 第二个片段将生成 <runtime><mvid> 元素,需要在清单实际工作之前将其删除 .

    • 不支持为应用程序生成客户端清单 .

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

  • 0

    使用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 .

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

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

  • 9

    您可以使用Unattended Make My Manifest spin off直接在自动构建中生成清单 . 它使用脚本文件添加依赖的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上运行 .

  • 57

    要填写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;
    

相关问题