You are viewing fragglet

fragglet [userpic]

How to make a program just run

December 10th, 2009 (01:05 pm)

Starting with Windows Vista, Windows limits the privileges that are given to normal users, running programs as the Administrator user only when necessary. To smooth over the fact that install programs for most software need to run as Administrator, it uses heuristics to detect whether a program is an installer. One of these is to look at the file name - if it contains "setup" in the name (among others), it is treated as an installer.

This is a problem if you develop a program that is not an installer but has "setup" in the name, because Windows treats it as though it is an installer and prompts you for administrator privileges.

User Account Control


The first problem is that it prompts the user for administrator privileges. This is part of the User Account Control system. Fortunately, there's a way around this - it's possible to embed a special "manifest" XML file inside the EXE that tells Windows that Administrator privileges aren't necessary.

Here's the magic manifest file to do this:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity version="0.0.0.0" processorArchitecture="X86"
                    name="foo.exe" type="win32"/>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel level="asInvoker" uiAccess="false" />
      </requestedPrivileges>
    </security>
  </trustInfo>
</assembly>

The important part here is the "requestedExecutionLevel" statement, that specifies to run the program as the invoker. I think the "uiAccess" element is necessary as well. I'm not entirely sure what this control does, and there are some people who say it should be set to true. However, it seems that if set to true, the executable has to be digitally signed with a certificate, which all looks like a massive hassle, so I've just left it turned off.

The "assemblyIdentity" tag here matches the executable name, but I'm not sure it's actually necessary. The version number is a dummy value.

Embedding it inside an executable is a matter of writing a resource file containing a statement to include the manifest file. Here's the magic statement for that:
1 24 MOVEABLE PURE "setup-manifest.xml"

The resource file is then compiled to a .o (using windres) and incorporated into the build.

Compatibility Assistant


So far, so good. If the above is done properly, Windows won't prompt to run the program with administrator privileges any more. However, that's not the end of the story. Windows still thinks the program is an installer, just an installer that doesn't need administrator privileges. The next problem is the "Program Compatibility Assistant".

If your program exits without writing any files to disk (in Chocolate Setup, it's possible to quit without saving configuration file changes, for example), the compatibility assistant appears. Because Windows thinks the program is an installer, and it hasn't written any files to disk, it assumes that something must have gone wrong with installation, and it might be a compatibility problem with a program designed for an older version of Windows. The assistant is supposed to help you resolve the problems you've encountered.

To work around this requires an addition to the manifest file to state that Vista (and Windows 7) are supported OSes; therefore, if no files are written, it's no problem. Here's the new version of the manifest:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity version="0.0.0.0" processorArchitecture="X86"
                    name="foo.exe" type="win32"/>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel level="asInvoker" uiAccess="false" />
      </requestedPrivileges>
    </security>
  </trustInfo>

  <!-- Stop the Program Compatibility Assistant appearing: -->

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


References