【发布时间】:2018-04-21 18:10:45
【问题描述】:
我想在 C++ 中创建一个 Windows 服务,以便在用户每次登录时以管理员身份启动我的程序而不弹出 UAC 窗口 因为这是我第一次这样做,所以我从这里使用了这个项目:https://code.msdn.microsoft.com/windowsapps/CppWindowsService-cacf4948/view/SourceCode
我将 CppWindowsService.cpp 中的第 74 行编辑为:
InstallService(
SERVICE_NAME, // Name of service
SERVICE_DISPLAY_NAME, // Name to display
SERVICE_AUTO_START, // Service start type
SERVICE_DEPENDENCIES, // Dependencies
0, // Service running account
SERVICE_PASSWORD // Password of the account
);
并在 SampleService.cpp 第 101 行的工作线程中添加了一些代码,变成这样:
void CSampleService::ServiceWorkerThread(void)
{
// Periodically check if the service is stopping.
PSID gpSidMIL_High;
ConvertStringSidToSidW(L"S-1-16-12288", &gpSidMIL_High);
DWORD userSessionID = WTSGetActiveConsoleSessionId();
HANDLE hToken, hToken2;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken)) WriteEventLogEntry(L"OpenProcessToken failed error", EVENTLOG_ERROR_TYPE);
if (!DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hToken2)) WriteEventLogEntry(L"DuplicateTokenEx error", EVENTLOG_ERROR_TYPE);
if (!SetTokenInformation(hToken2, TokenSessionId, &userSessionID, sizeof(userSessionID))) WriteEventLogEntry(L"SetTokenInformation 1 error", EVENTLOG_ERROR_TYPE);
DWORD dwUIAccess = 1;
if (!SetTokenInformation(hToken2, TokenUIAccess, &dwUIAccess, sizeof(dwUIAccess))) WriteEventLogEntry(L"SetTokenInformation 2 error", EVENTLOG_ERROR_TYPE);
//Set "high" mandatory integrity level
TOKEN_MANDATORY_LABEL tml = { 0 };
tml.Label.Attributes = SE_GROUP_INTEGRITY;
tml.Label.Sid = gpSidMIL_High;
if (!SetTokenInformation(hToken2, TokenIntegrityLevel, &tml, sizeof(TOKEN_MANDATORY_LABEL) + ::GetSidLengthRequired(1))) WriteEventLogEntry(L"SetTokenInformation 3 error", EVENTLOG_ERROR_TYPE);
LPVOID pEnv = 0;
if (!CreateEnvironmentBlock(&pEnv, hToken2, FALSE)) WriteEventLogEntry(L"CreateEnvironmentBlock error", EVENTLOG_ERROR_TYPE);
if (!ImpersonateLoggedOnUser(hToken2)) WriteEventLogEntry(L"ImpersonateLoggedOnUser error", EVENTLOG_ERROR_TYPE);
while (!m_fStopping)
{
STARTUPINFO stinfo = { 0 };
PROCESS_INFORMATION pinfo = { 0 };
stinfo.cb = sizeof(stinfo);
stinfo.lpDesktop = L"winsta0\\default";
if (!CreateProcessAsUserW(hToken2, L"path to exe that shows a message box", 0, 0, 0, FALSE, CREATE_UNICODE_ENVIRONMENT|CREATE_BREAKAWAY_FROM_JOB, pEnv, L"cwd of the exe file", &stinfo, &pinfo))
{
// after debugging I found that the error is coming from here
std::wstring error = L"CreateProcessAsUserW failed with error : ";
error += std::to_wstring(GetLastError());
WriteEventLogEntry(wcsdup(error.c_str()), EVENTLOG_ERROR_TYPE);
Sleep(10000);
}
while (!m_fStopping && pinfo.hProcess)
{
if(WaitForSingleObject(pinfo.hProcess, 1000) != WAIT_TIMEOUT) break;
}
// ::Sleep(2000); // Simulate some lengthy operations.
}
问题是这个服务在重新启动 Windows 或通过 sc.exe 或服务控制管理器手动启动后运行良好,但在从之前的关机启动后就不行了 当我关闭然后启动计算机时,我可以在任务管理器中看到该服务的 exe,所以我知道该服务正在运行并且有一个错误来自函数,我使用了 windows 事件并记录了错误,我终于找到了该错误来自 CreateProcessAsUser,它返回错误 5(拒绝访问) 我不知道问题出在哪里,因为服务在重新启动或手动启动后运行良好
【问题讨论】:
标签: c++ windows winapi service