Click here to Skip to main content
Email Password   helpLost your password?

Sample Image - VistaElevator.gif

Introduction

When developing applications for Windows Vista, one of the problems that often arises is how to programmatically control the execution level of a process. When the user starts an application, its elevation level is determined by the value of the requestedExecutionLevel attribute in its manifest, and Vista's User Account Control (UAC) takes appropriate actions depending on it (such as displaying the elevation prompt when needed, etc.) However, what if the application needs to start a new process with a different execution level than that of the application itself? For example:

Microsoft has provided a relatively easy way to accomplish the first task (starting a process elevated), by specifying the "runas" verb when calling the ShellExecuteEx API. However, for some reason they have not offered a similarly easy way of going in the opposite direction: to start a non-elevated process from an elevated one. In this article I will show how to solve this and related problems.

Determining the current elevation level

First of all, how can an application determine its current elevation level? The file VistaTools.cxx included in the source code to this article contains two functions that give the answer to this question.

The first such function is GetElevationType() and it uses the Win32 API GetTokenInformation() to obtain the elevation type of the token of the current process. The possible values that it can return are:

Note that the last two values can be returned only if both the UAC is enabled and the user is a member of the Administrator's group (that is, the user has a "split" token).

The second function is IsElevated() that also calls the GetTokenInformation() API, but requests the TokenElevation class of information. It can return one of the following:

Using these two functions, an application can determine the exact circumstances of its execution.

Starting an elevated process

If a non-elevated process needs to start an elevated one, all it has to do is call the ShellExecuteEx() API and supply the "runas" verb as one of its parameters. The source code of this article contains the function RunElevated() that does just that:

BOOL
RunElevated(    HWND hwnd,
        LPCTSTR pszPath,
        LPCTSTR pszParameters = NULL,
        LPCTSTR pszDirectory = NULL )
{
    SHELLEXECUTEINFO shex;

    memset( &shex, 0, sizeof( shex) );

    shex.cbSize        = sizeof( SHELLEXECUTEINFO );
    shex.fMask        = 0;
    shex.hwnd        = hwnd;
    shex.lpVerb        = _T("runas");
    shex.lpFile        = pszPath;
    shex.lpParameters    = pszParameters;
    shex.lpDirectory    = pszDirectory;
    shex.nShow        = SW_NORMAL;

    return ::ShellExecuteEx( &shex );
}

Starting a non-elevated process from an elevated one

Going in the opposite direction (from an elevated process to a non-elevated one) turns out to be much more difficult. If the parent process is elevated, then any process it starts directly becomes elevated too, no matter which value of the requestedExecutionLevel attribute is specified in the application's manifest. For some reason, Microsoft has not provided an API to lower the execution level directly, so we had to come up with an indirect way of achieving the goal.

The trick is to use the built-in Task Scheduler of Windows Vista to set up a task to be executed at the low execution level, and request that the task should start as soon as it is registered with Task Scheduler. The net result is about the same as if the process was started directly.

The source code of this article contains the function RunAsStdUser() that does exactly that. It is based on the MSDN sample "Registration Trigger Example", and it involves calls to more than a dozen COM interfaces to communicate with the Task Scheduler and set up a task to run at the standard (non-elevated) level. I am not including the source code of the function here as it's rather boring; you can find it in the file VistaTools.cxx

Seeing it all in action

The demo application (VistaElevator) illustrates how to perform both the elevation and lowering of the execution level programmatically. When you run it, it displays a dialog box that shows the information about the execution level of the current process obtained by calling GetElevationType() and IsElevated() (see above). It also offers you two choices of how to restart it, elevated or not. Depending on your choice, VistaElevator calls either RunElevated() or RunAsStdUser() functions (see above) to restart itself at the requested execution level.

Note: Make sure you have the latest Windows SDK (see msdn.microsoft.com for more information) if you want to compile the source code on your own.

An update: Vista Elevator 2.0

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralRun non-elevated, another method
Konkevych
4:31 16 Mar '09  
I think i have found (another) method to create limited token directly.
Here is the algorythm, proven to be functional:
1. CreateRestrictedToken with corresponding limited prilileges and Flags = 0x4 (LUA_TOKEN)
2. Retrieve linked token over GetTokenInformation from the created restricted token
3. Set "integrity level" via SetTokenInformation for the linked token
4. Return linked token

I cann't prove the created token is 100% the as "normal" limited token, but "is elevated", "elevation type" and "integrity level"
properties all returns proper results.
Generalimprovements to the 1.0 code
Todd C. Gleason
7:17 5 Mar '09  
I use a command-line tool I wrapped around the Vista Elevator 1.0 code. (I prefer not to use hooks myself so 1.0 really appealed to me.)

In any case, I have done a few things over time that make this code more reliable:

1. I generate a GUID as part of the task name instead of using a random number. This seems to work better when I run this multiple times in rapid succession (without it, a task may get deleted before it executes due to naming collisions). The basic code is interspersed into RunAsStdUser() roughly as follows:

    //  Choose a name for the task.

// initialize random seed
RPC_WSTR guidStr = 0x00;
GUID *pguid = new GUID;
UuidCreate(pguid);

// Convert the GUID to a string
UuidToString(pguid, &guidStr);
delete pguid;

WCHAR pszTaskName[90];
wsprintf((LPWSTR)pszTaskName, L"RunAsStdUser %s", guidStr);
::RpcStringFree(&guidStr);


...

// If the same task exists, remove it.
iRootFolder.p->DeleteTask( _bstr_t( pszTaskName), 0 ); // ignore error message, if any

...

DO( iRootFolder.p->RegisterTaskDefinition(
_bstr_t( pszTaskName ),
iTask.p,
TASK_CREATE_OR_UPDATE,
_variant_t(),
_variant_t(),
TASK_LOGON_INTERACTIVE_TOKEN,
_variant_t(),
&iRegisteredTask.p) )

...

//Delete the task when done
hr = iRootFolder.p->DeleteTask(
_bstr_t( pszTaskName ),
NULL);


2. I include this code (after put_StartWhenAvailable()) to make the task run even in battery mode (without it, laptops in battery mode won't execute these tasks at all):

	// We don't care about battery mode; start always
DO( iSettings.p->put_DisallowStartIfOnBatteries(VARIANT_BOOL(false)) )


--Todd C. Gleason
www.cool-man.org

GeneralImproved Function RunNonElevated() in V2.0
ncalverl
4:43 15 Jan '09  
Hi

You mention you have an updated v2.0 of your app with an improved RunNonElevated() function. Do you have the source available for this?
I did a quick check on the link you provided but could only find the application executable.

Cheers
Neil.
GeneralVista user account mode getting wrtting permission for an exe in program files/programdata
knareshkumar
19:14 1 Dec '08  
Hi,
i have an exe installed in program files or in programdata of vista's user account mode.
now i want to write in a xml file located in program files/programdata and in an ini file located in c:windows.

as from user account mode in vista i cannot write into any file.

can u help me in writing into the xml file(c:program file/c:programdata) and into an ini file(c:windows).

I am naresh kavali
intrested in formus of VC++, Com,ATL

GeneralRe: Vista user account mode getting wrtting permission for an exe in program files/programdata
knareshkumar
23:59 1 Dec '08  
I had used manifest in doing so for the exe

previously i was using only 'requireAdministrator' level and i was not getting the write permission now i added all three and its working....
Wink

I am naresh kavali
intrested in formus of VC++, Com,ATL

GeneralCan't built project
manh_duc
20:20 23 Nov '08  
I'm using Vista OS, VS2005 and last SDK for Vista to built project.
When I built it, it return error "TOKEN_ELEVATION_TYPE : undeclared identifier", but when I try built project on Win Server 2008, VS 2010 it run Ok.
Why it return error on Vista OS and how to fix this error?
Thanks!
GeneralRun As standard user with a manifest file
srinivas vaithianathan
21:23 9 Mar '08  
Thanks for the article. I was able to understand how to run a program as standard user programmatically. But can we specify standard user execution levels in the manifest file similiar to RequireAdministrator?
QuestionRegarding UAC and drag and drop and other problems.
na.nu
18:36 19 Nov '07  
Hi,

Read your article and used "run as" in installer and added manifests to a application executables that I am working on. Am able to get the elevation prompt on launch of the application. I am facing some problems though:

1) The application (win32) I am working on uses drag and drop. It a legacy application and I still use an old IDE for its development. The problem is that elevation has worked but drag and drop does not work any more. I read that since explorer and the desktop work at a lower priviledge level (medium) my application cannot receive any messages related to drag and drop. How do I resolve this? I have tried adding drag and drop messages to the application message filter using an API Changewindowmessagefilter(). This caused the application to crash.

2) I require to map a drive for my application to use. If I use Explorer to map the drive then my application does not recieve any messages regarding the added network drive. If I map using my application then only does my application becomes aware of the network drive.

3) All folders in a drive are set to read only so I cant send files to these drives as I get write protection status on checking the drive before copying.

Please help. Thanks.

Cry
AnswerRe: Regarding UAC and drag and drop and other problems.
Andrei Belogortseff
13:37 20 Nov '07  
> I have tried adding drag and drop messages to the application message filter using an API Changewindowmessagefilter(). This caused the application to crash.

We use ChangeWindowMessageFilter() in our products and it works just fine. You may want to run your application with a debugger to see what exactly is causing the crash, and go from there.

HTH



Andrei Belogortseff
http://www.winability.com

GeneralHow to elevate when UAC is disabled ?
_Olivier_
0:44 16 Nov '07  
When UAC has been globally disabled in the control panel and you're running a standard (limited) account, how to get the admin prompt or a credential dialog when launching a new program ?
I tried several things :
- use "runas" with ShellExecute(Ex)
- use a manifest with requireAdministrator
- name the program Install.exe
- right-click "Run as administrator"

None of these would bring a dialog asking for admin right. Programs would however still be launched but with the current user rights.
I was unable to find a solution on Internet to programmatically force a credential dialog in such situation, can someone help ?
GeneralRe: How to elevate when UAC is disabled ?
Geert van Horrik
6:58 18 Mar '08  
Did you ever found an answer to this question/problem?

Geert

Need an advanced auto-update feature for your software? Try Updater!
Visit my website: http://www.catenalogic.com

GeneralRe: How to elevate when UAC is disabled ?
_Olivier_
7:51 18 Mar '08  
unfortunately no Frown
GeneralRe: How to elevate when UAC is disabled ?
Geert van Horrik
8:38 19 Mar '08  
You can use CreateProcessWithLogonW! Good luck implementing this in your software.

Geert

Need an advanced auto-update feature for your software? Try Updater!
Visit my website: http://www.catenalogic.com

GeneralRe: How to elevate when UAC is disabled ?
_Olivier_
4:15 21 Mar '08  
...and probably CredUIPromptForCredentials for the dialog box
GeneralCan one Elevate from Low to Medium?
Don Griffin
19:08 29 Aug '07  
We've been working on a signed Java applet that downloads an EXE that needs to be run as the user (not admin). The IE dialog asking for permission to go up to medium integrity is not displayed when our app is in the low integrity temp directory. It silently executes the app at low integrity (ignoring our manifest asking for highestAvailable). IE only displays the elevation prompt when we execute apps from other directories. Oddly, IE also does not seem to display the elevation-to-medium prompt for limited users regardless of the app's location. I'm hoping that in your experiments you've dealt with the lack of docs on this type of elevation. Any help appreciated! (Oh, and thanks for the awesome article!)
GeneralClose application if non-elevated process is opened.
Identity Undisclosed
13:32 9 Aug '07  
Hi,

I want to close the application in case user chooses to select to open the application with limited i.e restart as non-elevated process.

Any idea how can i detect this.

Thanks.


"C makes it easy to shoot yourself in the foot. C++ makes it
harder, but when you do, it blows away your whole leg."
- Bjarne Stroustrup

GeneralRe: Close application if non-elevated process is opened.
Andrei Belogortseff
9:36 29 Aug '07  
> I want to close the application in case user chooses to select to open the application with limited i.e restart as non-elevated process. Any idea how can i detect this.

Sure: call GetElevationType() and if it returns TokenElevationLimited, it means your application is running as a limited user.

HTH

Andrei Belogortseff
http://www.winability.com

GeneralGet around Vista UAC restriction and prompt for the most part
nnm
15:38 1 Aug '07  
I have worked with Vista's UAC issues for the past month and learned that you can minimize the UAC restriction with some minor changes to your application.

1. Include a manifest file with a "asInvoker" requestedExecutionLevel level

2. Replace Registry or system configuration with a local configuration file

3. Vista UAC monitor write access to "Program Files" and "ProgramData" folder so the best way to avoid access restriction is to place your owned configuration file in a local folder that only your app know - "C:\MyAppConfig\". Don't following MS recommandation on getting system folder and such - unless you really have to.

Last, if your app do not create processes or manipulate system level operations with these changes, you can eliminate the "Admin" execution level and avoid the UAC annoyning prompts.

--



nn
GeneralRe: Get around Vista UAC restriction and prompt for the most part
Andrei Belogortseff
12:09 2 Aug '07  
> 2. Replace Registry or system configuration with a local configuration file

Or, just make sure you don't write to the HKLM branch of the registry. If you only write to the HKCU branch, you should not have any problem with UAC.

>> 3. Vista UAC monitor write access to "Program Files" and "ProgramData" folder so the best way to avoid access restriction is to place your owned configuration file in a local folder that only your app know - "C:\MyAppConfig\". Don't following MS recommandation on getting system folder and such - unless you really have to.
<<

This is a really bad advice. The first problem is that if you attempt to create a folder under C:\ from a non-elevated process, Vista will deny access to it for your application. But that's the smallest of all the possible problems that can happen.

Microsoft offers dedicated folders where application should store the settings files, user documents, etc. Using them _is_ the best way of making sure your application plays well with UAC, and other Windows parts.



Andrei Belogortseff
http://www.winability.com

GeneralRe: Get around Vista UAC restriction and prompt for the most part
nnm
14:40 2 Aug '07  
All processes are created with whatever happened to be the user's privilege execution level at the time - Most systems are operated as Admin or Super user, unless the application is in a terminal environment or corporate IT shared systems (which is rather rare, except server and such). So there is hardly a case of creating directory from non-elevated process in 99% of the time.

If you continue to use MS dedicated folders and such, you will continue to subject your application in MS's UAC nightmare. Frankly, my notes are to remind people that you don't have to follow MS half bake UAC security implementation. You can get away from it and focus on your owned app with some simple implementation. Of course each scenario is different, but the key is one can get away from the UAC nightmare if one just open his/her eyes. Last, if UAC was so superior and a good thing; MS would not allow the user to turn it off completely easily. Bottom line, you can follow MS's UAC blindly or just get away from it.

nn.
GeneralRe: Get around Vista UAC restriction and prompt for the most part
Andrei Belogortseff
15:06 2 Aug '07  
> All processes are created with whatever happened to be the user's privilege execution level at the time - Most systems are operated as Admin or Super user, unless the application is in a terminal environment or corporate IT shared systems (which is rather rare, except server and such). So there is hardly a case of creating directory from non-elevated process in 99% of the time.

I thought you were writing about an application that was supposed to run non-elevated? If you were writing your recommendations for an administrative application, it's another thing.

> If you continue to use MS dedicated folders and such, you will continue to subject your application in MS's UAC nightmare.

Quite the opposite, in my experience.

The problem with not using the recommended folders is not just about handling UAC, it's about many other things. Suppose several users can log in to this particular computer and use your application, how do you handle that? Do you create a separate settings file for each user? If yes, how do you associate each file with the correct user? How do you prevent users from peeking into the files that belong to other others? What if the user is roaming and logged on to another computer, how do you move the settings file to that computer? When the user wants to backup the settings, at which point do you remind him to add your folder to the backup set? And so on. Not using the recommended folders means that you have to find solutions to such problems on your own. If you use the standard folders, you get the solution for free!

Of course, there can be exceptions to the rules, but generally not using the recommended folders is not a good idea. (Let's agree to disagree about that.)

Andrei Belogortseff
http://www.winability.com

QuestionUAC elevator problem [modified]
vikasetrx
23:47 24 Jun '07  
I tried using the 2.0 version of UAC elevator. Specifically I used only RunNonelevated.

But everytime the call to ::SetWindowsHookEx() returns NULL handle and i found through ::GetLastError() that the error code is 1428(needs module handle). This means that ::GetModuleHandleEx() is not giving the correct handle. Is that right?

I tried to get across this by 1st using LoadLibrary() and giving the path of the dll that has been created with RunNonElevated() function. But this time the call to ::SetWindowHookEx() gives absurd results. The system hangs for a long time, then error comes that there is unknown software exception in iexplorer and same error in dv20.exe and then such errors keep coming. I am not able to proceed, the whole thing blacks out. Finally all the open windows are killed automatically and only then i am able to resume.

I am not sure what is happening. One thing that bothers me is that you mention to use recent SDKs. What do you mean by that ? Is is likely that this error has been caused by that ?


-- modified at 5:30 Monday 25th June, 2007
AnswerRe: UAC elevator problem
Andrei Belogortseff
11:44 25 Jun '07  
> I am not sure what is happening.

Me neither, sorry. It is working for me. You may also try a newer code that I posted with this article:

http://www.codeproject.com/vista-security/RunNonElevated.asp

> One thing that bothers me is that you mention to use recent SDKs. What do you mean by that ?

I mean that you need to use the latest version of the Windows SDK that includes the Vista-specific stuff.

Good luck!

Andrei Belogortseff
http://www.winability.com

GeneralCurrent process elevation
InfiniteCode
0:34 10 Apr '07  
Hi!

Great article!

I am interested how can I elevate my application level when it is running.
For example: I am starting the application as invoker, and then later
(not always) I need to execute some functions, that require administrator, like
registry, or program files folder file operations. The thing is that I don't
need to keep all the time program as administrator, that can be easily done with
manifest. I need to rise the level, and then move it back to asInvoker.

Thanks in advance!
GeneralRe: Current process elevation
Andrei Belogortseff
8:09 11 Apr '07  
> I am interested how can I elevate my application level when it is running.

The short answer is: you cannot. You can only start a separate (elevated) process when you need to do the administrative actions.

Andrei Belogortseff
http://www.winability.com


Last Updated 27 Feb 2007 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010