Создать файлы манифеста для COM без регистрации - PullRequest
81 голосов
/ 21 января 2009

У меня есть несколько приложений (некоторые родные, некоторые .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), а затем позволить генерировать остальные автоматически. Возможно ли это?

Ответы [ 5 ]

58 голосов
/ 25 января 2009

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

Make My Manifest ( ссылка )

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

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

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

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

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

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

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

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

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

mt.exe

Часть пакета Windows SDK (можно загрузить с 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

Однако есть некоторые проблемы с этим инструментом:

  • Первый фрагмент не будет генерироваться Прогидные атрибуты, ломающие клиентов которые используют CreateObject с progids.
  • Второй фрагмент будет сгенерирован <runtime> и <mvid> элементы которые должны быть удалены перед манифесты действительно работают.
  • Генерация клиентских манифестов для приложения не поддерживаются.

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

25 голосов
/ 14 июня 2012

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

Благодаря Дейву Темплину и его посту, который указал мне на задачу GenerateApplicationManifest , и MSDN дальнейшее документирование задачи .

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>
9 голосов
/ 21 января 2009

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

7 голосов
/ 14 октября 2009

Вы можете использовать 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.

0 голосов
/ 06 апреля 2018

Чтобы ввести ProgID, которые не включены в mt.exe, вы можете позвонить 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;
...