如何在Windows服务中以当前用户启动一个程序


总所周知,大多数Windows服务是以SYSTEM用户启动的,并且没有任何交互界面的。SYSTEM用户是系统中权限最高的用户,所以服务程序有极高的权限,可以操作注册表,系统目录等等。

但是有写东西不一定权限高就能取到,比如说想知道当前登录用户的一些相关信息,必须是当前用户启动的程序才可能得到这些信息,用SYSTEM用户启动的服务反而得不到这些信息,于是就有了需要在Windows服务中以当前用户启动一个进程的需求。

以下代码可以实现用当前用户启动一个程序,在Win7 64位机器上测试通过。


  1. //获取当前活动的SessionId
  2. DWORD dwSessionId = WTSGetActiveConsoleSessionId();
  3. HANDLE hToken = NULL;
  4. HANDLE hTokenDup = NULL;
  5. LPVOID pEnv = NULL;
  6. STARTUPINFO si;
  7. PROCESS_INFORMATION pi;
  8. //获取用户Token
  9. if(!WTSQueryUserToken(dwSessionId, &hToken))
  10. {
  11. CloseHandle(hToken);
  12. return;
  13. }
  14. //复制Token
  15. if(!DuplicateTokenEx(hToken,MAXIMUM_ALLOWED,NULL,SecurityIdentification,TokenPrimary,&hTokenDup))
  16. {
  17. CloseHandle(hToken);
  18. return;
  19. }
  20. //获取环境信息
  21. if(!CreateEnvironmentBlock(&pEnv,hTokenDup,FALSE))
  22. {
  23. CloseHandle(hToken);
  24. CloseHandle(hTokenDup);
  25. return;
  26. }
  27. //设置启动参数信息
  28. ZeroMemory( &si, sizeof( STARTUPINFO ) );
  29. si.cb = sizeof( STARTUPINFO );
  30. si.lpDesktop = "winsta0\\default";
  31. ZeroMemory( &pi, sizeof(pi) );
  32. DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS|CREATE_UNICODE_ENVIRONMENT|CREATE_NEW_CONSOLE;
  33. //以当前用户启动记事本
  34. if(!CreateProcessAsUser(hTokenDup,"notepad.exe",NULL,NULL,NULL,FALSE,dwCreationFlag,pEnv,NULL,&si,&pi))
  35. {
  36. DestroyEnvironmentBlock(pEnv);
  37. CloseHandle(hTokenDup);
  38. CloseHandle(hToken);
  39. fOut.close();
  40. }
  41. //等待启动的进程结束
  42. WaitForSingleObject(pi.hProcess, INFINITE);
  43. //清理工作
  44. DestroyEnvironmentBlock(pEnv);
  45. CloseHandle(hTokenDup);
  46. CloseHandle(hToken);