Hasilkan file manifes untuk COM bebas registrasi

87

Saya memiliki beberapa aplikasi (beberapa asli, beberapa .NET) yang menggunakan file manifes sehingga mereka dapat digunakan dalam isolasi lengkap , tanpa memerlukan pendaftaran COM global. Misalnya, ketergantungan pada server dbgrid32.ocx com dideklarasikan sebagai berikut di file myapp.exe.manifest yang berada di folder yang sama dengan 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 disebarkan ke folder yang sama, bersama dengan file dbgrid32.ocx.manifest itu sendiri:

<?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>

Ini semua berfungsi dengan baik tetapi mempertahankan file manifes ini secara manual agak merepotkan. Apakah ada cara untuk menghasilkan file ini secara otomatis? Idealnya saya hanya ingin menyatakan ketergantungan aplikasi pada daftar server COM (baik asli maupun .NET) dan kemudian biarkan sisanya dibuat secara otomatis. Apa itu mungkin?

Wim Coenen
sumber
+1 juga: Memberi tag ulang regfreecom karena tag itu lebih umum untuk COM bebas registri
MarkJ
Bolehkah saya menggunakan versi mstscax.dll yang lebih tinggi di folder instal saya sendiri dengan file manifes?
Acewind
@indonesia (Anda mungkin ingin mengeposkan pertanyaan baru dengan detail selengkapnya.)
UuDdLrLrSs
@UuDdLrLrSs Kabar baik! Saya memposting pertanyaan baru di sini: stackoverflow.com/questions/63575746/…
Acewind

Jawaban:

64

Sepertinya solusi yang tepat belum ada. Untuk meringkas beberapa penelitian:

Make My Manifest ( tautan )

Alat ini memindai proyek VB6 untuk mencari dependensi COM, tetapi juga mendukung deklarasi manual dependensi COM terikat-akhir (yaitu yang digunakan melalui CreateObject).

Yang cukup menarik, alat ini meletakkan semua informasi tentang dependensi di dalam manifes aplikasi. Exe aplikasi dan ketergantungannya digambarkan sebagai satu rakitan yang terdiri dari beberapa file. Saya tidak menyadari sebelumnya bahwa ini mungkin.

Sepertinya alat yang sangat bagus tetapi pada versi 0.6.6 memiliki batasan berikut:

  • hanya untuk aplikasi VB6, dimulai dari file proyek VB6. Malu, karena banyak yang dilakukannya sebenarnya tidak ada hubungannya dengan VB6.
  • aplikasi gaya wizard, tidak cocok untuk diintegrasikan dalam proses pembangunan. Ini bukan masalah besar jika dependensi Anda tidak banyak berubah.
  • freeware tanpa sumber, berisiko untuk mengandalkannya karena dapat sewaktu-waktu dapat ditinggalkan.

Saya tidak menguji apakah itu mendukung perpustakaan com .NET.

regsvr42 ( tautan proyek kode )

Alat baris perintah ini menghasilkan file manifes untuk pustaka COM asli. Ini memanggil DllRegisterServer dan kemudian memata-matai pendaftaran mandiri saat menambahkan informasi ke dalam registri. Itu juga dapat menghasilkan manifes klien untuk aplikasi.

Utilitas ini tidak mendukung pustaka .NET COM, karena ini tidak mengekspos rutin DllRegisterServer.

Utilitas ini ditulis dalam C ++. Kode sumber tersedia.

mt.exe

Bagian dari Windows SDK (dapat diunduh dari MSDN ), yang sudah Anda miliki jika Anda menginstal studio visual. Itu didokumentasikan di sini . Anda dapat membuat file manifes untuk pustaka COM asli dengan itu seperti ini:

mt.exe -tlb:mycomlib.ocx -dll:mycomlib.ocx -out:mycomlib.ocx.manifest

Anda dapat membuat file manifes untuk pustaka .NET COM dengan itu seperti ini:

mt.exe -managedassemblyname:netlib.dll -nodependency -out:netlib.dll.manifest

Namun, ada beberapa masalah dengan alat ini:

  • Cuplikan pertama tidak akan menghasilkan atribut progid, merusak klien yang menggunakan CreateObject dengan progid.
  • Cuplikan kedua akan menghasilkan <runtime>dan <mvid>elemen yang perlu dihapus sebelum manifes benar-benar berfungsi.
  • Pembuatan manifes klien untuk aplikasi tidak didukung.

Mungkin rilis SDK di masa mendatang akan meningkatkan alat ini, saya menguji yang ada di Windows SDK 6.0a (vista).

Wim Coenen
sumber
1
Saya pikir Anda melewatkan satu opsi: mazecomputer.com tetapi saya tidak tahu apa-apa tentang itu yang tidak dijelaskan situs web.
Bob
MMM juga akan mengarahkan DLL non-COM (standar). Saya tidak yakin alat lain melakukan ini.
Bob
Sekadar catatan untuk yang gugup: sumber MMM telah dirilis. Sisi negatifnya, ini tampaknya karena penulis telah memutuskan untuk berhenti mengerjakannya. Masih pertanda positif.
Gavin
2
Situs untuk MMM sudah tidak aktif lagi tetapi tempat di mana kode sumber diletakkan masih tersedia untuk v0.9 dan v0.12 .
Scott Chamberlain
1
Baru saja mencoba mt.exe untuk pustaka .NET COM seperti dijelaskan di atas dan berfungsi tanpa modifikasi pada manifes menggunakan v7.1A. Juga, tautan untuk MMM tidak berfungsi tetapi Make My Manifest yang tidak diberi perhatian tampaknya melakukan pekerjaan yang layak.
bzuillsmith
29

Dengan tugas MSBuild GenerateApplicationManifest saya menghasilkan manifes pada baris perintah yang identik dengan manifes yang dihasilkan Visual Studio. Saya menduga Visual Studio menggunakan GenerateApplicationManifest selama pembuatan. Di bawah ini adalah skrip build saya yang dapat dijalankan dari baris perintah menggunakan msbuild "msbuild build.xml"

Terima kasih kepada Dave Templin dan postingannya yang menunjukkan tugas GenerateApplicationManifest , dan dokumentasi tugas MSDN lebih lanjut .

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
sumber
1
Saya pikir ini harus benar-benar ditandai sebagai jawaban atas pertanyaan ini. Saya sekarang menggunakan ini untuk mengotomatiskan semua generasi nyata kita. Terima kasih @mcdon, Anda telah menghemat banyak pekerjaan untuk saya.
Pete Magsig
Saya setuju ini adalah solusi terbaik saat membangun dengan Visual Studio. Ini mungkin tidak dinilai lebih tinggi hanya karena itu diposting jauh lebih lambat dari jawaban lain
dschaeffer
bagaimana menambahkan ini ke dalam csproj?
jle
@jle Saya rasa Anda bisa menambahkannya ke csproj Anda di target AfterBuild. Berikut link dari msdn , dan postingan lain tentang topik acara prebuild dan postbuild. Catatan Saya belum menguji termasuk ini di csproj, tapi saya kira itu akan berhasil.
mcdon
1
11 tahun terlambat ke pesta tetapi terima kasih atas perhatiannya!
Dave Templin
9

Make My Manifest (MMM) adalah alat yang bagus untuk melakukan ini. Anda juga dapat menulis skrip untuk memproses semua file DLL / OCX Anda menggunakan mt.exe untuk menghasilkan manifes untuk masing-masing file dan kemudian menggabungkan semuanya. MMM biasanya lebih baik / lebih mudah, karena juga menangani banyak kasus khusus / aneh.

jdve
sumber
3
Saya sedikit gugup tentang MMM ini; itu hanya sebuah blog, freeware tetapi tidak ada kode sumber yang tersedia, hanya link ke "exe self-extracting" dan saya melihat komentar tentang utilitas yang menyebabkan XP crash. mmm ...
Wim Coenen
"Crash" itu adalah utilitas MMM itu sendiri yang sekarat. Ini telah diperbaiki dalam versi 0.6.5 tetapi Anda tetap menginginkan 0.6.6, karena saat masih beta, kedaluwarsa tidak lagi. Anda selalu dapat menggunakan MT.EXE sebagai gantinya seperti yang telah disarankan.
Bob
mt.exe tidak menghasilkan progid ketika saya menggunakannya di server com asli seperti dbgrid32.ocx
Wim Coenen
Penggunaan COM bebas reg dengan komponen yang diotorisasi .NET tampaknya dapat menyebabkan XP mogok - lihat stackoverflow.com/questions/617253/…
MarkJ
8

Anda dapat menggunakan spin off Make My Manifest tanpa pengawasan untuk menghasilkan manifes langsung dalam build otomatis. Ini menggunakan file skrip untuk menambahkan komponen COM yang bergantung. Ini adalah kutipan dari contoh ini dengan perintah yang tersedia:

# 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
#

Ini akan berjalan pada Windows 32 atau 64 bit.

wqw
sumber
+1 Menarik, terutama karena kode sumbernya tersedia. Saya agak bingung dengan kemiripan nama, ternyata "make my manifest" dan "unattended make my manifest" adalah alat yang berbeda oleh penulis yang berbeda.
Wim Coenen
2
Catatan - pada 2017 (8 tahun ...) proyek ini masih aktif dengan pembaruan pemeliharaan sesekali. github.com/wqweto/UMMM/commits/master . Ini bekerja dengan baik dan saya menggunakannya secara rutin.
UuDdLrLrSs
0

Untuk mengisi ProgID yang tidak disertakan mt.exe, Anda dapat memanggil ProgIDFromCLSIDuntuk mencarinya dari registri. Ini memerlukan registrasi COM tradisional sebelum menyelesaikan file manifes, tetapi selanjutnya, file manifes akan mencukupi sendiri.

Kode C # ini menambahkan ProgID ke semua kelas COM dalam manifest:

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);

Kode tersebut bergantung pada definisi interop berikut:

[DllImport("ole32.dll")] static extern int ProgIDFromCLSID([In] ref Guid clsid, [MarshalAs(UnmanagedType.LPWStr)] out string lplpszProgID);
const int S_OK = 0;
Edward Brey
sumber