在服务中以当前用户身份启动一个程序

在CodeProject上看到一个Demo, 在服务中以当前用户身份启动一个程序.

跟帖的人指出了一些bug, 我整理了一下, 将跟帖人指出的bug在工程中修正.

他提供的类, 也有一个小bug, 没有被跟帖的人指出, 被我发现并修正.

这个Demo整理后, 被我用在项目中, 用起来效果还不错.

以当前登录用户的身份运行一个程序的好处: 

* 可以避免权限问题. e.g. 文件建立后, 当前用户打不开.

* 有些程序或部件运行, 是需要Windows窗口消息的, 不能直接在服务中运行.

工程下载点: src_bk_2015_0722_1601_prj_run_cur_user_prog_on_service.zip

编译环境: vs2010 vc++

备注 :  

 /// @todo ls 服务启动停止时, 检测服务是否已经在运行或停止的处理要加上, 提高效率.

/// 如果硬生生的启动停止服务时, 还要启动停止桌面上的程序, 在没有检测服务状态时, 要花费的时间多些.

效果图:

工程预览:

[cpp] view plaincopy
 
  1. // lsServiceForTest.cpp : Defines the entry point for the application.  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5. #include <process.h>  
  6. #include "lsServiceForTest.h"  
  7. #include "ProcessStarter.h"  
  8.   
  9. #define SERVICE_VER_W L"1, 0, 0, 1"  
  10. #define PROJECT_MODIFY_TIME L"2015-0722-1426"  
  11.   
  12. VOID WINAPI ServiceMain(DWORD dwArgc, LPWSTR *lpszArgv);  
  13. SERVICE_TABLE_ENTRYW lpServiceStartTable[] =   
  14. {  
  15.     {SERVICE_NAME_W, ServiceMain},  
  16.     {NULL, NULL}  
  17. };  
  18.   
  19. SERVICE_STATUS_HANDLE g_hServiceCtrlHandler = NULL;   
  20. SERVICE_STATUS g_ServiceStatus;  
  21. std::wstring g_strPathNameMe = L"";  
  22. std::wstring g_strCmdLine = L"";  
  23. ns_base::CThreadManager g_ThreadManager;  
  24.   
  25. VOID ServiceMainProc();  
  26. static UINT WINAPI ThreadProcWorker(void* pParam);  
  27. BOOL ThreadProcStart_Worker();  
  28. BOOL ThreadProcStop_Worker();  
  29.   
  30. BOOL GetObjProgInfo(DWORD dwSessionId, OUT std::wstring& strObjPathName, OUT std::wstring& strCmdLine);  
  31.   
  32. VOID ExecuteAsService();  
  33. VOID WINAPI ServiceHandler(DWORD fdwControl);  
  34.   
  35. int APIENTRY _tWinMain(HINSTANCE hInstance,  
  36.     HINSTANCE hPrevInstance,  
  37.     LPTSTR    lpCmdLine,  
  38.     int       nCmdShow)  
  39. {  
  40.     std::wstring strLogFilePathName = L"";  
  41.   
  42.     ns_base::GetFilePathName_Me(g_strPathNameMe);  
  43.     g_strCmdLine = (NULL != lpCmdLine) ? lpCmdLine : L"";  
  44.   
  45.     strLogFilePathName = ns_business::GetLogPathName_lsServiceForTest().c_str();  
  46.     SetLogFilePathName(strLogFilePathName.c_str());  
  47.   
  48.     ServiceMainProc();  
  49.     return 0;  
  50. }  
  51.   
  52. VOID ServiceMainProc()  
  53. {  
  54.     WriteLogEx(L">> ServiceMainProc() [%s][%s][%s]", SERVICE_NAME_W, SERVICE_VER_W, PROJECT_MODIFY_TIME);  
  55.   
  56.     if (ns_base::StringCompare_equ(g_strCmdLine.c_str(), L"-i")  
  57.         || ns_base::StringCompare_equ(g_strCmdLine.c_str(), L"-I"))  
  58.     {  
  59.         ns_base::ServiceInstall(g_strPathNameMe.c_str(), SERVICE_NAME_W);  
  60.     }  
  61.     else if (ns_base::StringCompare_equ(g_strCmdLine.c_str(), L"-s")  
  62.         || ns_base::StringCompare_equ(g_strCmdLine.c_str(), L"-S"))  
  63.     {  
  64.         ns_base::ServiceStart(SERVICE_NAME_W);  
  65.     }  
  66.     else if (ns_base::StringCompare_equ(g_strCmdLine.c_str(), L"-k")  
  67.         || ns_base::StringCompare_equ(g_strCmdLine.c_str(), L"-K"))  
  68.     {  
  69.         ns_base::ServiceStop(SERVICE_NAME_W);  
  70.     }  
  71.     else if (ns_base::StringCompare_equ(g_strCmdLine.c_str(), L"-u")  
  72.         || ns_base::StringCompare_equ(g_strCmdLine.c_str(), L"-U"))  
  73.     {  
  74.         ns_base::ServiceUnInstall(SERVICE_NAME_W);  
  75.     }  
  76.     else  
  77.         ExecuteAsService();  
  78.   
  79.     WriteLogEx(L"<< ServiceMainProc() [%s][%s][%s]", SERVICE_NAME_W, SERVICE_VER_W, PROJECT_MODIFY_TIME);  
  80. }  
  81.   
  82. VOID ExecuteAsService()  
  83. {  
  84.     WriteLogEx(L">> ExecuteAsService");  
  85.   
  86.     if(!ThreadProcStart_Worker())  
  87.     {  
  88.         WriteLogEx(L"ThreadProcStart_Worker failed[%d]", GetLastError());  
  89.     }  
  90.   
  91.     if(!StartServiceCtrlDispatcherW(lpServiceStartTable))  
  92.     {  
  93.         WriteLogEx(L"StartServiceCtrlDispatcher failed[%d]", GetLastError());  
  94.     }  
  95.   
  96.     WriteLogEx(L"<< ExecuteAsService");  
  97. }  
  98.   
  99. VOID WINAPI ServiceMain(DWORD dwArgc, LPWSTR* lpszArgv)  
  100. {  
  101.     WriteLogEx(L">> ServiceMain(%d, lpszArgv)", dwArgc);  
  102.     do   
  103.     {  
  104.         g_ServiceStatus.dwServiceType = SERVICE_WIN32;   
  105.         g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;   
  106.         g_ServiceStatus.dwControlsAccepted =   
  107.             SERVICE_ACCEPT_STOP  
  108.             | SERVICE_ACCEPT_PAUSE_CONTINUE  
  109.             | SERVICE_ACCEPT_SHUTDOWN  
  110.             | SERVICE_ACCEPT_PARAMCHANGE  
  111.             | SERVICE_ACCEPT_NETBINDCHANGE  
  112.             | SERVICE_ACCEPT_HARDWAREPROFILECHANGE  
  113.             | SERVICE_ACCEPT_POWEREVENT  
  114.             | SERVICE_ACCEPT_SESSIONCHANGE  
  115.             | SERVICE_ACCEPT_PRESHUTDOWN  
  116.             | SERVICE_ACCEPT_TIMECHANGE  
  117.             | SERVICE_ACCEPT_TRIGGEREVENT;  
  118.   
  119.         g_ServiceStatus.dwWin32ExitCode = 0;   
  120.         g_ServiceStatus.dwServiceSpecificExitCode = 0;  
  121.         g_ServiceStatus.dwCheckPoint = 0;   
  122.         g_ServiceStatus.dwWaitHint = 0;   
  123.   
  124.         g_hServiceCtrlHandler = RegisterServiceCtrlHandlerW(SERVICE_NAME_W, ServiceHandler);   
  125.         if (NULL == g_hServiceCtrlHandler)   
  126.         {  
  127.             ns_base::NotifyFailed_RegisterServiceCtrlHandler(GetLastError(), SERVICE_NAME_W);  
  128.             break;  
  129.         }   
  130.   
  131.         // Initialization complete - report running status   
  132.         g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;   
  133.         g_ServiceStatus.dwCheckPoint = 0;   
  134.         g_ServiceStatus.dwWaitHint = 0;    
  135.         if (!SetServiceStatus(g_hServiceCtrlHandler, &g_ServiceStatus))   
  136.         {   
  137.             ns_base::NotifyFailed_SetServiceStatus(GetLastError(), SERVICE_NAME_W);  
  138.         }   
  139.     } while (0);  
  140.   
  141.     WriteLogEx(L"<< ServiceMain(%d, lpszArgv)", dwArgc);  
  142. }  
  143.   
  144. VOID WINAPI ServiceHandler(DWORD fdwControl)  
  145. {  
  146.     int iIndex = 0;  
  147.   
  148.     WriteLogEx(L">> ServiceHandler(%d)", fdwControl);  
  149.     switch(fdwControl)   
  150.     {  
  151.     case SERVICE_CONTROL_STOP:  
  152.     case SERVICE_CONTROL_SHUTDOWN:  
  153.         g_ThreadManager.StopThread(TRUE, L"g_ThreadManager");  
  154.         g_ServiceStatus.dwWin32ExitCode = 0;   
  155.         g_ServiceStatus.dwCurrentState  = SERVICE_STOPPED;   
  156.         g_ServiceStatus.dwCheckPoint    = 0;   
  157.         g_ServiceStatus.dwWaitHint      = 0;  
  158.   
  159.         // terminate all processes started by this service before shutdown  
  160.         ns_business::StopAndKill_dlgNotify();  
  161.         break;   
  162.     case SERVICE_CONTROL_PAUSE:  
  163.         g_ServiceStatus.dwCurrentState = SERVICE_PAUSED;   
  164.         break;  
  165.     case SERVICE_CONTROL_CONTINUE:  
  166.         g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;   
  167.         break;  
  168.     default:  
  169.         WriteLogEx(L"Unrecognized opcode %d ", fdwControl);  
  170.     };  
  171.   
  172.     if (!SetServiceStatus(g_hServiceCtrlHandler,  &g_ServiceStatus))   
  173.     {   
  174.         ns_base::NotifyFailed_SetServiceStatus(GetLastError(), SERVICE_NAME_W);  
  175.     }  
  176.   
  177.     WriteLogEx(L"<< ServiceHandler(%d)", fdwControl);  
  178. }  
  179.   
  180. static UINT WINAPI ThreadProcWorker(void* pParam)  
  181. {  
  182.     BOOL bLog = TRUE;  
  183.     DWORD dwSessionIdPrev = -1;  
  184.     DWORD dwSessionId = -1;  
  185.     size_t nSleepTotal = 0;  
  186.     UINT uRc = S_FALSE;  
  187.   
  188.     std::wstring strObjPathName = L"";  
  189.     std::wstring strCmdLine = L"";  
  190.   
  191.     ns_base::TAG_THREAD_MANAGER_PARAM ThreadManagerParam;  
  192.     ns_base::TAG_THREAD_MANAGER_PARAM* pThreadManagerParam = NULL;  
  193.     CProcessStarter ProcessStarter;  
  194.   
  195.     WriteLogEx(L">> lsServiceForTest ThreadProcWorker");  
  196.     do   
  197.     {  
  198.         if (NULL == pParam)  
  199.             break;  
  200.   
  201.         pThreadManagerParam = (ns_base::TAG_THREAD_MANAGER_PARAM*)pParam;  
  202.         ThreadManagerParam.copy((ns_base::TAG_THREAD_MANAGER_PARAM*)pParam);  
  203.         SAFE_DELETE(pThreadManagerParam);  
  204.         if (NULL == ThreadManagerParam.pThreadManager)  
  205.             break;  
  206.   
  207.         while(!ThreadManagerParam.pThreadManager->IsNeedQuitThread())  
  208.         {  
  209.             if (!ns_base::SleepContinueEx(2000, 100, nSleepTotal))  
  210.                 continue;  
  211.   
  212.             /// 保证 只有在SessionId变化的时候, 才打印 FindActiveSessionId 的日志  
  213.             if (!ProcessStarter.FindActiveSessionId(dwSessionId, bLog)  
  214.                 || (dwSessionIdPrev == dwSessionId))  
  215.             {  
  216.                 if (bLog)  
  217.                     bLog = FALSE;  
  218.   
  219.                 continue;  
  220.             }  
  221.   
  222.             if (!bLog)  
  223.                 bLog = TRUE;  
  224.   
  225.             /// 用户每次切换一次桌面, 我们就启动一次子程序  
  226.             do   
  227.             {  
  228.                 dwSessionIdPrev = dwSessionId;  
  229.                 if (GetObjProgInfo(dwSessionId, strObjPathName, strCmdLine))  
  230.                 {  
  231.                     if (!ns_base::IsFileExist(strObjPathName.c_str()))  
  232.                     {  
  233.                         WriteLogEx(L"[error] !ns_base::IsFileExist(%s)", strObjPathName.c_str());  
  234.                         break;  
  235.                     }  
  236.   
  237.                     /// 确保在多个SessionId的环境下, 也只有当前SessionId上运行唯一一个dlgNotify  
  238.                     ns_business::StopAndKill_dlgNotify();  
  239.   
  240.                     ProcessStarter.Run(  
  241.                         strObjPathName.c_str(),  
  242.                         strCmdLine.c_str());  
  243.                 }  
  244.             } while (0);  
  245.   
  246.             continue;  
  247.         }  
  248.   
  249.         uRc = S_OK;  
  250.     } while (0);  
  251.     WriteLogEx(L"<< FzAppService ThreadProcWorker");  
  252.   
  253.     return uRc;  
  254. }  
  255.   
  256. BOOL ThreadProcStart_Worker()  
  257. {  
  258.     BOOL bRc = FALSE;  
  259.     ns_base::TAG_THREAD_MANAGER_PARAM* pThreadManagerParam = NULL;  
  260.   
  261.     if (!g_ThreadManager.IsNeedQuitThread()  
  262.         && !g_ThreadManager.IsThreadRunning())  
  263.     {  
  264.         do   
  265.         {  
  266.             pThreadManagerParam = new ns_base::TAG_THREAD_MANAGER_PARAM;  
  267.             if (NULL == pThreadManagerParam)  
  268.                 break;  
  269.   
  270.             pThreadManagerParam->pThreadManager = &g_ThreadManager;  
  271.             g_ThreadManager.SetThreadHandle(  
  272.                 (HANDLE)_beginthreadex(  
  273.                 NULL,   
  274.                 0,   
  275.                 &ThreadProcWorker,   
  276.                 (void*)pThreadManagerParam,   
  277.                 0,   
  278.                 NULL));  
  279.   
  280.             bRc = TRUE;  
  281.         } while (0);  
  282.     }  
  283.   
  284.     return bRc;  
  285. }  
  286.   
  287. BOOL ThreadProcStop_Worker()  
  288. {  
  289.     g_ThreadManager.StopThread(TRUE, L"g_ThreadManager");  
  290.     return TRUE;  
  291. }  
  292.   
  293. BOOL GetObjProgInfo(DWORD dwSessionId, OUT std::wstring& strObjPathName, OUT std::wstring& strCmdLine)  
  294. {  
  295.     ns_base::GetPathName_Me(strObjPathName);  
  296.     strObjPathName += FILE_NAME_ObjProgInfo;  
  297.   
  298.     strCmdLine = ns_base::StringFormatV(L"sessionId-%d", dwSessionId);  
  299.   
  300.     return TRUE;  
  301. }  


CProcessStarter 实现, 负责以当前用户身份启动一个程序.

[cpp] view plaincopy
 
  1. #ifndef _PROCESS_STARTER_H_  
  2. #define _PROCESS_STARTER_H_  
  3.   
  4. #include "stdafx.h"  
  5.   
  6. class CProcessStarter  
  7. {  
  8. public:  
  9.     CProcessStarter();  
  10.   
  11.     /// 如果没有找到"已经激活的SessionId", 说明还没有进入桌面  
  12.     BOOL FindActiveSessionId(OUT DWORD& dwSessionId, BOOL bNeedLog);  
  13.     BOOL Run(LPCWSTR pcProcessPathName, LPCWSTR pcCmdLine);  
  14.       
  15. private:  
  16.     HANDLE GetCurrentUserToken();  
  17.   
  18. private:  
  19.     std::wstring m_strProcessPathName;  
  20.     std::wstring m_strCmdLine;  
  21. };  
  22.   
  23. #endif //_PROCESS_STARTER_H_  
[cpp] view plaincopy
 
    1. #include "stdafx.h"  
    2. #include "ProcessStarter.h"  
    3.   
    4. #include <userenv.h>  
    5. #pragma comment(lib, "Userenv.lib")  
    6.   
    7. #include <wtsapi32.h>  
    8. #pragma comment(lib, "Wtsapi32.lib")  
    9.   
    10. CProcessStarter::CProcessStarter()  
    11.     : m_strProcessPathName(L""),   
    12.     m_strCmdLine(L"")  
    13. {  
    14. }  
    15.   
    16. BOOL CProcessStarter::FindActiveSessionId(OUT DWORD& dwSessionId, BOOL bNeedLog)  
    17. {  
    18.     BOOL bFindActiveSession = FALSE;  
    19.     DWORD dwIndex = 0;  
    20.   
    21.     PWTS_SESSION_INFO pWtsSessionInfo = NULL;  
    22.     DWORD dwCntWtsSessionInfo = 0;  
    23.   
    24.     if (bNeedLog)  
    25.         WriteLogEx(L">> CProcessStarter::FindActiveSessionId()");  
    26.     do   
    27.     {  
    28.         dwSessionId = (DWORD)(-1);  
    29.   
    30.         if ((!WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pWtsSessionInfo, &dwCntWtsSessionInfo))  
    31.             || (NULL == pWtsSessionInfo))  
    32.         {  
    33.             if (bNeedLog)  
    34.                 WriteLogEx(L"break 0 CProcessStarter::FindActiveSessionId()");  
    35.   
    36.             break;  
    37.         }  
    38.   
    39.         for (dwIndex = 0; dwIndex < dwCntWtsSessionInfo; dwIndex++)  
    40.         {  
    41.             if (WTSActive == pWtsSessionInfo[dwIndex].State)  
    42.             {  
    43.                 dwSessionId = pWtsSessionInfo[dwIndex].SessionId;  
    44.                 bFindActiveSession = TRUE;  
    45.                 break;  
    46.             }  
    47.         }  
    48.   
    49.         WTSFreeMemory(pWtsSessionInfo);  
    50.   
    51.         if (!bFindActiveSession)  
    52.         {  
    53.             if (bNeedLog)  
    54.                 WriteLogEx(L"break 1 CProcessStarter::FindActiveSessionId()");  
    55.   
    56.             break;  
    57.         }  
    58.     } while (0);  
    59.   
    60.     if (bNeedLog)  
    61.     {  
    62.         WriteLogEx(L"<< CProcessStarter::FindActiveSessionId(), bFindActiveSession = [%s], dwSessionId = %d",   
    63.             bFindActiveSession ? L"TRUE" : L"FALSE",   
    64.             dwSessionId);  
    65.     }  
    66.   
    67.     return bFindActiveSession;  
    68. }  
    69.   
    70. HANDLE CProcessStarter::GetCurrentUserToken()  
    71. {  
    72.     DWORD dwSessionId = 0;  
    73.     HANDLE hCurrentToken = NULL;  
    74.     HANDLE hPrimaryToken = NULL;  
    75.   
    76.     WriteLogEx(L">> CProcessStarter::GetCurrentUserToken()");  
    77.     do   
    78.     {  
    79.         if (!FindActiveSessionId(dwSessionId, TRUE))  
    80.         {  
    81.             WriteLogEx(L"break 0 CProcessStarter::GetCurrentUserToken()");  
    82.             break;  
    83.         }  
    84.   
    85.         if (!WTSQueryUserToken(dwSessionId, &hCurrentToken)  
    86.             || (NULL == hCurrentToken))  
    87.         {  
    88.             WriteLogEx(L"break 2 CProcessStarter::GetCurrentUserToken()");  
    89.             break;  
    90.         }  
    91.   
    92.         if (!DuplicateTokenEx(hCurrentToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, 0, SecurityImpersonation, TokenPrimary, &hPrimaryToken))  
    93.         {  
    94.             WriteLogEx(L"break 3 CProcessStarter::GetCurrentUserToken()");  
    95.             break;  
    96.         }  
    97.   
    98.     } while (0);  
    99.   
    100.     WriteLogEx(L"<< CProcessStarter::GetCurrentUserToken(), hCurrentToken = 0x%p, hPrimaryToken = 0x%p",   
    101.         hCurrentToken,  
    102.         hPrimaryToken);  
    103.   
    104.     SAFE_CLOSE_HANDLE(hCurrentToken);  
    105.     return hPrimaryToken;  
    106. }  
    107.   
    108. BOOL CProcessStarter::Run(LPCWSTR pcProcessPathName, LPCWSTR pcCmdLine)  
    109. {  
    110.     BOOL bRc = FALSE;  
    111.     BOOL bTmp = FALSE;  
    112.     HANDLE hPrimaryToken = NULL;  
    113.     STARTUPINFOA StartupInfo = {0};  
    114.     PROCESS_INFORMATION processInfo = {0};  
    115.     std::wstring command = L"";  
    116.     LPVOID lpEnvironment = NULL;  
    117.   
    118.     WriteLogEx(L">> CProcessStarter::Run");  
    119.   
    120.     do   
    121.     {  
    122.         if ((NULL == pcProcessPathName) || (!ns_base::IsFileExist(pcProcessPathName)))  
    123.         {  
    124.             WriteLogEx(L"break 0 CProcessStarter::Run");  
    125.             break;  
    126.         }  
    127.   
    128.         this->m_strProcessPathName = pcProcessPathName;  
    129.         this->m_strCmdLine = (NULL != pcCmdLine) ? pcCmdLine : L"";  
    130.   
    131.         hPrimaryToken = GetCurrentUserToken();  
    132.         if (NULL == hPrimaryToken)  
    133.         {  
    134.             WriteLogEx(L"break 1 CProcessStarter::Run");  
    135.             break;  
    136.         }  
    137.   
    138.         StartupInfo.cb = sizeof(STARTUPINFO);  
    139.         command = L""";  
    140.         command += m_strProcessPathName.c_str();  
    141.         command += L""";  
    142.         if (m_strCmdLine.length() != 0)  
    143.         {  
    144.             command += L" ";  
    145.             command += m_strCmdLine.c_str();  
    146.         }  
    147.   
    148.         WriteLogEx(L"command = [%s]", command.c_str());  
    149.   
    150.         if (!CreateEnvironmentBlock(&lpEnvironment, hPrimaryToken, TRUE))  
    151.         {  
    152.             WriteLogEx(L"!CreateEnvironmentBlock by hPrimaryToken");  
    153.         }  
    154.   
    155.         bTmp = CreateProcessAsUserA(  
    156.             hPrimaryToken,   
    157.             0,   
    158.             (LPSTR)ns_base::W2Aex(command.c_str()).c_str(),   
    159.             NULL,   
    160.             NULL,   
    161.             FALSE,   
    162.             NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT,  
    163.             lpEnvironment, // __in_opt    LPVOID lpEnvironment,  
    164.             0,   
    165.             &StartupInfo,   
    166.             &processInfo);  
    167.   
    168.         if (NULL != lpEnvironment)  
    169.             DestroyEnvironmentBlock(lpEnvironment);  
    170.   
    171.         WriteLogEx(L"CreateProcessAsUserA = %s", bTmp ? L"TRUE" : L"FALSE");  
    172.         if (!bTmp)  
    173.             break;  
    174.   
    175.         bRc = TRUE;  
    176.     } while (0);  
    177.   
    178.     SAFE_CLOSE_HANDLE(hPrimaryToken);  
    179.     WriteLogEx(L"<< CProcessStarter::Run, bRc = [%s]", bRc ? L"TRUE" : L"FALSE");  
    180.   
    181.     return bRc;  
    182. }  

http://blog.csdn.net/lostspeed/article/details/47018925

http://download.csdn.net/detail/lostspeed/8925599

原文地址:https://www.cnblogs.com/findumars/p/5174324.html