Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.

ID: 24512, Example Console App with User Account Control (UAC) support

by Fredrik Haglund Email: Anonymous

Example console appilcation showing how to make an Command Line application that is Windows Vista compatible and aware of User Account Control (UAC)
Download Details
FTP  download also available
CDN Login Required to Download. (You will be redirected to the login page if you click on the Download Link)
To download this, you must have registered:
A free membership

For Delphi, Version 10.0  to 11.0 721 downloads
Copyright: No significant restrictions

Terms of use: Embarcadero use at your own risk disclaimer

Size: 4,685 bytes
Updated on Sun, 18 Mar 2007 19:43:39 GMT
Originally uploaded on Sun, 18 Mar 2007 19:41:45 GMT
SHA1 Hash: 125A222124AEF9C55CE97DF00C11D6AF2CD8AD3E
MD5 Hash: E7555848701A5B79DB9CEF5BB4438D23

    Explore the files in this upload

I talked about User Account Control (UAC) during my CodeRage-session last week. I think UAC is one of the most important features of Windows Vista and if you are not in total control of your users' environment, sooner or later you will run into questions and support issus related to UAC.

UAC Horror Story
I heard a real horror story related to UAC from a developer in Sweden last week during the Delphi User Group meeting in Stockholm. Their application has a local database and the database engine is launched by the application. Since UAC made the application start as Standard User the database enginge also started as Standard User. But a Standard User did not have the rights needed to modify the database files where they got installed. You would assume that this would generate an Access Denied error or some other error message? But no, and now the horror begins...

Since their application did not have required execution level information in the manifest Windows Vista runs the process in compatibility mode. Instead of failing to open the database which the process has no right to modify Windows Vista silently makes a copy of the whole database (to the personal VirtualStore for each user) and saves the changes there instead. The users did not notice anything initally because they work on diffrent projects but after a while they started to wonder why they could not see any changes their colleagues have done.

When they found out what was wrong they had to do a lot of manual work to merge each users' copy of the database back into one database again...

Conclusion: To get rid of the dangerous compatibility feature called Virtualization or Redirection by adding a manifest with required execution level to all you executables immediately! This can be done easily by just recompiling your application in Delphi 2007 for Win32 and checking use themes in project options or use the xpman unit in D2007. With an earlier Delphi release you can manually create and include the manifest.

Command Line Applications
I did not talk so much about command line applications and UAC during my Code-Rage session so I would like to write a little about that.

First, like with all applications targeting Windows Vista, you should have a manifest with required execution level to turn off compatibility mode. But even if you command line tool requires admin privileges you should never set level = "requireAdministrator". The reason for this is that you do not want a batch script to be interrupted with a modal consent dialog, instead Microsoft recommends you to halt execution with an error message and set the exit code to ERROR_ELEVATION_REQUIRED.

program VistaConsoleApplication;


//Include Manifest with trustinfo to make executable Vista Logo Compliant and not run in compatibility mode.
//Console Applications should always run as invoker even if they require admin privileges.
{$R 'ExecutionLevelAsInvokerManifest.res' 'ExecutionLevelAsInvokerManifest.rc'}

UserAccessControlUtils in 'UserAccessControlUtils.pas';

//Call function to test we have admin privelieges

//TODO: Your admin tool here...

The RequireAdminConsole function is really simple and it uses a function IsUserAnAdmin in the WinAPI to test. I have written the code so it binds dynamically. The reason is to make it work on operation systems before Windows 2000. You could also use a NT4 compatible apporoach and check if token has SID for admin group but that would be much more code...

ModName = 'shell32.dll';
hShell32: HMODULE;
_IsUserAnAdmin: function(): BOOL; stdcall;

function IsUserAnAdmin: Boolean;
if Assigned(_IsUserAnAdmin) then
Result := _IsUserAnAdmin()
Result := True;
if hShell32 = 0 then
hShell32 := LoadLibrary(ModName);
if hShell32 <> 0 then
_IsUserAnAdmin := GetProcAddress(hShell32, 'IsUserAnAdmin'); // Do not localize
if Assigned(_IsUserAnAdmin) then
Result := _IsUserAnAdmin();

SErrorElevationRequired = 'Access Denied. Administrator permissions are needed to use the selected options. Use an administrator command prompt to complete these tasks.';

procedure RequireAdminConsole;
if not IsUserAnAdmin then

A new question
The code above just checks if your process is currently running with admin privileges. But with UAC there is also another question - can the user become an administrator?

Since UAC splits the login token into a user token and a full token during login (if you have admin priveliges) you need to use new WinAPI features to find the answer to this question.

//Enumeration is mirroring TOKEN_ELEVATION_TYPE in Windows Vista SDK (except first value).
TTokenElevationType = (TokenElevationNotAvailable, TokenElevationTypeDefault, TokenElevationTypeFull, TokenElevationTypeLimited);

//Extend existing enumeration in Windows.pas with new Vista constants
TTokenInformationClass = (TokenUser = 1, TokenGroups, TokenPrivileges,
TokenOwner, TokenPrimaryGroup, TokenDefaultDacl, TokenSource, TokenType,
TokenImpersonationLevel, TokenStatistics, TokenRestrictedSids, TokenSessionId,
TokenGroupsAndPrivileges, TokenSessionReference, TokenSandBoxInert, TokenAuditPolicy,
TokenOrigin, TokenElevationType, TokenLinkedToken, TokenElevation, TokenHasRestrictions,
TokenAccessInformation, TokenVirtualizationAllowed, TokenVirtualizationEnabled,
TokenIntegrityLevel, TokenUIAccess, TokenMandatoryPolicy, TokenLogonSid);

function GetTokenElevationType: TTokenElevationType;
hToken: THandle;
elevationType: Integer;
dwSize: DWORD;
Result := TokenElevationNotAvailable;
hToken := 0;
Win32Check(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, hToken));
if GetTokenInformation(hToken, Windows.TTokenInformationClass(TokenElevationType), @elevationType, sizeof(elevationType), dwSize) then
Result := TTokenElevationType(elevationType);
if hToken<>0 then

Call the function GetTokenElevationType above to test the current state of elevation.

case GetTokenElevationType of
WriteLn('No information about elevation is available. (This is a non-vista machine)');
WriteLn('TokenElevationTypeDefault - User is not using a split token.');
WriteLn('TokenElevationTypeFull - User has a split token, and the process is running elevated.');
WriteLn('TokenElevationTypeLimited - User has a split token, but the process is not running elevated.');

   Latest Comments  View All Add New

Move mouse over comment to see the full text

Could not retrieve comments. Please try again later.

Server Response from: ETNACDC03