Vista manifests and .Net

There's a few things for your application in Windows Vista that you can control using a manifest. Perhaps the most well-known use for manifests is to specify the use of the comctl32.dll version 6, which is needed to use visual styles with your application. I'm not talking about this though, as this has been the case since XP, and there's no problem here with .Net since you can (and probably do) use Application.EnableVisualStyles() instead of a manifest.

Vista also offers some other stuff which you can control with manifests: requested execution level and high-DPI compatibility (aka DPI awareness).

The first you'll probably know: with UAC enabled, applications running on Vista don't get admin privileges by default, even if the current user is a member of the Administrators group (a good post about how this actually works can be found here). If you do need admin privileges, the application must be elevated. You can do this manually by right-clicking the application executable or shortcut and choosing "Run as administrator". Additionally, Vista uses some heuristics to automatically prompt for elevation for some apps.

But the recommended approach to doing this is by specifying the "requestedExecutionLevel" attribute in your application's manifest. You can use the "requireAdministrator" value to force elevation, but even if you don't need elevation it has benefits to use a manifest (specifying "asInvoker" to indicate you don't need anything special in this case). If you do this, you're sure that Vista's heuristics will never accidentally elevate your application when it doesn't need to be. Additionally, using a manifest will disable file and registry virtualization (a technique that allows badly behaved applications to think they can write to protected locations such as Program Files or HKEY_LOCAL_MACHINE, when in fact they can't; the writes are redirected to a virtualized location). Disabling virtualization helps enforce that your app behaves properly (since writes to those locations will now actually fail instead of be redirected) and makes sure it behaves consistently on x64; a .Net 2.0 application (compiled with the default "Any CPU" setting) when run under an x64 version of Windows will run as a native x64 application, and x64 processes never use virtualization.

The second, less well-known thing you can do with manifests in Vista is mark your application DPI aware. There are two ways to do this: by using the SetProcessDPIAware() function in the Win32 API, or by using a manifest. In my experience, the former method will break .Net's automatic scaling in some circumstances, no matter how early you call the function. The manifest approach doesn't have this problem. If your application is not marked DPI aware, it will be scaled by the Desktop Window Manager under non-standard DPI values, leading to reduced image quality (most notably, fuzzy text). Of course, only mark your application as DPI aware when it actually is DPI aware: be sure to test your application with different DPI settings!

A manifest that controls these two settings is shown below:

<?xml version="1.0" encoding="UTF-8"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <asmv2:trustInfo xmlns:asmv2="urn:schemas-microsoft-com:asm.v2">
    <asmv2:security>
      <asmv2:requestedPrivileges>
        <asmv2:requestedExecutionLevel level="asInvoker" />
      </asmv2:requestedPrivileges>
    </asmv2:security>
  </asmv2:trustInfo>
  <asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
      <dpiAware>true</dpiAware>
    </asmv3:windowsSettings>
  </asmv3:application>
</assembly>

Now there's two ways you can include this manifest: as an external file named "YourExecutable.exe.manifest" or by embedding it into your executable. I vastly prefer the latter method since it eases deployment.

This is where it gets tricky (and also .Net specific; everything I've said so far applies to both native and .Net apps). Where Visual C++ automatically embeds manifests in executables, the C# and VB compilers do not offer this possibility. Fortunately, we can embed the manifest ourselves, using mt.exe (which is shipped with Visual Studio, and also with the Windows SDK):

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

Looks simple enough. But wait! If the assembly was strong named, embedding the manifest invalidates the hash and thus breaks the executable (the latest version of mt.exe will warn you of this). The solution is to re-sign with sn.exe (comes with the .Net Framework SDK):

sn.exe -Ra YourExecutable.exe YourStrongNameKey.snk

Now wouldn't it be nice if this could be done automatically? Fortunately, it can, using build events. Build events can be found in the project properties in Visual Studio. For C# projects, it's a separate tab in the list on the left ("Build Events"). For VB projects, use the "Build Events" button at the bottom of the "Compile" tab. Set the post-build event command line to the following:

"$(DevEnvDir)..\..\VC\bin\mt.exe" -nologo -manifest "$(ProjectDir)app.manifest" -outputresource:"$(TargetPath);#1"
"$(DevEnvDir)..\..\sdk\v2.0\Bin\sn.exe" -q -Ra "$(TargetPath)" "$(ProjectDir)strongnamekey.snk"

You may need to adjust the paths of mt.exe and sn.exe depending on your Visual Studio installation. You will also need to modify the name of the strong name key file and manifest file.

There's one thing left. If you use the latest version of mt.exe, it will now perpetually warn you about the need to re-sign your assembly, which Visual Studio picks up on and shows in the Error List. To prevent that, check the "Delay sign only" box on the "Signing" tab of the project settings. Now your assembly will not actually be signed when mt.exe is run, so there's no warning. Sn.exe will correctly sign it afterwards.

Categories: Programming
Posted on: 2007-07-06 13:53 UTC.

Comments

Shelly

2007-08-01 10:30 UTC

Thanks so much for this post - tried to follow a few different posts describing this process and this is the first that worked straight off the bat for me. (Not sure what went wrong before, but it's only Vista day 2 for me).

Mr. Bungle

2007-10-09 23:37 UTC

Awesome. I've been looking as the best way to do this and you've helped me decide.

I assume VS2008 will have better support for embedding manifests alongside signing for c# apps.

Mr. Bungle

2007-10-10 00:17 UTC

Side note: according to http://msdn2.microsoft.com/en-us/library/h4fa028b(VS.80).aspx you should not strong-name sign EXE files or files that are private to your application:

"In general, you should avoid strong-naming application EXE assemblies. A strongly named application or component cannot reference a weak-named component, so strong-naming an EXE prevents the EXE from referencing weak-named DLLs that are deployed with the application.

For this reason, the Visual Studio project system does not strong-name application EXEs. Instead, it strong-names the Application manifest, which internally points to the weak-named application EXE.

In addition, you may want to avoid strong-naming components that are private to your application. "

steve

2007-12-22 07:40 UTC

Good call

Dave Midgley

2007-12-31 13:45 UTC

This is great, but I have two fairly major problems. I have used Bart De Smet's test program at
http://community.bartdesmet.net/blogs/bart/archive/2006/10/28/Windows-Vista-_2D00_-Demand-UAC-elevation-for-an-application-by-adding-a-manifest-using-mt.exe.aspx
which displays whether the program actually has admin rights. The compiled program works fine, the problems occur when I build a deplyment project and try to install the program:
1) the manifest no longer seems to work, ie. the program says that it does not have admin rights;
2) If the app is strong-named and re-signed after the manifest is added in the post-build, then the installed program doesn't work at all - it just says "UacDemo has stopped working" which I beleive is Vista's totally unhelpful way of saying that there has been an unhandled exception. If anyone can shed any light on either or both of these I'd be most grateful.

Dave Midgley

2007-12-31 14:18 UTC

Isn't it always the way - just after I posted the above I found the solution. For the benefit of anuone else with the same problem - it arises because the .exe file that is put into the .msi deployment file isn't the one from the bin directory, it's the one from the obj directory (I suppose that's one of things things that "everybody knows" - well, I didn't!), so BOTH files need to have the manifest added, and BOTH files need to be resigned.

Sven Groot Author comment

2007-12-31 14:56 UTC

Hi Dave,

Yep, you're right about that. This problem also affects ClickOnce. For MSI projects an alternative solution is to add the exe manually instead of the project output.

I would also like to note that Visual Studio 2008 can embed the manifest for you (and in fact, creates one with "asInvoker" execution level by default) so this issue doesn't occur there.

Alireza Haghshenas

2008-08-18 06:29 UTC

Hi

There is a drawback when using manifests to enforce elevation: the app will elevate no matter what it's supposed to do. This is against the nature of UAC: everyone is limited, unless really required, and in that case the user is explicitly asked for the elevation.
It would be much better if there was a solution to ask for elevation only where (i.e. around the lines of code or method, etc) where the administrative event is to happen. It would be even better if the app could return to limited privilege as soon as possible.
Do you know any programmatic solution for this?

Sven Groot Author comment

2008-08-18 12:48 UTC

Hi Alireza,

What you're supposed to do is put the code that requires elevation in a separate executable (which has the necessary manifest) and then launch that executable from your main application. You can also use a special elevated COM moniker for out-of-process COM objects (see the UAC docs on MSDN) but I have never tried that with .Net.

Alireza Haghshenas

2008-08-21 11:39 UTC

Hi.

Thank you for the answer. I can understand this: a process started as a limited user remains limited during its lifecycle, so the only way is to switch to elevated permissions at the process startup. therefore no code inside the app is able to do that and hence, we have to use manifests.

thanks a lot.

Thorleif Sandberg

2008-11-05 13:25 UTC

Thanks so much for this post - tried to follow a few different posts describing this process and this is the first that worked straight off the bat for me too.

Amolpbhavsar

2010-09-06 10:53 UTC

what is the procedure for V Studio 2010

Add comment

Comments are closed for this post. Sorry.

Latest posts

Categories

Archive

Syndication

RSS Subscribe