C# and native resources

  • Thread starter Carl Daniel [VC++ MVP]
  • Start date
C

Carl Daniel [VC++ MVP]

Problem: C# 2.0 doesn't imbed a UAC manifest in the EXE files that it
produces.
Problem: The suggested solution on MSDN is unworkable (manually opening the
EXE using VS as a resource editor and inserting the manifet resource).
Problem: Changing the C# project to explicitly link a .RES file suppresses
the generation of the native VS_VERSIONINFO resource by the C# compiler.

All in all, MS made it harder than necessary to produce a Vista-compliant
EXE from C# 2.0.

So how have people solved this problem?

It seems like some kind of command-line tool to insert the manifest resource
after the fact would be a good solution - there are a variety of such tools
on that market, all of which seem overpriced for such a simple task.

Any free tools out there that can insert a manifest resource into an
existing EXE?

-cd
 
W

Willy Denoyette [MVP]

Carl Daniel said:
Problem: C# 2.0 doesn't imbed a UAC manifest in the EXE files that it
produces.
Problem: The suggested solution on MSDN is unworkable (manually opening
the EXE using VS as a resource editor and inserting the manifet resource).
Problem: Changing the C# project to explicitly link a .RES file
suppresses the generation of the native VS_VERSIONINFO resource by the C#
compiler.

All in all, MS made it harder than necessary to produce a Vista-compliant
EXE from C# 2.0.

So how have people solved this problem?

It seems like some kind of command-line tool to insert the manifest
resource after the fact would be a good solution - there are a variety of
such tools on that market, all of which seem overpriced for such a simple
task.

Any free tools out there that can insert a manifest resource into an
existing EXE?

-cd


Carl, the Windows SDK comes with a tool called the "Microsoft (R) Manifest
Tool" the PE file is: mt.exe.

You can use this tool to embed a manifest in a post build step in VS2005.
VS2008 supports this by default, see the project settings.

Willy.
 
C

Carl Daniel [VC++ MVP]

Willy Denoyette said:
Tool" the PE file is: mt.exe.

You can use this tool to embed a manifest in a post build step in VS2005.
VS2008 supports this by default, see the project settings.

OK, I wondered if mt.exe could do what I need. I'll take a look at the docs
for it. Glad to hear that they got this sorted out in VS2008 - it's a bit
of a pain in VS2005.

-cd
 
C

Carl Daniel [VC++ MVP]

Carl Daniel said:
OK, I wondered if mt.exe could do what I need. I'll take a look at the
docs for it. Glad to hear that they got this sorted out in VS2008 - it's
a bit of a pain in VS2005.

No joy from mt.exe so far - all it says is "general error c1010070: Failed
to load and parse the manifest.".

This is the manifest that I'm trying to embed:

<assembly xmlns=""urn:schemas-microsoft-com:asm.v1""
manifestVersion=""1.0"">
<asmv3:trustInfo xmlns:asmv3=""urn:schemas-microsoft-com:asm.v3"">
<asmv3:security>
<asmv3:requestedPrivileges>
<asmv3:requestedExecutionLevel
level=""asInvoker""
uiAccess=""false"" />
</asmv3:requestedPrivileges>
</asmv3:security>
</asmv3:trustInfo>
</assembly>

Ideas?

-cd
 
C

Carl Daniel [VC++ MVP]

So far, nothing but disaster. I tried a different manifest fragment using
the v2 schema. That is acceptable to mt.exe, but the resulting EXE file
doesn't run, failing with "Configuration System Failed to Initialize".
That's after re-signing the EXE with sn.exe too.

Can anyone post a simple, complete example of embedding a manifest in a C#
exe file that's sufficient to let the app run 'asInvoker' on Vista?

-cd
 
W

Willy Denoyette [MVP]

Carl Daniel said:
No joy from mt.exe so far - all it says is "general error c1010070: Failed
to load and parse the manifest.".

This is the manifest that I'm trying to embed:

<assembly xmlns=""urn:schemas-microsoft-com:asm.v1""
manifestVersion=""1.0"">
<asmv3:trustInfo xmlns:asmv3=""urn:schemas-microsoft-com:asm.v3"">
<asmv3:security>
<asmv3:requestedPrivileges>
<asmv3:requestedExecutionLevel
level=""asInvoker""
uiAccess=""false"" />
</asmv3:requestedPrivileges>
</asmv3:security>
</asmv3:trustInfo>
</assembly>

Ideas?

-cd


This works for me:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="1.0.0.0" name="some.exe"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

Note that as name is only used for documentation purposes, this is not
checked by the loader.

running:

mt -manifest some.manifest -outputresource:some.exe;#1

-manifest specifies the manifest file while -outpuresource refers to the
executable PE file.
#1 is the manifest entry (1 for an exe, 2 for a DLL).

Willy.
 
C

Carl Daniel [VC++ MVP]

Willy Denoyette said:
This works for me:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="1.0.0.0" name="some.exe"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

Note that as name is only used for documentation purposes, this is not
checked by the loader.

running:

mt -manifest some.manifest -outputresource:some.exe;#1

-manifest specifies the manifest file while -outpuresource refers to the
executable PE file.
#1 is the manifest entry (1 for an exe, 2 for a DLL).

I got mt.exe to be happy with a slightly different manifest, but I'm not
convinced that everything's working quite right yet.

Here's what I'm doing now:

MyApp.exe.manifest:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
<requestedExecutionLevel
level="asInvoker"
uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

Post-build event in C# project:

mt.exe -manifest
$(ProjectDir)\Resources\$(TargetFileName).manifest -outputresource:$(TargetPath);#1
sn -R $(TargetPath) $(SolutionDir)\MyCompany.snk

Any problems with the above?

Is the <assemblyIdentity> element required? If so, I can add it, but that
just replaces one problem with another - how to get the correct (C#
auto-assigned) version number into the manifest file.

-cd
 
B

Ben Voigt [C++ MVP]

Is the said:
that just replaces one problem with another - how to get the correct (C#
auto-assigned) version number into the manifest file.

Reflection.Assembly.LoadFile(...).GetName().Version

Make some small tool to spit out the correct manifest given the filename of
the assembly. You could even make "asInvoker" an argument to the tool to
make it a little more general.
 
C

Carl Daniel [VC++ MVP]

Ben said:
Reflection.Assembly.LoadFile(...).GetName().Version

Make some small tool to spit out the correct manifest given the
filename of the assembly. You could even make "asInvoker" an
argument to the tool to make it a little more general.

Yeah, I know - that's an easy problem to solve, it just seems like I
shouldn't need to run 3 or 4 separate post-build processes on my EXE to end
up with a valid end product.

Everything appears to work fune without the <assemblyIdentity> element,
although I haven't yet tried actually installing and running the app on
Vista.

-cd
 
W

Willy Denoyette [MVP]

Carl Daniel said:
I got mt.exe to be happy with a slightly different manifest, but I'm not
convinced that everything's working quite right yet.

Here's what I'm doing now:

MyApp.exe.manifest:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
<requestedExecutionLevel
level="asInvoker"
uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

Post-build event in C# project:

mt.exe -manifest
$(ProjectDir)\Resources\$(TargetFileName).manifest -outputresource:$(TargetPath);#1
sn -R $(TargetPath) $(SolutionDir)\MyCompany.snk

Any problems with the above?

Is the <assemblyIdentity> element required? If so, I can add it, but that
just replaces one problem with another - how to get the correct (C#
auto-assigned) version number into the manifest file.

The <assemblyIdentity> element is optional, the mt tool produces this
element, or, with a default string when run without -identity option or with
the values specified by this option.
For instance when you run mt on a X86 platform, he will insert the following
assemblyIdentity element:

<assemblyIdentity name="xxxxxxxx" version="0.0.0.0"
processorArchitecture="x86">

where "xxxxxxxxxx" is the name of the PE file (dll or exe) without the
extension.

The processorArchitecture will reflect the platform mt.exe was run on. This
element can have the values x86, amd64 or IA64. These values are parsed and
validated by the OS loader, valid values will not prevent the loading of the
assembly when run on a different platform than specified.
For instance an processorArchitecture="amd64", will perfectly load on an X86
Intel architecture and vice versa.

Not sure why you want to relate the "managed assembly" version with the PE
manifest version though, they are not really related. More, the PE version
is not really relevant in an embedded manifest, this version stamp is only
meant to be used in a SxS schenario.

Willy.
 
W

Willy Denoyette [MVP]

Carl Daniel said:
Yeah, I know - that's an easy problem to solve, it just seems like I
shouldn't need to run 3 or 4 separate post-build processes on my EXE to
end up with a valid end product.

Everything appears to work fune without the <assemblyIdentity> element,
although I haven't yet tried actually installing and running the app on
Vista.

-cd



Your manifest ok and will work on Vista. Note that you can extract the
embedded manifest with

mt -managedassemblyname:some.exe -out:extracted.manifest
here extracted.manifest is an XML file, just have a look at it to see what
the mt has added to your original manifest file.

Willy.
 
C

Carl Daniel [VC++ MVP]

Willy said:
The <assemblyIdentity> element is optional, the mt tool produces this
element, or, with a default string when run without -identity option
or with the values specified by this option.
For instance when you run mt on a X86 platform, he will insert the
following assemblyIdentity element:

<assemblyIdentity name="xxxxxxxx" version="0.0.0.0"
processorArchitecture="x86">

where "xxxxxxxxxx" is the name of the PE file (dll or exe) without the
extension.

The processorArchitecture will reflect the platform mt.exe was run
on. This element can have the values x86, amd64 or IA64. These values are
parsed and validated by the OS loader, valid values will not prevent
the loading of the assembly when run on a different platform than
specified. For instance an processorArchitecture="amd64", will perfectly
load on
an X86 Intel architecture and vice versa.

OK. Extracting the manifest from my finished EXE, I see that mt recorded
the platform as "msil", which sounds like the right thing for a pure "Any
CPU" .NET assembly.

Oddly, the manifest fragment that I fed into mt when the EXE was built (the
<trustInfo> element) is missing from the manifest that mt extracts from the
EXE, so now I'm left wondering if I've actually accomplished anything
useful at all. The extracted manifest looks like this:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
name="MyApp"
version="1.2.2965.28735"
publicKeyToken="c7fdcb0b05e7acdd"
processorArchitecture="msil">
</assemblyIdentity>
<file name="MyApp.exe" hashalg="SHA1"></file>
<dependency>
<dependentAssembly>
<assemblyIdentity name="System.Configuration.Install" ...
... a bunch more dependencies
</assembly>

What happened to the trustInfo element that was the whole purpose of this
exercise?
Not sure why you want to relate the "managed assembly" version with
the PE manifest version though, they are not really related.

I just don't want a single EXE file to have two different version numbers -
it's just another potential source of confusion.
More, the PE version is not really relevant in an embedded manifest, this
version stamp is
only meant to be used in a SxS schenario.

Got it. I don't think SxS is relevant for this application at this time,
but it's good to know how the pieces fit together.

-cd
 
C

Carl Daniel [VC++ MVP]

Carl Daniel said:
Oddly, the manifest fragment that I fed into mt when the EXE was built
(the <trustInfo> element) is missing from the manifest that mt extracts
from the EXE, so now I'm left wondering if I've actually accomplished
anything useful at all.

Interesting. It looks like

mt -managedassembly:myfile.exe -out:myfile.exe.manifest

does not extract the manifest from the exe, rather, it generates a basic
manifest for the assembly, including dependencies and version info. If I
look at the PE file with a resource editor, I see exactly the manifest that
I inserted and none of the dependency/version info that mt produces in
response to the command above.

mt -inputresource:myfile.exe;#1 -out:myfile.exe.manifest

does extract the manifest that's embedded in the exe, and it's exactly the
manifest that I added.

-cd
 
W

Willy Denoyette [MVP]

Carl Daniel said:
OK. Extracting the manifest from my finished EXE, I see that mt recorded
the platform as "msil", which sounds like the right thing for a pure "Any
CPU" .NET assembly.

Oddly, the manifest fragment that I fed into mt when the EXE was built
(the <trustInfo> element) is missing from the manifest that mt extracts
from the EXE, so now I'm left wondering if I've actually accomplished
anything useful at all. The extracted manifest looks like this:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
name="MyApp"
version="1.2.2965.28735"
publicKeyToken="c7fdcb0b05e7acdd"
processorArchitecture="msil">
</assemblyIdentity>
<file name="MyApp.exe" hashalg="SHA1"></file>
<dependency>
<dependentAssembly>
<assemblyIdentity name="System.Configuration.Install" ...
... a bunch more dependencies
</assembly>

What happened to the trustInfo element that was the whole purpose of this
exercise?
I guess the mt tool doesn't know how to extract this element, as it predates
Vista, note that there are other ways to embed a manifest, but by far this
is the easiest when dealing with managed assemblies.
Anyway, your trustInfo is correct and will do what it is supposed to do on
Vista.
I just don't want a single EXE file to have two different version
numbers - it's just another potential source of confusion.

The version number in the manifest relates to the "PE file" version, a PE
file is also called an assembly, the "managed" assembly however is not
directly related to the PE assembly, a PE file is just a container, a single
PE file can hold multiple "managed code assemblies".
Got it. I don't think SxS is relevant for this application at this time,
but it's good to know how the pieces fit together.

-cd

Willy.
 
C

Carl Daniel [VC++ MVP]

Carl Daniel said:
Interesting. It looks like

mt -managedassembly:myfile.exe -out:myfile.exe.manifest

does not extract the manifest from the exe, rather, it generates a basic
manifest for the assembly, including dependencies and version info. If I
look at the PE file with a resource editor, I see exactly the manifest
that I inserted and none of the dependency/version info that mt produces
in response to the command above.

mt -inputresource:myfile.exe;#1 -out:myfile.exe.manifest

does extract the manifest that's embedded in the exe, and it's exactly the
manifest that I added.

I ended up changing my post-build step to the following:

mt.exe -managedassemblyname:$(TargetPath) -nodependency -out:$(TargetPath).tmp
mt.exe -manifest $(ProjectDir)\Resources\$(TargetFileName).manifest
$(TargetPath).tmp -outputresource:$(TargetPath);#1
sn.exe -R $(TargetPath) $(SolutionDir)\MyCompany.snk

That gives me a manifest with the <trustLevel> element that Vista requires,
and also a correct <assemblyIdentity>.

-cd
 
W

Willy Denoyette [MVP]

Carl Daniel said:
Interesting. It looks like

mt -managedassembly:myfile.exe -out:myfile.exe.manifest

does not extract the manifest from the exe, rather, it generates a basic
manifest for the assembly, including dependencies and version info. If I
look at the PE file with a resource editor, I see exactly the manifest
that I inserted and none of the dependency/version info that mt produces
in response to the command above.

mt -inputresource:myfile.exe;#1 -out:myfile.exe.manifest

does extract the manifest that's embedded in the exe, and it's exactly the
manifest that I added.

-cd

Well, I just found out that :
1) running...
mt -inputresource:some.exe -out:some.manifest
produces the complete XML manifest info including the UAC entry <trustInfo
...
2)
That the version of mt.exe included with the SDK is an older version, a
newer version is found in:
x:\program files\Microsoft Visual Studio 8\Common7\Tools\Bin

Willy.
 
W

Willy Denoyette [MVP]

Carl Daniel said:
Carl Daniel said:
"Carl Daniel [VC++ MVP]"
Oddly, the manifest fragment that I fed into mt when the EXE was built
(the <trustInfo> element) is missing from the manifest that mt extracts
from the EXE, so now I'm left wondering if I've actually accomplished
anything useful at all.

Interesting. It looks like

mt -managedassembly:myfile.exe -out:myfile.exe.manifest

does not extract the manifest from the exe, rather, it generates a basic
manifest for the assembly, including dependencies and version info. If I
look at the PE file with a resource editor, I see exactly the manifest
that I inserted and none of the dependency/version info that mt produces
in response to the command above.

mt -inputresource:myfile.exe;#1 -out:myfile.exe.manifest

does extract the manifest that's embedded in the exe, and it's exactly
the manifest that I added.

I ended up changing my post-build step to the following:

mt.exe -managedassemblyname:$(TargetPath) -nodependency -out:$(TargetPath).tmp
mt.exe -manifest $(ProjectDir)\Resources\$(TargetFileName).manifest
$(TargetPath).tmp -outputresource:$(TargetPath);#1
sn.exe -R $(TargetPath) $(SolutionDir)\MyCompany.snk

That gives me a manifest with the <trustLevel> element that Vista
requires, and also a correct <assemblyIdentity>.

-cd


Here's a KB article describing an alternate solution:
http://support.microsoft.com/kb/944276

Willy.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top