Создание файлов манифеста для COM без регистрации

87

У меня есть некоторые приложения (некоторые из них, некоторые из .NET), которые используют файлы манифеста, поэтому их можно развернуть в полной изоляции , не требуя какой-либо глобальной регистрации 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 без регистрации
MarkJ
Могу ли я использовать более позднюю версию mstscax.dll в моей папке установки с помощью файла манифеста?
Acewind
@acewind да. (Вы можете разместить новый вопрос с более подробной информацией.)
UuDdLrLrSs
@UuDdLrLrSs Хорошие новости! Я
публикую

Ответы:

63

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

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

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

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

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

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

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

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

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

Эта утилита не поддерживает библиотеки .NET COM, поскольку они не предоставляют подпрограмму 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

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

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

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

Вим Коенен
источник
1
Я думаю, вы пропустили один вариант: mazecomputer.com, но я ничего не знаю о нем, который веб-сайт не описывает.
Боб
MMM также перенаправляет не-COM (стандартные) библиотеки DLL. Я не уверен, что это делают другие инструменты.
Боб
Замечание для нервных: исходники МММ опубликованы. С другой стороны, это похоже на то, что автор решил прекратить работу над этим. По-прежнему положительный знак.
Gavin
2
Сайт для MMM больше не работает, но место, где был размещен исходный код, все еще доступно для v0.9 и v0.12 .
Скотт Чемберлен
1
Просто попробовал mt.exe для .NET COM-библиотек, как описано выше, и он работал без изменений в манифесте с использованием v7.1A. Кроме того, ссылки для MMM не работали, но Unattented Make My Manifest, похоже, неплохо справляется.
bzuillsmith
28

С помощью задачи 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>
McDon
источник
Думаю, это действительно стоит отметить как ответ на этот вопрос. Теперь я использую это для автоматизации всего нашего манифеста. Спасибо @mcdon, вы сэкономили мне много работы.
Pete Magsig
Я согласен, что это лучшее решение при сборке с помощью Visual Studio. Вероятно, он не оценен выше только потому, что он был опубликован намного позже, чем другие ответы
dschaeffer
как добавить это в csproj?
jle
@jle Я думаю, вы могли бы добавить его в свой csproj в цели AfterBuild. Вот ссылка с msdn и еще одно сообщение на тему событий перед сборкой и после сборки. Обратите внимание, что я не тестировал включение этого в csproj, но подозреваю, что это сработает.
mcdon
Можно ли сгенерировать манифест для библиотеки DLL C # COM, чтобы ее мог использовать любой исполняемый файл (вместо создания манифеста для каждого исполняемого
файла
9

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

jdve
источник
3
Я немного нервничаю из-за этого МММ; это просто блог, бесплатное ПО, но без исходного кода, только ссылка на «самораспаковывающийся exe», и я вижу комментарии об утилите, вызывающей сбой XP. ммм ...
Вим Коенен
Эти «сбои» были причиной смерти самой утилиты MMM. Это было исправлено в версии 0.6.5, но вы все равно захотите 0.6.6, поскольку, пока он еще находится в бета-версии, срок его действия не истекает. Вы всегда можете использовать MT.EXE, как уже было предложено.
Боб
mt.exe не генерирует прогиды, когда я использую его на собственных серверах com, таких как dbgrid32.ocx
Вим Коенен
Использование reg free COM с компонентами, созданными .NET, очевидно, может привести к сбою XP - см. Этот stackoverflow.com/questions/617253/…
MarkJ
8

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

wqw
источник
+1 Интересно, тем более что исходники доступны. Меня немного смущает схожесть имен, по-видимому, «сделать мой манифест» и «автоматически сделать мой манифест» - это разные инструменты разных авторов.
Wim Coenen
2
Примечание. По состоянию на 2017 год (8 лет спустя ...) этот проект все еще активен с периодическими обновлениями обслуживания. github.com/wqweto/UMMM/commit/master . Он работает хорошо, и я регулярно им пользуюсь.
UuDdLrLrSs
0

Чтобы заполнить идентификаторы 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;
Эдвард Брей
источник