以服务权限,即SYSTEM帐户启动的程序是无法取得用户的profile的,比如startup文件夹的路径。 首先,Shell函数是不行的:
SHGetSpecialFolderPath取得的是C:\Windows\system32\config\systemprofile\ 其次,环境变量也得不到。 GetEnvironmentVariable返回203( ERROR_ENVVAR_NOT_FOUND)
注:从服务应用程序可以拿到全局的环境变量,诸如ALLUSERS等等,但是各个用户的就搞不定了。 虽说从服务来访问用户的profile是一种非常不好的设计,但是如果有一些特殊需求的话,, 可以使用下面的方法。
BOOL
bRes
=
FALSE;
char lpPath [ MAX_PATH ]; DWORD RetVal = 0; DWORD ErrCode = 0; DWORD ConsoleSessionId = 0; // 函数的句柄 HMODULE hInstKernel32 = NULL; HMODULE hInstWtsapi32 = NULL; // Token的句柄 HANDLE hTokenUser = NULL; HANDLE hTokenThisProcess = NULL; HANDLE hTokenThis = NULL; // WTSGetActiveConsoleSessionId 函数,得到当前登录用户的会话ID // 这里的代码用的是VC6,新版的SDK已经包括此函数,无需LoadLibrary了。 typedef DWORD ( WINAPI * WTSGetActiveConsoleSessionIdPROC)(); WTSGetActiveConsoleSessionIdPROC WTSGetActiveConsoleSessionId = NULL; hInstKernel32 = LoadLibrary( "Kernel32.dll"); if ( ! hInstKernel32) { return FALSE; } WTSGetActiveConsoleSessionId = ( WTSGetActiveConsoleSessionIdPROC) GetProcAddress( hInstKernel32 , "WTSGetActiveConsoleSessionId"); if ( ! WTSGetActiveConsoleSessionId) { return FALSE; } // WTSQueryUserToken 函数,通过会话ID得到令牌 typedef BOOL ( WINAPI * WTSQueryUserTokenPROC)( ULONG SessionId , PHANDLE phToken ); WTSQueryUserTokenPROC WTSQueryUserToken = NULL; hInstWtsapi32 = LoadLibrary( "Wtsapi32.dll"); if ( ! hInstWtsapi32) { return FALSE; } WTSQueryUserToken = ( WTSQueryUserTokenPROC) GetProcAddress( hInstWtsapi32 , "WTSQueryUserToken"); if ( ! WTSQueryUserToken) { return FALSE; } // 得到当前激活用户的会话ID ConsoleSessionId = WTSGetActiveConsoleSessionId(); // 得到当前登录用户的令牌 bRes = WTSQueryUserToken( ConsoleSessionId , & hTokenUser); if ( ! bRes) { return FALSE; } // 模仿成当前登录用户 bRes = ImpersonateLoggedOnUser( hTokenUser); if ( ! bRes) { return FALSE; } // 取得当前用户的Startup文件夹路径 bRes = SHGetSpecialFolderPath( NULL , lpPath , CSIDL_STARTUP , TRUE); if ( ! bRes) { return FALSE; } else { MessageBox( NULL , lpPath , "Startup" , MB_OK); } // 终止模拟,返回 RevertToSelf();
在其它session中(如远程桌面的session)弹出窗口
弹出窗口,可以按照下述方法来实现,注:执行这段代码的进程就是你的服务进程,当前运行在session0中。还有一个前提,在本地登录时已经能弹出窗口。
HANDLE hThisProcess = GetCurrentProcess(); // 获取当前进程句柄
// 打开当前进程令牌
HANDLE hTokenThis = NULL;
OpenProcessToken(hThisProcess, TOKEN_ALL_ACCESS, &hTokenThis);
// 复制一个进程令牌,目的是为了修改session id属性,以便在其它session中创建进程
HANDLE hTokenDup = NULL;
DuplicateTokenEx(hTokenThis, MAXIMUM_ALLOWED,NULL, SecurityIdentification, TokenPrimary, &hTokenDup);
DWORD dwSessionId = WTSGetActiveConsoleSessionId(); // 获取活动session id,这里要注意,如果服务器还没有被登录而使用了远程桌面,这样用是可以的,如果有多个session存在,不能简单使用此函数,需要枚举所有session并确定你需要的一个,或者干脆使用循环,针对每个session都执行后面的代码
SetTokenInformation(hTokenDup, TokenSessionId, &dwSessionId, sizeof(DWORD)); // 把session id设置到备份的令牌中
// 好了,现在要用新的令牌来创建一个服务进程。注意:是“服务”进程!如果需要以用户身份运行,必须在前面执行LogonUser来获取用户令牌
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(STARTUPINFO));
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = "WinSta0\\Default";
LPVOID pEnv = NULL;
DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE; // 注意标志
CreateEnvironmentBlock(&pEnv, hTokenDup, FALSE); // 创建环境块
// 创建新的进程,这个进程就是你要弹出窗口的进程,它将工作在新的session中
CreateProcessAsUser(hTokenDup, NULL, _T("D:\\GetUserName.exe"), NULL, NULL, FALSE, dwCreationFlag, pEnv, NULL, &si, &pi);
|
服务应用程序如何访问当前登录用户的信息
最新推荐文章于 2024-08-30 08:53:59 发布