总所周知,大多数Windows服务是以SYSTEM用户启动的,并且没有任何交互界面的。SYSTEM用户是系统中权限最高的用户,所以服务程序有极高的权限,可以操作注册表,系统目录等等。
但是有写东西不一定权限高就能取到,比如说想知道当前登录用户的一些相关信息,必须是当前用户启动的程序才可能得到这些信息,用SYSTEM用户启动的服务反而得不到这些信息,于是就有了需要在Windows服务中以当前用户启动一个进程的需求。
以下代码可以实现用当前用户启动一个程序,在Win7 64位机器上测试通过。
- //获取当前活动的SessionId
- DWORD dwSessionId = WTSGetActiveConsoleSessionId();
- HANDLE hToken = NULL;
- HANDLE hTokenDup = NULL;
- LPVOID pEnv = NULL;
- STARTUPINFO si;
- PROCESS_INFORMATION pi;
-
-
- //获取用户Token
- if(!WTSQueryUserToken(dwSessionId, &hToken))
- {
- CloseHandle(hToken);
- return;
- }
-
-
- //复制Token
- if(!DuplicateTokenEx(hToken,MAXIMUM_ALLOWED,NULL,SecurityIdentification,TokenPrimary,&hTokenDup))
- {
- CloseHandle(hToken);
- return;
- }
-
-
- //获取环境信息
- if(!CreateEnvironmentBlock(&pEnv,hTokenDup,FALSE))
- {
- CloseHandle(hToken);
- CloseHandle(hTokenDup);
- return;
- }
-
-
- //设置启动参数信息
- ZeroMemory( &si, sizeof( STARTUPINFO ) );
- si.cb = sizeof( STARTUPINFO );
- si.lpDesktop = "winsta0\\default";
- ZeroMemory( &pi, sizeof(pi) );
- DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS|CREATE_UNICODE_ENVIRONMENT|CREATE_NEW_CONSOLE;
-
- //以当前用户启动记事本
- if(!CreateProcessAsUser(hTokenDup,"notepad.exe",NULL,NULL,NULL,FALSE,dwCreationFlag,pEnv,NULL,&si,&pi))
- {
- DestroyEnvironmentBlock(pEnv);
- CloseHandle(hTokenDup);
- CloseHandle(hToken);
- fOut.close();
- }
- //等待启动的进程结束
- WaitForSingleObject(pi.hProcess, INFINITE);
-
- //清理工作
- DestroyEnvironmentBlock(pEnv);
- CloseHandle(hTokenDup);
- CloseHandle(hToken);
-