Створіть файли маніфестів для 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 Гарні новини! Я відправляю нове питання тут: stackoverflow.com/questions/63575746 / ...
Acewind

Відповіді:


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 з progids.
  • Другий фрагмент генерує <runtime>та <mvid>елементи, які потрібно видалити перед тим, як маніфести дійсно запрацюють.
  • Генерація клієнтських маніфестів для додатків не підтримується.

Можливо, майбутні випуски SDK покращать цей інструмент, я протестував той у Windows SDK 6.0a (vista).


1
Я думаю, ви пропустили один варіант: mazecomputer.com, але я нічого про це не знаю, веб-сайт не описує.
Боб,

MMM також переспрямовуватиме бібліотеки DLL, що не є COM (стандартними). Я не впевнений, що інші інструменти роблять це.
Боб,

Просто примітка для нервових: джерело МММ опубліковано. З мінусів це здається тому, що автор вирішив припинити над цим працювати. Все-таки позитивний знак.
Гевін,

2
Сайт MMM більше не працює, але місце, куди був поміщений вихідний код, все ще доступне для версій 0.9 і v.12 .
Скотт Чемберлен,

1
Просто спробував mt.exe для бібліотек .NET COM, як описано вище, і він працював без змін у маніфесті, використовуючи v7.1A. Крім того, посилання на MMM не працювали, але ненавмисний 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, ти врятував мені багато роботи.
Pete Magsig

Я згоден, що це найкраще рішення при створенні з Visual Studio. Ймовірно, його не оцінюють вищим лише тому, що він був опублікований набагато пізніше інших відповідей
dschaeffer

як додати це в csproj?
jle

@jle Я думаю, ви можете додати його до свого csproj у цілі AfterBuild. Ось посилання від msdn та ще одне повідомлення на тему подій prebuild і postbuild. Примітка. Я не тестував, включаючи це в csproj, але я підозрюю, що це буде працювати.
mcdon

Чи може маніфест бути сформований для DLL C # COM, щоб будь-який exe міг його споживати (а не генерувати маніфест на кожному exe, включаючи DLL?)
GilesDMiddleton

9

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


3
Я трохи нервуюся з приводу цього MMM; це просто блог, безкоштовна програма, але вихідний код недоступний, лише посилання на "саморозпаковується exe", і я бачу коментарі щодо утиліти, яка спричиняє збій XP. ммм ...
Вім Коен

Ці "збої" були вмирання самої утиліти MMM. Це було виправлено у версії 0.6.5, але ви все одно захочете 0.6.6, оскільки, поки вона ще є бета-версією, термін її дії вже не діє. Ви завжди можете використовувати MT.EXE замість цього, хоча, як уже було запропоновано.
Боб

mt.exe не генерує progid, коли я використовую його на власних com-серверах, таких як dbgrid32.ocx
Вім

Використання рег безкоштовно 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.


+1 Цікаво, особливо тому, що вихідний код доступний. Мене трохи бентежить схожість назви, мабуть, "зробити свій маніфест" та "без нагляду зробити свій маніфест" - це різні інструменти різних авторів.
Вім Коен

2
Примітка - станом на 2017 рік (8 років ...) цей проект все ще активний з періодичними оновленнями технічного обслуговування. github.com/wqweto/UMMM/commits/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;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.