UacHelpers.CppLibrary/UserAccountControl.cpp
author StephaneLenclud
Thu, 18 Apr 2013 23:25:10 +0200
changeset 402 ded1323b61ee
permissions -rw-r--r--
Front View plug-in does not init if no sensor added.
Fixing some format to make strings shorter.
Now trying to start SoundGraphAccess.exe process from same directory.
Packed mode now can display three sensors along with the current time.
     1 #include "UserAccountControl.h"
     2 
     3 #include <windows.h>
     4 #pragma comment (lib, "kernel32.lib")
     5 #pragma comment (lib, "advapi32.lib")
     6 
     7 #include <vcclr.h>
     8 #include <msclr\marshal.h>
     9 #include <msclr\marshal_windows.h>
    10 
    11 using namespace msclr::interop;
    12 
    13 using namespace System::ComponentModel;
    14 using namespace Microsoft::Win32;
    15 
    16 namespace UacHelpers {
    17 
    18 	Process^ UserAccountControl::CreateProcessAsAdmin(System::String^ exePath, System::String^ arguments)
    19     {
    20         ProcessStartInfo^ psi = gcnew ProcessStartInfo(exePath, arguments);
    21         psi->UseShellExecute = true;
    22         psi->Verb = "runas";
    23 		return Process::Start(psi);
    24     }
    25 
    26 	Process^ UserAccountControl::CreateProcessAsStandardUser(System::String^ exePath, System::String^ arguments)
    27 	{
    28 		marshal_context context;
    29 
    30 		//If the current process is not elevated, then there's no reason to go through the hassle --
    31 		//just use the standard System.Diagnostics.Process facilities.
    32 		if (!IsCurrentProcessElevated)
    33 		{
    34 			return Process::Start(exePath, arguments);
    35 		}
    36 
    37 		//The following implementation is roughly based on Aaron Margosis' post:
    38 		//http://blogs.msdn.com/aaron_margosis/archive/2009/06/06/faq-how-do-i-start-a-program-as-the-desktop-user-from-an-elevated-app.aspx
    39 
    40 		//Enable SeIncreaseQuotaPrivilege in this process.  (This requires administrative privileges.)
    41 		HANDLE hProcessToken = NULL;
    42 		if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hProcessToken))
    43 		{
    44 			throw gcnew Win32Exception(GetLastError());
    45 		}
    46 		else
    47 		{
    48 			TOKEN_PRIVILEGES tkp;
    49 			tkp.PrivilegeCount = 1;
    50 			LookupPrivilegeValueW(NULL, SE_INCREASE_QUOTA_NAME, &tkp.Privileges[0].Luid);
    51 			tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    52 			AdjustTokenPrivileges(hProcessToken, FALSE, &tkp, 0, NULL, NULL);
    53 			DWORD dwLastErr = GetLastError();
    54 			CloseHandle(hProcessToken);
    55 			if (ERROR_SUCCESS != dwLastErr)
    56 			{
    57 				throw gcnew Win32Exception(dwLastErr);
    58 			}
    59 		}
    60 
    61 		//Get window handle representing the desktop shell.  This might not work if there is no shell window, or when
    62 		//using a custom shell.  Also note that we're assuming that the shell is not running elevated.
    63 		HWND hShellWnd = GetShellWindow();
    64 		if (hShellWnd == NULL)
    65 		{
    66 			throw gcnew System::InvalidOperationException("Unable to locate shell window; you might be using a custom shell");
    67 		}
    68 
    69 		//Get the ID of the desktop shell process.
    70 		DWORD dwShellPID;
    71 		GetWindowThreadProcessId(hShellWnd, &dwShellPID);
    72 		if (dwShellPID == 0)
    73 		{
    74 			throw gcnew Win32Exception(GetLastError());
    75 		}
    76 
    77 		//Open the desktop shell process in order to get the process token.
    78 		HANDLE hShellProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwShellPID);
    79 		if (hShellProcess == NULL)
    80 		{
    81 			throw gcnew Win32Exception(GetLastError());
    82 		}
    83 
    84 		HANDLE hShellProcessToken = NULL;
    85 		HANDLE hPrimaryToken = NULL;
    86 		try
    87 		{
    88 			//Get the process token of the desktop shell.
    89 			if (!OpenProcessToken(hShellProcess, TOKEN_DUPLICATE, &hShellProcessToken))
    90 			{
    91 				throw gcnew Win32Exception(GetLastError());
    92 			}
    93 
    94 			//Duplicate the shell's process token to get a primary token.
    95 			const DWORD dwTokenRights = TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID;
    96 			if (!DuplicateTokenEx(hShellProcessToken, dwTokenRights, NULL, SecurityImpersonation, TokenPrimary, &hPrimaryToken))
    97 			{
    98 				throw gcnew Win32Exception(GetLastError());
    99 			}
   100 
   101 			//Start the target process with the new token.
   102 			STARTUPINFO si = {0}; si.cb = sizeof(si);
   103 			PROCESS_INFORMATION pi = {0};
   104 			if (!CreateProcessWithTokenW(hPrimaryToken, 0,
   105 				context.marshal_as<LPCWSTR>(exePath), context.marshal_as<LPWSTR>(exePath + " " + arguments),
   106 				0, NULL, NULL, &si, &pi))
   107 			{
   108 				throw gcnew Win32Exception(GetLastError());
   109 			}
   110 			CloseHandle(pi.hProcess);
   111 			CloseHandle(pi.hThread);
   112 
   113 			return Process::GetProcessById(pi.dwProcessId);
   114 		}
   115 		finally
   116 		{
   117 			if (hShellProcessToken != NULL)
   118 				CloseHandle(hShellProcessToken);
   119 
   120 			if (hPrimaryToken != NULL)
   121 				CloseHandle(hPrimaryToken);
   122 
   123 			if (hShellProcess != NULL)
   124 				CloseHandle(hShellProcess);
   125 		}
   126 	}
   127 
   128 	bool UserAccountControl::IsUserAdmin::get()
   129 	{
   130 		if (UserAccountControl::IsUacEnabled)
   131 			return GetProcessTokenElevationType() != TokenElevationTypeDefault;	//split token
   132 
   133 		//If UAC is off, we can't rely on the token; check for Admin group.
   134 		return WindowsPrincipal(WindowsIdentity::GetCurrent()).IsInRole("Administrators");
   135 	}
   136 
   137 	bool UserAccountControl::IsUacEnabled::get()
   138 	{
   139 		//Check the HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\System\EnableLUA registry value.
   140 		RegistryKey^ key = Registry::LocalMachine->OpenSubKey(UacRegistryKey, false);
   141 		return key->GetValue(UacRegistryValue)->Equals(1);
   142     }
   143 
   144 	void UserAccountControl::DisableUac()
   145 	{
   146 		SetUacRegistryValue(false);
   147 	}
   148 
   149 	void UserAccountControl::DisableUacAndRestartWindows()
   150 	{
   151 		DisableUac();
   152 		RestartWindows();
   153 	}
   154 
   155 	void UserAccountControl::EnableUac()
   156 	{
   157 		SetUacRegistryValue(true);
   158 	}
   159 
   160 	void UserAccountControl::EnableUacAndRestartWindows()
   161 	{
   162 		EnableUac();
   163 		RestartWindows();
   164 	}
   165 
   166 	bool UserAccountControl::IsCurrentProcessElevated::get()
   167 	{
   168 		return GetProcessTokenElevationType() == TokenElevationTypeFull;	//elevated
   169 	}
   170 
   171 	bool UserAccountControl::IsCurrentProcessVirtualized::get()
   172 	{
   173 		HANDLE hToken;
   174         try
   175         {
   176             if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
   177 				throw gcnew Win32Exception(GetLastError());
   178 
   179             DWORD virtualizationEnabled;
   180 			DWORD dwSize;
   181 			if (!GetTokenInformation(hToken, TokenVirtualizationEnabled, &virtualizationEnabled, sizeof(virtualizationEnabled), &dwSize))
   182                 throw gcnew Win32Exception(GetLastError());
   183 
   184 			return virtualizationEnabled != 0;
   185         }
   186         finally
   187         {
   188             CloseHandle(hToken);
   189         }
   190 	}
   191 
   192 	int UserAccountControl::GetProcessTokenElevationType()
   193 	{
   194 		HANDLE hToken;
   195         try
   196         {
   197             if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
   198 				throw gcnew Win32Exception(GetLastError());
   199 
   200             TOKEN_ELEVATION_TYPE elevationType;
   201 			DWORD dwSize;
   202             if (!GetTokenInformation(hToken, TokenElevationType, &elevationType, sizeof(elevationType), &dwSize))
   203                 throw gcnew Win32Exception(GetLastError());
   204 
   205 			return elevationType;
   206         }
   207         finally
   208         {
   209             CloseHandle(hToken);
   210         }
   211 	}
   212 
   213 	void UserAccountControl::SetUacRegistryValue(bool enabled)
   214 	{
   215 		RegistryKey^ key = Registry::LocalMachine->OpenSubKey(UacRegistryKey, true);
   216 		key->SetValue(UacRegistryValue, enabled ? 1 : 0);
   217 	}
   218 
   219 	void UserAccountControl::RestartWindows()
   220 	{
   221 		InitiateSystemShutdownEx(NULL, NULL, 0/*Timeout*/,
   222 								 TRUE/*ForceAppsClosed*/, TRUE/*RebootAfterShutdown*/,
   223 								 SHTDN_REASON_MAJOR_OPERATINGSYSTEM | SHTDN_REASON_MINOR_RECONFIG | SHTDN_REASON_FLAG_PLANNED);
   224 		//This shutdown flag corresponds to: "Operating System: Reconfiguration (Planned)".
   225 	}
   226 }