floele
floele

Reputation: 3788

How to embed/merge multiple manifest files into C# application?

In Visual Studio you can set an option "Additional Manifest Files" in C++ projects in order to merge an additional manifest file into the default application manifest.

We use this option with a shared "compatibility manifest" that only includes a list of supported OS versions:

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 
    <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> 
      <application>
        <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> <!--app support for Windows Vista -->
        <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/> <!--app support for Windows 7 -->
        <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/> <!--app support for Windows 8 -->
        <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/> <!--app support for Windows 8.1 -->
      </application> 
    </compatibility>
</assembly>

Now we would like to embed that shared manifest also into existing WinForms/WPF applications, so that it merges with the existing application manifest files. Is that possible with C# projects? We would like to avoid defining this list of OSes in every project.

Upvotes: 13

Views: 1778

Answers (2)

Mitch
Mitch

Reputation: 22301

You can insert mt into the build process by defining custom targets that merge the manifests before inclusion in the exe. Add the following targets to your project file, then add additional manifests as <AdditionalManifestToMerge items.

Targets:

<Target Name="GenerateComFreeManifestItems" Condition="'@(AdditionalManifestToMerge)' != ''">
  <PropertyGroup>
    <Win32ManifestPreMerge>$(Win32Manifest)</Win32ManifestPreMerge>
    <Win32Manifest>$(IntermediateOutputPath)app_merged.manifest</Win32Manifest>
    <MtPath Condition="'$(MtPath)' == ''">C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x86\mt.exe</MtPath>
  </PropertyGroup>
</Target>
<Target Name="GenerateComFreeManifest" BeforeTargets="CoreCompile" DependsOnTargets="GenerateComFreeManifestItems"
    Condition="'@(AdditionalManifestToMerge)' != ''"
    Inputs="@(AdditionalManifestToMerge);$(Win32ManifestPreMerge)"
    Outputs="$(Win32Manifest)">
  <Exec Command="&quot;$(MtPath)&quot; -manifest &quot;$(Win32ManifestPreMerge)&quot;@(AdditionalManifestToMerge -> ' &quot;%(Identity)&quot;') -out:&quot;$(Win32Manifest)&quot;" />
  <ItemGroup>
    <FileWrites Include="$(Win32Manifest)" />
  </ItemGroup>
</Target>

Item(s):

<ItemGroup>
  <AdditionalManifestToMerge Include="..\path\to.dll.manifest" />
</ItemGroup>

Note: This is a bit fragile since it depends on the location of mt.exe being consistent on each machine. I'm sure there is a proper way to find it - but google has failed me (see Path to SignTool.exe or "Windows Kits" directory when using Visual Studio 2012 for some bad options)

Upvotes: 0

Klaus G&#252;tter
Klaus G&#252;tter

Reputation: 12007

You can use a post-build action calling the ManifestTool mt.exe (from the Windows SDK) to add or update a manifest:

mt.exe -updateresource:"myapp.exe";#1 -manifest "additional.manifest"

See MT command line for more information.

Note that when you opted to sign the assembly, you have to re-sign it after this modification:

sn.exe -R "myapp.exe" "mykey.snk"

Upvotes: 0

Related Questions