Hi Team,
I am using the advapi32.dll to consume CreateProcessAsUser to launch the ui exe(UIAccess=true) in user context.
But i am getting elevated permission required exception..
I googled it and found that we need to use SetTokenInformation to make it work for uiaccesss=true exe's.
Could you please guide me how to do it..?
Below is my current code..
public Process StartProcessAsCurrentUser(string appPath, string cmdLine = null, string workDir = null, bool visible = true)
// APIs below will fail if it is not running in session 0
//if (Process.GetCurrentProcess().SessionId != 0)
// return null;
var userToken = IntPtr.Zero;
var startInfo = new NativeStructsNew.STARTUPINFO();
var procInfo = new NativeStructsNew.PROCESS_INFORMATION();
var environmentHandler = IntPtr.Zero;
Process result = null;
startInfo.cb = Marshal.SizeOf(typeof(NativeStructsNew.STARTUPINFO));
if (!GetActiveSessionUserToken(out userToken))
throw new Exception($"{nameof(StartProcessAsCurrentUser)} - {nameof(GetActiveSessionUserToken)} failed.");
int dwCreationFlags = NativeConsts.CREATE_UNICODE_ENVIRONMENT | (visible ? NativeConsts.CREATE_NEW_CONSOLE : NativeConsts.CREATE_NO_WINDOW);
startInfo.wShowWindow = (short)(visible ? SW.SW_SHOW : SW.SW_HIDE);
startInfo.lpDesktop = "winsta0\\default";
if (!NativeMethodsNew.CreateEnvironmentBlock(ref environmentHandler, userToken, false))
int errorCode = Marshal.GetLastWin32Error();
throw new Exception($"{nameof(StartProcessAsCurrentUser)} - {nameof(NativeMethodsNew.CreateEnvironmentBlock)} failed. GetLastError = {errorCode}");
var sa = new NativeStructsNew.SECURITY_ATTRIBUTES();
sa.Length = Marshal.SizeOf(sa);
var ta = new NativeStructsNew.SECURITY_ATTRIBUTES();
ta.Length = Marshal.SizeOf(ta);
if (!NativeMethodsNew.CreateProcessAsUser(userToken, appPath, cmdLine, ref sa, ref ta, false,
dwCreationFlags, environmentHandler, workDir, ref startInfo, out procInfo))
int errorCode = Marshal.GetLastWin32Error();
throw new Exception($"{nameof(StartProcessAsCurrentUser)} - CreateProcessAsUser failed. GetLastError = {errorCode}");
uint pid = procInfo.dwProcessId;
result = Process.GetProcessById((int)pid);
catch (Exception)
// The process does not exist
result = null;
finally
if (userToken != IntPtr.Zero)
NativeMethodsNew.CloseHandle(userToken);
if (environmentHandler != IntPtr.Zero)
NativeMethodsNew.DestroyEnvironmentBlock(environmentHandler);
if (procInfo.hThread != IntPtr.Zero)
NativeMethodsNew.CloseHandle(procInfo.hThread);
if (procInfo.hProcess != IntPtr.Zero)
NativeMethodsNew.CloseHandle(procInfo.hProcess);
return result;
---------
private static UInt32 GetActiveConsoleSessionId()
IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
uint activeSessionId = Platform.NoUserSession;
IntPtr infoSessionsHandler = IntPtr.Zero;
int sessionsCount = 0;
if (NativeMethodsNew.WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, ref infoSessionsHandler, ref sessionsCount))
Int32 dataSize = Marshal.SizeOf(typeof(NativeStructsNew.WTS_SESSION_INFO));
IntPtr current = infoSessionsHandler;
for (int i = 0; i < sessionsCount; i++)
var si = (NativeStructsNew.WTS_SESSION_INFO)Marshal.PtrToStructure(current, typeof(NativeStructsNew.WTS_SESSION_INFO));
if (WTS_CONNECTSTATE_CLASS.WTSActive == si.State)
activeSessionId = si.SessionID;
break;
current += dataSize;
if (infoSessionsHandler != IntPtr.Zero)
NativeMethodsNew.WTSFreeMemory(infoSessionsHandler);
return activeSessionId;
catch (Exception ex)
Debug.WriteLine("exception in GetActiveConsoleSessionId - {0}", ex);
return Platform.NoUserSession;
public uint GetActiveUserSessionId()
return GetActiveConsoleSessionId();
public bool GetActiveSessionUserToken(out IntPtr userToken)
userToken = IntPtr.Zero;
bool result = false;
IntPtr userTokenHandle = IntPtr.Zero;
// Get active user session id by enumerating through the sessions
uint activeSessionId = GetActiveUserSessionId();
// If enumerating did not work, fall back to the old method
if (activeSessionId == NativeConsts.INVALID_SESSION_ID)
activeSessionId = NativeMethodsNew.WTSGetActiveConsoleSessionId();
// Get the primary access token of the logged-on user specified by the session ID
if (activeSessionId != NativeConsts.INVALID_SESSION_ID
&& NativeMethodsNew.WTSQueryUserToken(activeSessionId, out userTokenHandle) != 0)
var ta = new NativeStructsNew.SECURITY_ATTRIBUTES();
ta.Length = Marshal.SizeOf(ta);
// Convert the impersonation token to a primary token
result = NativeMethodsNew.DuplicateTokenEx(userTokenHandle, 0, ref ta,
(int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, (int)TOKEN_TYPE.TokenPrimary,
out userToken);
NativeMethodsNew.SetTokenInformation(userToken, TOKEN_INFORMATION_CLASS.TokenUIAccess, 0, (UInt32)IntPtr.Size);
finally
if (userTokenHandle != IntPtr.Zero)
NativeMethodsNew.CloseHandle(userTokenHandle);
return result;
NativeMethodsNew.SetTokenInformation(userToken, TOKEN_INFORMATION_CLASS.TokenUIAccess, 0, (UInt32)IntPtr.Size);
I see two issues in this line of code --
If you want to set the UIAccess flag in the token you must pass 1 instead of 0. The docs describing TokenUIAccess say "The buffer receives a DWORD value that is nonzero if the token has the UIAccess flag set." In 64-bit code IntPtr.Size will be 8 bytes, but the TokenUIAccess should be set with a 4 byte value. It appears that in 64 bit code the function passes the wrong size information. Use uint instead of IntPtr to always work with a 4 byte value.
Un WPF UI exe which i am trying to launch has below
<requestedExecutionLevel level="asInvoker" uiAccess="true" />
SerTokenInformation method with api in NativeMethodnew class.
The Below code is where i am calling SetTokenInformation.
Still i am getting the same issue.. Please assist me the correct code..