从Vista上的服务使用CreateProcessAsUser的桌面问题

我正在使用VC ++来使用CreateProcessAsUser从Vista上的服务创build一个进程。 当我通过本地机器上的login执行此代码时,进程创build成功。 当我使用远程桌面(mstsc)从另一台机器login到我的机器并启动我的应用程序时,相同的代码失败。

我可以理解,当我进行远程login时,活动桌面被视为远程桌面。 有人可以帮助我如何获得当前login用户桌面的桌面名称,而不是远程桌面的桌面名称。

这是我的代码

ACTIVECONSOLESESSIONIDFUNC lpfnProc; // WTSGetActiveConsoleSessionId function pointer HMODULE hModule = NULL; // Instance for kernel32.dll library DWORD dwSessionId = 0; // Session ID HANDLE hToken = NULL; // Active session token HANDLE hDupToken = NULL; // Duplicate session token WCHAR szErr[1024] = {0}; LPVOID lpEnvironment = NULL; // Environtment block // Get the active session ID hModule = LoadLibrary(KERNEL32LIB); if(!hModule) { //wsprintf(szErr, L"LoadLibrary Error: %d", GetLastError()); return; } lpfnProc = (ACTIVECONSOLESESSIONIDFUNC)GetProcAddress(hModule,"WTSGetActiveConsoleSessionId"); dwSessionId = lpfnProc(); // Get token of the logged in user by the active session ID BOOL bRet = WTSQueryUserToken(dwSessionId, &hToken); if (!bRet) { //wsprintf(szErr, L"WTSQueryUserToken Error: %d", GetLastError()); return; } // Get duplicate token from the active logged in user's token bRet = DuplicateTokenEx(hToken, // Active session token MAXIMUM_ALLOWED, // Desired access NULL, // Token attributes SecurityIdentification, // Impersonation level TokenPrimary, // Token type &hDupToken); // New/Duplicate token if (!bRet) { //wsprintf(szErr, L"DuplicateTokenEx Error: %d", GetLastError()); return; } // Get all necessary environment variables of logged in user // to pass them to the process bRet = CreateEnvironmentBlock(&lpEnvironment, // Environment block hDupToken, // New token FALSE); // Inheritence if(!bRet) { //wsprintf(szErr, L"CreateEnvironmentBlock Error: %d", GetLastError()); return; } HDESK hdeskInput=OpenInputDesktop(0, FALSE, 0); // does not set GetLastError(), so GetLastError() is arbitrary if NULL is returned if( hdeskInput==NULL ) { TRACE( "hdeskInput==NULL" ); return false; } // Initialize Startup and Process info startupInfo->cb = sizeof(STARTUPINFO); startupInfo->lpDesktop = TEXT("winsta0\\default"); // Start the process on behalf of the current user BOOL returnCode = CreateProcessAsUser(hDupToken, applicationName, commandLine, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT, lpEnvironment, NULL, startupInfo, &processInformation); 

谢谢,F

Solutions Collecting From Web of "从Vista上的服务使用CreateProcessAsUser的桌面问题"

这里是完整的工作代码来做你想做的事情

 //Function to run a process as active user from windows service void ImpersonateActiveUserAndRun(WCHAR* path, WCHAR* args) { DWORD session_id = -1; DWORD session_count = 0; WTS_SESSION_INFOA *pSession = NULL; if (WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSession, &session_count)) { //log success } else { //log error return; } for (int i = 0; i < session_count; i++) { session_id = pSession[i].SessionId; WTS_CONNECTSTATE_CLASS wts_connect_state = WTSDisconnected; WTS_CONNECTSTATE_CLASS* ptr_wts_connect_state = NULL; DWORD bytes_returned = 0; if (::WTSQuerySessionInformation( WTS_CURRENT_SERVER_HANDLE, session_id, WTSConnectState, reinterpret_cast<LPTSTR*>(&ptr_wts_connect_state), &bytes_returned)) { wts_connect_state = *ptr_wts_connect_state; ::WTSFreeMemory(ptr_wts_connect_state); if (wts_connect_state != WTSActive) continue; } else { //log error continue; } HANDLE hImpersonationToken; if (!WTSQueryUserToken(session_id, &hImpersonationToken)) { //log error continue; } //Get real token from impersonation token DWORD neededSize1 = 0; HANDLE *realToken = new HANDLE; if (GetTokenInformation(hImpersonationToken, (::TOKEN_INFORMATION_CLASS) TokenLinkedToken, realToken, sizeof(HANDLE), &neededSize1)) { CloseHandle(hImpersonationToken); hImpersonationToken = *realToken; } else { //log error continue; } HANDLE hUserToken; if (!DuplicateTokenEx(hImpersonationToken, //0, //MAXIMUM_ALLOWED, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS | MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &hUserToken)) { //log error continue; } // Get user name of this process //LPTSTR pUserName = NULL; WCHAR* pUserName; DWORD user_name_len = 0; if (WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, session_id, WTSUserName, &pUserName, &user_name_len)) { //log username contained in pUserName WCHAR string } //Free memory if (pUserName) WTSFreeMemory(pUserName); ImpersonateLoggedOnUser(hUserToken); STARTUPINFOW StartupInfo; GetStartupInfoW(&StartupInfo); StartupInfo.cb = sizeof(STARTUPINFOW); //StartupInfo.lpDesktop = "winsta0\\default"; PROCESS_INFORMATION processInfo; SECURITY_ATTRIBUTES Security1; Security1.nLength = sizeof SECURITY_ATTRIBUTES; SECURITY_ATTRIBUTES Security2; Security2.nLength = sizeof SECURITY_ATTRIBUTES; void* lpEnvironment = NULL; // Get all necessary environment variables of logged in user // to pass them to the new process BOOL resultEnv = CreateEnvironmentBlock(&lpEnvironment, hUserToken, FALSE); if (!resultEnv) { //log error continue; } WCHAR PP[1024]; //path and parameters ZeroMemory(PP, 1024 * sizeof WCHAR); wcscpy(PP, path); wcscat(PP, L" "); wcscat(PP, args); // Start the process on behalf of the current user BOOL result = CreateProcessAsUserW(hUserToken, NULL, PP, //&Security1, //&Security2, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE, //lpEnvironment, NULL, //"C:\\ProgramData\\some_dir", NULL, &StartupInfo, &processInfo); if (!result) { //log error } else { //log success } DestroyEnvironmentBlock(lpEnvironment); CloseHandle(hImpersonationToken); CloseHandle(hUserToken); CloseHandle(realToken); RevertToSelf(); } WTSFreeMemory(pSession); } 

什么是启动服务来创建一个新的过程,因为这涉及到一个合适的答案是什么? WTSGetActiveConsoleSessionId获取当前物理控制台会话的会话ID,而不是您的意义上的“活动”会话ID。 有了终端服务,可能会有许多不同的用户连接到不同的会话,所以你不能只挑一个,希望,但实际上可能有或没有实际登录的用户。

一种方法是使用WTSEnumerateSessions列出所有活动的会话,并尝试找到你想要的,你可以使用类似WTSQuerySessionInformation的东西来获取该会话的用户名。

如果你的服务是响应你用户帐户的请求(而不是一些自动事件),那么如果你使用的是类似于RPC /命名管道/ DCOM等的东西,你总是可以模拟用户(假设安全设置允许非匿名/识别模拟)并将线程的令牌复制到主令牌中并使用该令牌。

大量的谷歌搜索后,我能找到解决我的问题。

这里是我找到解决方案的链接。 http://www.codeproject.com/KB/vista-security/interaction-in-vista.aspx

感谢每一个试图帮助我的人。