Генерировать файлы манифеста для регистрации-free COM

StackOverflow https://stackoverflow.com/questions/465882

Вопрос

У меня есть несколько приложений (некоторые собственные, некоторые .NET), которые используют файлы манифеста, чтобы они могли быть развернут в полной изоляции, не требуя какой-либо глобальной регистрации на COM.Например, зависимость от com-сервера dbgrid32.ocx объявлена следующим образом в файле 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), а затем позволить остальным генерироваться автоматически.Возможно ли это?

Это было полезно?

Решение

Похоже, идеального решения пока не существует.Подведем итог некоторым исследованиям:

Сделай Мой Манифест (Ссылка)

Этот инструмент сканирует проект VB6 для поиска COM-зависимостей, но он также поддерживает ручное объявление COM-зависимостей с поздней привязкой (т.е.те, которые используются через CreateObject).

Интересно, что этот инструмент помещает всю информацию о зависимостях внутрь манифеста приложения.Исполняемый файл приложения и его зависимости описаны как единая сборка, состоящая из нескольких файлов.Раньше я и не подозревал, что это возможно.

Выглядит как очень хороший инструмент, но начиная с версии 0.6.6, он имеет следующие ограничения:

  • только для приложений VB6, запускается из файла проекта VB6.Позор, потому что многое из того, что он делает, на самом деле не имеет ничего общего с VB6.
  • приложение в стиле мастера, не подходит для интеграции в процесс сборки .Это не огромная проблема, если ваши зависимости не сильно меняются.
  • бесплатная программа без исходного кода, полагаться на нее рискованно, потому что она может стать ненужной в любой момент.

Я не проверял, поддерживает ли он .NET com-библиотеки.NET.

regsvr42 (ссылка на кодовый проект)

Этот инструмент командной строки генерирует файлы манифеста для собственных COM-библиотек.Он вызывает DllRegisterServer, а затем отслеживает саморегистрацию, добавляя информацию в реестр.Он также может генерировать клиентский манифест для приложений.

Эта утилита не поддерживает COM-библиотеки .NET, поскольку они не предоставляют процедуру DllRegisterServer.

Утилита написана на C++.Исходный код доступен.

mt.exe

Часть пакета SDK для Windows (можно загрузить с MSDN), который у вас уже есть, если у вас установлена Visual Studio.Это так задокументировано здесь.Вы можете сгенерировать файлы манифеста для собственных 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, нарушая работу клиентов которые используют CreateObject с progids.
  • Второй фрагмент будет сгенерирован <runtime> и <mvid> элементы которые необходимо удалить, прежде чем манифесты действительно заработают.
  • Генерация клиентских манифестов для приложений не поддерживается.

Возможно, будущие выпуски SDK улучшат этот инструмент, я протестировал его в Windows SDK 6.0a (vista).

Другие советы

С помощью задачи MSBuild Генерировать проявление приложения Я сгенерировал манифест в командной строке, идентичный манифесту, который генерирует Visual Studio.Я подозреваю, что Visual Studio использует Генерировать проявление приложения во время сборки.Ниже приведен мой скрипт сборки, который можно запустить из командной строки с помощью msbuild "msbuild build.xml"

Спасибо Дейву Темплину и его сообщение, которое указало мне на задачу GenerateApplicationManifest, и MSDN's дальнейшее документирование задачи.

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>

Сделай Мой Манифест (МММ) это хороший инструмент для этого.Также возможно написать скрипт для обработки всех ваших DLL / OCX файлов с помощью mt.exe сгенерировать манифест для каждого из них, а затем объединить их все вместе.MMM обычно лучше / проще, потому что он также обрабатывает множество особых / странных случаев.

Вы можете использовать Оставленный без Присмотра, Делаю Свой Манифест спин-офф для создания манифестов непосредственно в автоматических сборках.Он использует файл сценария для добавления зависимых 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.

Чтобы заполнить прогиды, которые mt.exe не включены, вы можете вызвать ProgIDFromCLSID чтобы посмотреть их в реестре.Для этого требуется традиционная регистрация COM до заполнения файла манифеста, но впоследствии файл манифеста будет самодостаточным.

Этот код на C # добавляет PROGIDS ко всем 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;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top