windows Service启动具有管理员权限的GUI进程

2 篇文章 0 订阅

一、前言
自从Windows Vista后,Windows Service就不支持启动GUI application。网上很多资料介绍的方法可以启动GUI进程,但是有些不具有管理员权限,有些启动用户属于system用户,不是当前登录用户,只能通过如下方法。
二、代码
1、获取到受限的token

/* UAC开启时,当前用户拥有两个token,分别是受限的token和不受限的token。可以用下面代码获取到受限的token*/
	HANDLE GetCurrentUserToken()
	{
		PWTS_SESSION_INFO pSessionInfo = 0;
		DWORD dwCount = 0;
		::WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSessionInfo, &dwCount);
		int session_id = 0;
		for (DWORD i = 0; i < dwCount; ++i)
		{
			WTS_SESSION_INFO si = pSessionInfo[i];
			if (WTSActive == si.State)
			{
				session_id = si.SessionId;
				break;
			}
		}

		::WTSFreeMemory(pSessionInfo);

		HANDLE current_token = 0;
		BOOL bRet = ::WTSQueryUserToken(session_id, &current_token);
		if (bRet == FALSE)
		{
			qCritical() << "WTSQueryUserToken failed";
			return 0;
		}

		// 创建一个新的访问令牌来复制一个已经存在的标记
		HANDLE primaryToken = 0;
		bRet = ::DuplicateTokenEx(current_token, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, 0, SecurityImpersonation, TokenPrimary, &primaryToken);
		if (bRet == FALSE)
		{
			qCritical() << "DuplicateTokenEx failed";
			return 0;
		}

		::CloseHandle(current_token);

		return primaryToken;
	}

2、创建出具有管理员权限的GUI进程

// 创建出具有管理员权限,并且属于当前用户的界面程序
	BOOL launchGUIApplication(std::wstring app, std::vector<std::wstring> params)
	{
		BOOL bResult = FALSE;
		// 由受限的primaryToken和GetTokenInformation得到不受限的hTheToken
		HANDLE primaryToken = GetCurrentUserToken();
		if (primaryToken == 0)
		{
			qCritical() << "GetCurrentUserToken failed";
			return FALSE;
		}

		HANDLE hTheToken = NULL;
		DWORD dwSize = 0;
 		if ( GetTokenInformation(primaryToken, TokenLinkedToken, (VOID*)&hTheToken, sizeof(HANDLE), &dwSize))
		{
			// 让当前线程模拟登陆用户进行操作
			if (ImpersonateLoggedOnUser(hTheToken) == TRUE)
			{
				DWORD dwCreationFlags = HIGH_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
				STARTUPINFO si = { sizeof(si) };
				PROCESS_INFORMATION pi;
				SECURITY_ATTRIBUTES Security1 = { sizeof(Security1) };
				SECURITY_ATTRIBUTES Security2 = { sizeof(Security2) };

				LPVOID pEnv = NULL;
				if (CreateEnvironmentBlock(&pEnv, hTheToken, TRUE))
				{
					dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
				}

				TCHAR path[MAX_PATH];
				_tcscpy_s(path, MAX_PATH, app.c_str());
				TCHAR commandLine[MAX_PATH];
				_tcscpy_s(commandLine, MAX_PATH, L" ");
				for (auto item : params) {
					_tcscat_s(commandLine, MAX_PATH, item.c_str());
				}

				// Launch the process in the client's logon session.
				bResult = CreateProcessAsUser(
					hTheToken,
					(LPWSTR)(path),
					(LPWSTR)(commandLine),
					&Security1,
					&Security2,
					FALSE,
					dwCreationFlags,
					pEnv,
					NULL,
					&si,
					&pi
				);

				if (!bResult)
				{
					qCritical() << "CreateProcessAsUser failed";
				}

				RevertToSelf();

				if (pEnv)
				{
					DestroyEnvironmentBlock(pEnv);
				}
			}
			else
			{
				qCritical() << "ImpersonateLoggedOnUser failed";
			}
			CloseHandle(hTheToken);
		}
		CloseHandle(primaryToken);

		return bResult;
	}

3、调用方法

		std::string  strAppName = "C:\\Windows\\System32\\calc.exe";
		std::wstring strAppPath = to_wchar_t(strAppName); 
		std::vector<std::wstring> params = {};
		bool bResult = launchGUIApplication(strAppPath, params);
		if (bResult == FALSE) {
			qCritical() << "Failed to launch AppPath =" << strAppPath.c_str();
		}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值