Создать файлы манифеста для COM без регистрации
У меня есть некоторые приложения (некоторые нативные, некоторые.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 ответов
Похоже, идеального решения еще не существует. Подводя итог некоторым исследованиям:
Сделай мой манифест ( ссылка)
Этот инструмент сканирует проект 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
Однако есть некоторые проблемы с этим инструментом:
- Первый фрагмент не будет генерировать атрибуты progid, нарушая работу клиентов, которые используют CreateObject с progids.
- Второй фрагмент будет генерировать
<runtime>
а также<mvid>
элементы, которые должны быть удалены до того, как манифесты действительно сработают. - Генерация клиентских манифестов для приложений не поддерживается.
Возможно, будущие выпуски SDK улучшат этот инструмент, я протестировал один из них в Windows SDK 6.0a (Vista).
С помощью задачи 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>
Make My Manifest (MMM) - хороший инструмент для этого. Также можно написать скрипт для обработки всех ваших файлов DLL/OCX с помощью mt.exe, чтобы сгенерировать манифест для каждого из них, а затем объединить их все вместе. MMM обычно лучше / легче, потому что он также обрабатывает множество особых / странных случаев.
Вы можете использовать функцию 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.
Чтобы заполнить 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;