4
votes

Starting with Windows Vista, Microsoft added a class of compatibility shims that will allow an application that assumes it has administrative file and registry access to continue to function.

In other words: An application that failed on Windows XP would run on Windows Vista.

These OS provided bug-fixes can be disabled by adding a section to the application manifest, declaring the application should run asInvoker:

<!-- Disable Windows Vista standard user compatability heuristics -->
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
   <security>
      <requestedPrivileges>
         <requestedExecutionLevel level="asInvoker"/>
      </requestedPrivileges>
   </security>
</trustInfo>

Ideally, a developer would test their application to ensure that it doesn't (needlessly) require administrative privelages. In order for me to test this, i would need to manifest it asInvoker.

But when it comes down to it, i'm not going to release the application to the customer manifested asInvoker. If i did miss something, i don't want the user to be impacted. i want Microsoft's operating system to fix my mistakes. Problem with this solution is:

  • i have to modify the manfiest before release
  • i'll never know about the things i missed, becuase they're just work on Windows Vista.

A similar conundrum comes up with Windows 7's supportedOS manifiest entires. You can add a manifest to the application indicating which version of Windows you were designed and tested for:

<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> 
   <application> 
      <!--The ID below indicates application support for Windows Vista -->
      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> 
      <!--The ID below indicates application support for Windows 7 -->
      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
   </application> 
</compatibility>

In the case of the supportedOS items, the operating system knows up front which OS you were designed for. This will place your application in the context of Windows Vista if you do not say that you support Windows 7:

alt text
(source: msdn.com)

This action is similar to running an application in some Compatibility Mode, e.g.:

  • Windows Server 2008 (Service Pack 1)
  • Windows Vista (Service Pack 2)
  • Windows Vista (Service Pack 1)
  • Windows Vista
  • Windows Server 2003 (Service Pack 1)
  • Windows XP (Service Pack 2)
  • Windows 2000
  • Windows NT 4.0 (Service Pack 5)
  • Windows 98 / Windows Me
  • Windows 95

where you will get a schmorgasboard of compatibilty shims applied, and Windows will emulate old undocumented behaviour in order to help your app from crashing when it depended on that undocumented behaviour.

An example of compatibility shims that Windows 7 will provide for an application running in the Windows Vista context:

  • RPC will use the old private thread pool, rather than the OS thread pool
  • you will be able to Lock the primary video desktop display buffer
  • you will be able to Blit to the primary desktop video buffer without specifying a clipping window
  • you will be vulnerable to a GetOverlappedResult race condition (if you depended on it)
  • you will continue to get Program Compatibilty Assistant (PCA) mitigation

And once again, in order to test my application properly under Windows 7, i have to add the supportsOS manifest entry. But, again, i'm not going to ship the application with that flag, because i don't want to lose the benefit of these shims (e.g. PCA). And, again, if an app has problems that were fixed because it was running in the Vista context: i'll never know about it from our customers - because the app is just working.


Thoughts? Guidance? Best practices?

3
This is a very good question.i_am_jorf
If you leave off the manifest (asinvoker), then you would NOT be notified of a problem. Windows would just invoke its UAC heuristics and silently use virtual folders and virtual registry hives to fulfill your app's errant requests. AsInvoker will actually result in your app getting an error if you attempt to exceed your security rating - and hence you can actually find & debug it. You have the concept backwards, AFAICTMordachai
Mordachai: Yes, that's what i (thought) my question says. If i have no manifest, Windows will fix problems. If i add the manifest, the heuristics are disabled.Ian Boyd
"In order for me to test this, i would need to manifest it asInvoker." i manifest it while testing so that i see errors (because heuristics are disabled). "i'm not going to release the application to the customer manifested asInvoker. If i did miss something, i don't want the user to be impacted." And i take away the manifest entry for release.Ian Boyd

3 Answers

2
votes

i'm not going to release the application to the customer manifested asInvoker. If i did miss something, i don't want the user to be impacted.

I think this is a bad approach. My advice is to manifest correctly from the start and test what you deploy.

Microsoft is not going to bend over backwards for everyone's compatibility. They're going to target the most common, high-impact mistakes made by the biggest vendors. If you miss some small issue, the chance of them providing a shim in the future is small.

Every time Microsoft adds a compatibility shim, we all pay a price. There are APIs that don't work the way they should because they had to handle some case in a brain dead way to achieve compatibility with somebody else's bug. This means long, painful debugging sessions, it means wading through longer (or less complete) documentation, and it means little inefficiencies in the OS for everyone. It also means Windows developers are wasting time fixing other people's mistakes instead of improving the OS.

Sometimes these compatibility changes are big hammers that penalize developers who do it right. Many applications don't handle high DPI correctly, so--in the name of compatibility--Vista assumes that no applications handle it correctly (unless they explicitly claim otherwise). Vista applies UI scaling. Applications that didn't handle high-DPI get improved (but suboptimal) results. Applications that did handle high_DPI get degraded results. (And customers who used the good apps see them get worse when they upgrade to Vista and blame Microsoft.) The developers who didn't pay their taxes get help from Microsoft, the rest of us (including Microsoft) get penalized. The only way to avoid this is for everyone to pay their taxes.

In general, Microsoft is getting better at making these compatibility shims more targeted (though Vista was pretty blunt). Nevertheless, there's a little cost to each one.

Follow the best practice during development. Test what you plan to deploy. If it breaks big, Microsoft might fix it for you. Otherwise, you might have to release an update. That's better than everyone suffering a penalty because some developers didn't do the right thing.

1
votes

AsInvoker is the correct way to distribute your application!!!

All that says, is run with the user's credentials. It doesn't say 'do something sneaky' or 'use admin rights'.

Without that manifest, you're branding your application as "I'm not aware of UAC, so please provide me whatever hacks you need to make me still maybe function on any system that has UAC"

But if your application doesn't try to do admin-only things - and you can easily test that by simply being logged in as a standard user & then running your app and watching for failures - then AsInvoker is absolutely correct.

This might help you get a handle on it: A Programmer's Exploration of Vista's User Account Control

0
votes

As I understand it, instead of supplying a manifest file with your distribution it can also be linked directly into your EXE file by adding the following command to your application's resource file: [1,2].

CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "YourApp.exe.manifest"

A separate manifest file in the directory containing the EXE file could override this linked-in manifest, but that is up to the customer. You wouldn't supply it.

Now, the "RC" resource compiler from Microsoft accepts preprocessor directives such as #ifdef [3]. Which means, you could instruct your Visual Studio to have two separate build targets defining different preprocessor definitions such as TESTING and DEPLOYMENT.

Then, it is just a matter of using #ifdef directives to use two different manifest files for your testing and deployment build targets, and you can edit the manifest files as you wish. Would this solve your problem?

[1] http://msdn.microsoft.com/en-us/library/ms997646.aspx
[2] http://doc.ddart.net/xmlsdk/htm/sdk_dependencies_5wvi.htm
[3] http://msdn.microsoft.com/en-us/library/aa381033%28VS.85%29.aspx