Run programs elevated on Vista

What does "Elevated" mean?

One of the differences between Vista and XP is the User Account Control (UAC) in Vista. The UAC controls who has access to what folders and files. A normal user account in Vista does not have administrator privileges. Some access requires administrator privileges, such as writing to files in the Program Files folder, accessing certain control panel applications and write to certain CSIDL folders - see my last blog about where to put data under Vista. For that, Vista requires elevation to administrator privileges and will prompt the user to elevate. The elevation prompts the user for permission to use the software or requests an administrator login.

Require elevation

The elevation requirement is controlled from within the software by the vista manifest. The Vista manifest is an XML file, just like the XP manifest, but with some additional branches, most notably the trustinfo branch. Below is the Vista manifest that we use for our Build Automator It is generated with our AddVistaManifest extension template in our Icetips Utilities.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly
   xmlns="urn:schemas-microsoft-com:asm.v1"
   manifestVersion="1.0">
<assemblyIdentity
    processorArchitecture="x86"
    version="1.0.0.0"
    type="win32"
    name="BuildAutomator.exe"/>
    <description>Build Automator</description>
    <dependency>
    <dependentAssembly>
    <assemblyIdentity
         type="win32"
         name="Microsoft.Windows.Common-Controls"
         version="6.0.0.0"
         publicKeyToken="6595b64144ccf1df"
         language="*"
         processorArchitecture="x86"/>
    </dependentAssembly>
    </dependency>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel
          level="asInvoker"
          uiAccess="false"/>
        </requestedPrivileges>
       </security>
  </trustInfo>
</assembly>

The important part of the manifest is the RequestedExecutionLevel. The level attribute can have one of 3 possible settings:

  • requireAdministrator
  • asInvoker
  • highestAvailable

Normal programs should use asInvoker. Otherwise the program will prompt for elevation every time it is run and unless that is really required it should not be done. To force elevation of a program, the manifest should be set to requireAdministrator.

Running programs

In Clarion we have been able to use the RUN statement to run external programs without much problems. However, with Vista, a problem comes up if you want to run a program that either needs to be elevated by the program running it or the program to be run is using requireAdministrator. Either way it needs to be elevated.

Unfortunately RUN cannot handle this properly. The reason is that RUN uses the CreateProcess API internally and it cannot trigger the elevation process. If you try to use RUN to execute a program that requires administrator privileges is that nothing happens! This can cause support issues that are easily avoided.For that either ShellExecute or ShellExecuteEx must be used. In addition to that, if you want the calling program to wait for the called program you need to use WaitForSingleObject to force the process to wait.

Code sample

The following code sample is from our ITRun method in the ITShellClass of the Icetips Utilities. This is the main code that optionally elevates the program using the RunAs verb for ShellExecuteEx. It will also automatically trigger elevation if the called program uses requireAdministrator manifest.

    Verb = IT_SE_Open   !! Defaults to not elevated
    If Elevate
      If SELF.IsVista
        Verb = IT_SE_RunAs  !! Elevate to requireAdministrator
      End
    End
    !SELF.ODS('  Verb = ' & Verb)
    
    SHi.fMask                  =  IT_SEE_MASK_NOCLOSEPROCESS !!ULONG
    SHi.hwnd                   =  0{Prop:Handle}             !!IT_HWND       ! UNSIGNED
    SHi.lpVerb                 =  Address(Verb)              !!Long
    SHi.lpFile                 =  Address(cCmdLine)          !!Long
    SHi.lpParameters           =  Address(cParam)            !!Long
    SHi.lpDirectory            =  Address(P)                 !!Long
    SHi.nShow                  =  IT_SW_SHOWNORMAL           !!IT_int        ! SIGNED
    !SHi.hInstApp               =                            !!IT_HINSTANCE  ! UNSIGNED
    SHi.lpIDList               =  0                          !!IT_LPVOID     ! ULONG
    SHi.lpClass                =  0                          !!Long
    SHi.hkeyClass              =  0                          !!IT_HKEY       ! UNSIGNED
    SHi.dwHotKey               =  0                          !!IT_DWORD      ! ULONG
    SHi.DUMMYUNIONNAME         =  0                          !!Long          ! Pointer to union...
    !SHi.hProcess               =  !!IT_HANDLE     ! UNSIGNED
    SHi.cbSize                 =  Size(SHi) !!IT_DWORD       !! ULONG
    !SELF.ODS('  Before ShellExecEx')
    If Not SELF.ShellExecEx(SHi)
      hProc = 0
      SELF.ODS('  ShellExecEx failed in ITShellClass.ITRun.')
    Else
      hProc = Shi.hProcess
    End
    !SELF.ODS('  After ShellExecEx')
    If hProc
      If pWait
        RetVal = IT_WaitForSingleObject(hProc,-1)
        If IT_GetExitCodeProcess(hProc, lRetCode)
          RetValue = lRetCode
        Else
          RetValue = RetVal
        End
        RetVal = IT_CloseHandle(hProc)
      End
    End
    If Not cCmdLine &= NULL
      Dispose(cCmdLine)
    End

The WaitForSingleObject is called with a handle to the running process if you want the calling program to wait for the called program. The called program will wait and practically be completely dead until the called program is terminated. When that happens the next line of code uses GetExitCodeProcess to retrieve the exit code from the called program and places it into a variable that is returned from the ITRun method.

Running with the Icetips Utilities

With the Icetips Utilities it is very easy to implement the ITRun to make running programs under Vista a non-issue. First you need to add the Global Utilities extension to your application - also to the data dll, or exporting dll so the classes are included and compiled.

In your procedure data embed you add an instance of the ITShellClass:

ITS  ITShellClass

Now you are ready to use it in the procedure:

 Code
 ITS.ITRun('"C:\Program Files\Icetips Creative\' &|
           'Build Automator\BuildAutomator.exe"',True,'/E',,True)

That is all there is to it!

Running without...

To demonstrate this and show how you can do this easily, we have uploaded a small sample app written in Clarion 6.3. It uses some of the code in the Icetips Utilities methods to let you select a program and run it, with optional parameters and option to wait for the called program to terminate. It also has a button where you can use the standard Clarion RUN statement and observe the differences under vista. I would suggest that you try to run something that requires administrator privileges - most installers do - and see what happens when you use the RUN statement and when you use the ITRun procedure instead.

You can download the ITRun.zip from the Icetips website at http://www.icetips.com/downloadfile.php?FileID=89 Please note that this is a simple ZIP file. Unzip it to a folder and read the docs.txt file in it. Compile the application and run it and try out for yourself how it works.

We have used those methods to run elevated applications, for example Web Updates for Setup Builder installs, for several years without any problems. We hope this little app helps you to get your applications running under Vista.

Our Icetips Utilities mentioned here is a collection of classes and templates for Clarion developers. They are part of our Gold Subscription plan.

The Build Automator is a developer tool to automate compiling and building applications and installs. It works with many developer tools such as Visual Studio, Delphi/RAD Studio 2008, Clarion, SetupBuilder, Inno Setup, Setup Factor and MSI Factory.

Some Interesting Links:

UAC Elevation in Managed Code: Guidance for Implementing COM Elevation

We welcome and appreciate your comments on this entry:)

-- Arnor Baldvinsson

3 thoughts on “Run programs elevated on Vista

  1. Vista still drives me crazy as I spend a fair bit of time daily helping clients fix permissions.

    For example, I want to run an FM3-driven application during the installation to automatically upgrade the end user's files, but then the resulting UPG.TPS belongs to the administrator, and blocks the end user from opening the application. The methods available to run a process unelevated from an installer are interpreted by some anti-virus applications as viral, so those can't be used... sometimes the list box format manager file also gets the wrong permissions.

    sigh... there's no end to it.

  2. Arnor

    Vince - thanks for the comment:)

    I think this is material for another blog entry;) This is definitely one area where UAC makes installs difficult. For example you cannot run your application at the end of an install if the installer is elevated and the installed program should not run elevated. The installed program then ends up being elevated and writes stuff into the wrong folders. What I've started doing is to install this stuff into COMMON_APPDATA and when the program starts up I run a "startup" process that takes care of those updates. Once done it updates a registry setting and either a setup file or an ini file so that it will not be done again. I like to use double safety on that so in case someone changes the registry it's also stored somewhere else and only if both places agree, the update process is run. Probably not perfect but seems to work so far.

    Arnor

Leave a Reply