This little article shows you how to elevate an application using JWSCL.
There are two possible ways to elevate an application :

  1. Elevate the application from the beginning
  2. Elevate special parts of your application

Both ways needs a manifest to be included into your application.

1. Elevate the application from the beginning

The easiest way to elevate an application is to tell Windows to do it for you. This is done by applying a manifest.

A manifest is a text resource that tells Windows what needs to be prepared before your application starts. This includes theme support and privileges your application needs. Developers maybe know it from Windows XP where it enables themed window controls.

Telling Windows to start your application as an administrator is done by using “requireAdministrator” as required security level in the manifest. However the code below is just an excerpt. You can get a full version of the manifest with a warning.

<security>
  <requestedPrivileges>
    <requestedExecutionLevel level="requireAdministrator"/>
  </requestedPrivileges>
</security>

If you are going to use this manifest in your application, you have to consider that your application needs to be elevated all the time. Thus users without administrator access cannot launch your application at all.

However there is a second way which does not need a manifest at all. Some applications do start their own process with elevated rights. They start a second instance, close the actual one and go on elevated.
Examples are :

  • the Taskmanager can elevate itself by clicking “Show processes from all users”
    Bild
  • ProcessExplorer
    Bild

JWSCL contains a unit called JwsclElevation which provides the necessary functions to allow this simple elevation.

function JwShellExecute(const hWnd: HWND; FileName, Parameters,
Directory: TJwString; ShowCmd: Integer): HINST;
This function just works like the usual ShellExecute but let’s you elevate any program or your application. The return value In the following way you can start the command line prompt with elevated privileges.

var hProc : THandle;
begin
  hProc := JwShellExecute(0, ‘cmd’, , , SW_SHOW);
  if hProc <> 0 then
    CloseHandle(hProc);

The developer version (revision > 317) does have some more extension, less bugs and a different behavior.

function JwShellExecute(const hWnd: HWND;
    FileName,
    Parameters,
    Directory: TJwString;
    ShowCmd: Integer;
    Flags : TJwShellExecuteFlags = [sefNoClosehProcess]): HANDLE;

Let me list the differences :

  • JwShellExecute raises EJwsclWinCallFailedException when the call to ShellExecuteEx fails.
  • The new optional parameter Flags controls some aspects
    • sefNoUi does not allow ShellExecute to show error messages on the user’s screen
    • sefIgnoreElevationIfNotAvailable. Usually JwShellExecute checks whether the user is already elevated and if so just starts the application. However this call will fail on preVista systems. If this flag is set the function will not fail on preVista systems and just execute the application.
    • sefFixDirWithRunAs. ShellExecute ignores the directory parameter if it is called with the “runas” verb. However with this flag set, the JEDI function uses a trick to start the application in the correct directory. In this way there maybe a command window visible.
    • sefNoClosehProcess. The newer version of JwShellExecute closes the returned process handle for you if this flag is not set. If you need that process handle (e.g. waiting for the process to end) you should remove it.
  • The return value is a handle to the process. It is now automatically closed for your if you do not deny it through the flag parameter.

The following code shows how to start the application with elevated privileges from whithin the same app.

var NewProcessHandle : HANDLE;
begin
  try
    NewProcessHandle := JwShellExecute(ForeGroundWindow,
        ParamStr(0), Parameter, Directory, SW_NORMAL,
        [sefNoUi, sefFixDirWithRunAs,
         sefIgnoreElevationIfNotAvailable, sefNoClosehProcess]);
    except
    On E : EJwsclWinCallFailedException do
    begin
      LastError := E.LastError;
      //do error stuff here
     exit;
    end;
  end;
  //make sure the app has started
  if NewProcessHandle <> 0 then
  begin
    //wait for the app to be initialized and read to get user input
    //or just remove it – what you like
    WaitForInputIdle(NewProcessHandle, yourTimeHere);
    CloseHandle(NewProcessHandle);
    //terminate your application here
  end;

2. Elevate special parts of your application

To elevate special parts of your application is the prefered way for a Vista application. This is done by separate the parts of your application that needs administrative rights, into an external process. We do not need to create a new application and do the inter-process communication stuff. Windows Vista uses an external COM process for this task. So the solutions goes with a COM DLL that we have to implement. In addition to that we also have to add a manifest – of course.

<security>
  <requestedPrivileges>
    <requestedExecutionLevel level="asInvoker"/>
  </requestedPrivileges>
</security>

I will not tell the whole story about how to create a COM DLL and do all the stuff that has to be done. You should read Aleksander Oven’s tutorial how to accomplish that.
I’m going to show you how you can use the JWSCL methods.

Create your COM Dll and implement the COM interface. This may look like this (from the RunEl example in JWSCL):

uses jwaWindows, ActiveX, Dialogs,
  Classes, ComObj, RunElCOM_TLB, StdVcl;      

type
 TJwRunElevated = class(TTypedComObject, IJwRunElevated)
 protected
  function RunAppElevated(AppName: PWideChar;
     Parameter: PWideChar; Dir: PWideChar;
     ClientProcessID: LongWord; out NewThreadHandle: LongWord;
     out NewProcessHandle: LongWord;
     out ResultValue: LongWord): HResult;  stdcall; end;

The important stuff comes here.

initialization
  TElevationClassFactory.Create(
    @ElevationDescription, true,
    ComServer, TJwRunElevated,
    CLASS_JwRunElevated,
    iMultiInstance);

Use the TElevationClassFactory or TJwElevationClassFactory (in developer version > 317) for registering the COM class in Windows. After you registered the COM class using regsvr32 (see Tutorial) you can retrieve an instance of the COM class with JwCoCreateInstanceAsAdmin.

var
  ElevatedObject: IJwRunElevated;
  Result : HRESULT;
begin
  Result := JwCoCreateInstanceAsAdmin(
       ForeGroundWindow,
       CLASS_JwRunElevated,
       IID_IJwRunElevated,
       ElevatedObject);

If the thread has already elevated privileges the function JwCoCreateInstanceAsAdmin simply returns an instance without using the elevation prompt.

In developer version (revision > 317) the returned result value can contain information about the status.

  • ERROR_SUCCESS – No error
  • (revision > 317) ERROR_CANCELLED – the user has canceled the UAC prompt.
  • (revision > 317) E_CLASS_IS_NOT_SETUP – the requested COM class has not been setup to be used for elevation.
  • CoGetObject (if elevation is required) or CoCreateInstance (if elevation is not required) may return an error value

Be warned:
If you try to execute this function on a preVista system, the function is going to fail with EJwsclUnsupportedWindowsVersionException.


You can find the shown source code in the repository of JWSCL. The library has two sample applications that use the technics describes above:

Warning:
There is a problem with the manifest scanner on Windows XP. If you try to start an application with a manifest created for Vista you’re goingt to probably have a Blue Screen of Death. So you have to get a correct manifest from here (english translation).

Tell me how you liked this blog entry by adding a comment.