在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 服务启动停止时, 检测服务是否已经在运行或停止的处理要加上, 提高效率.
/// 如果硬生生的启动停止服务时, 还要启动停止桌面上的程序, 在没有检测服务状态时, 要花费的时间多些.
效果图:
工程预览:
- // lsServiceForTest.cpp : Defines the entry point for the application.
- //
- #include "stdafx.h"
- #include <process.h>
- #include "lsServiceForTest.h"
- #include "ProcessStarter.h"
- #define SERVICE_VER_W L"1, 0, 0, 1"
- #define PROJECT_MODIFY_TIME L"2015-0722-1426"
- VOID WINAPI ServiceMain(DWORD dwArgc, LPWSTR *lpszArgv);
- SERVICE_TABLE_ENTRYW lpServiceStartTable[] =
- {
- {SERVICE_NAME_W, ServiceMain},
- {NULL, NULL}
- };
- SERVICE_STATUS_HANDLE g_hServiceCtrlHandler = NULL;
- SERVICE_STATUS g_ServiceStatus;
- std::wstring g_strPathNameMe = L"";
- std::wstring g_strCmdLine = L"";
- ns_base::CThreadManager g_ThreadManager;
- VOID ServiceMainProc();
- static UINT WINAPI ThreadProcWorker(void* pParam);
- BOOL ThreadProcStart_Worker();
- BOOL ThreadProcStop_Worker();
- BOOL GetObjProgInfo(DWORD dwSessionId, OUT std::wstring& strObjPathName, OUT std::wstring& strCmdLine);
- VOID ExecuteAsService();
- VOID WINAPI ServiceHandler(DWORD fdwControl);
- int APIENTRY _tWinMain(HINSTANCE hInstance,
- HINSTANCE hPrevInstance,
- LPTSTR lpCmdLine,
- int nCmdShow)
- {
- std::wstring strLogFilePathName = L"";
- ns_base::GetFilePathName_Me(g_strPathNameMe);
- g_strCmdLine = (NULL != lpCmdLine) ? lpCmdLine : L"";
- strLogFilePathName = ns_business::GetLogPathName_lsServiceForTest().c_str();
- SetLogFilePathName(strLogFilePathName.c_str());
- ServiceMainProc();
- return 0;
- }
- VOID ServiceMainProc()
- {
- WriteLogEx(L">> ServiceMainProc() [%s][%s][%s]", SERVICE_NAME_W, SERVICE_VER_W, PROJECT_MODIFY_TIME);
- if (ns_base::StringCompare_equ(g_strCmdLine.c_str(), L"-i")
- || ns_base::StringCompare_equ(g_strCmdLine.c_str(), L"-I"))
- {
- ns_base::ServiceInstall(g_strPathNameMe.c_str(), SERVICE_NAME_W);
- }
- else if (ns_base::StringCompare_equ(g_strCmdLine.c_str(), L"-s")
- || ns_base::StringCompare_equ(g_strCmdLine.c_str(), L"-S"))
- {
- ns_base::ServiceStart(SERVICE_NAME_W);
- }
- else if (ns_base::StringCompare_equ(g_strCmdLine.c_str(), L"-k")
- || ns_base::StringCompare_equ(g_strCmdLine.c_str(), L"-K"))
- {
- ns_base::ServiceStop(SERVICE_NAME_W);
- }
- else if (ns_base::StringCompare_equ(g_strCmdLine.c_str(), L"-u")
- || ns_base::StringCompare_equ(g_strCmdLine.c_str(), L"-U"))
- {
- ns_base::ServiceUnInstall(SERVICE_NAME_W);
- }
- else
- ExecuteAsService();
- WriteLogEx(L"<< ServiceMainProc() [%s][%s][%s]", SERVICE_NAME_W, SERVICE_VER_W, PROJECT_MODIFY_TIME);
- }
- VOID ExecuteAsService()
- {
- WriteLogEx(L">> ExecuteAsService");
- if(!ThreadProcStart_Worker())
- {
- WriteLogEx(L"ThreadProcStart_Worker failed[%d]", GetLastError());
- }
- if(!StartServiceCtrlDispatcherW(lpServiceStartTable))
- {
- WriteLogEx(L"StartServiceCtrlDispatcher failed[%d]", GetLastError());
- }
- WriteLogEx(L"<< ExecuteAsService");
- }
- VOID WINAPI ServiceMain(DWORD dwArgc, LPWSTR* lpszArgv)
- {
- WriteLogEx(L">> ServiceMain(%d, lpszArgv)", dwArgc);
- do
- {
- g_ServiceStatus.dwServiceType = SERVICE_WIN32;
- g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
- g_ServiceStatus.dwControlsAccepted =
- SERVICE_ACCEPT_STOP
- | SERVICE_ACCEPT_PAUSE_CONTINUE
- | SERVICE_ACCEPT_SHUTDOWN
- | SERVICE_ACCEPT_PARAMCHANGE
- | SERVICE_ACCEPT_NETBINDCHANGE
- | SERVICE_ACCEPT_HARDWAREPROFILECHANGE
- | SERVICE_ACCEPT_POWEREVENT
- | SERVICE_ACCEPT_SESSIONCHANGE
- | SERVICE_ACCEPT_PRESHUTDOWN
- | SERVICE_ACCEPT_TIMECHANGE
- | SERVICE_ACCEPT_TRIGGEREVENT;
- g_ServiceStatus.dwWin32ExitCode = 0;
- g_ServiceStatus.dwServiceSpecificExitCode = 0;
- g_ServiceStatus.dwCheckPoint = 0;
- g_ServiceStatus.dwWaitHint = 0;
- g_hServiceCtrlHandler = RegisterServiceCtrlHandlerW(SERVICE_NAME_W, ServiceHandler);
- if (NULL == g_hServiceCtrlHandler)
- {
- ns_base::NotifyFailed_RegisterServiceCtrlHandler(GetLastError(), SERVICE_NAME_W);
- break;
- }
- // Initialization complete - report running status
- g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
- g_ServiceStatus.dwCheckPoint = 0;
- g_ServiceStatus.dwWaitHint = 0;
- if (!SetServiceStatus(g_hServiceCtrlHandler, &g_ServiceStatus))
- {
- ns_base::NotifyFailed_SetServiceStatus(GetLastError(), SERVICE_NAME_W);
- }
- } while (0);
- WriteLogEx(L"<< ServiceMain(%d, lpszArgv)", dwArgc);
- }
- VOID WINAPI ServiceHandler(DWORD fdwControl)
- {
- int iIndex = 0;
- WriteLogEx(L">> ServiceHandler(%d)", fdwControl);
- switch(fdwControl)
- {
- case SERVICE_CONTROL_STOP:
- case SERVICE_CONTROL_SHUTDOWN:
- g_ThreadManager.StopThread(TRUE, L"g_ThreadManager");
- g_ServiceStatus.dwWin32ExitCode = 0;
- g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
- g_ServiceStatus.dwCheckPoint = 0;
- g_ServiceStatus.dwWaitHint = 0;
- // terminate all processes started by this service before shutdown
- ns_business::StopAndKill_dlgNotify();
- break;
- case SERVICE_CONTROL_PAUSE:
- g_ServiceStatus.dwCurrentState = SERVICE_PAUSED;
- break;
- case SERVICE_CONTROL_CONTINUE:
- g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
- break;
- default:
- WriteLogEx(L"Unrecognized opcode %d ", fdwControl);
- };
- if (!SetServiceStatus(g_hServiceCtrlHandler, &g_ServiceStatus))
- {
- ns_base::NotifyFailed_SetServiceStatus(GetLastError(), SERVICE_NAME_W);
- }
- WriteLogEx(L"<< ServiceHandler(%d)", fdwControl);
- }
- static UINT WINAPI ThreadProcWorker(void* pParam)
- {
- BOOL bLog = TRUE;
- DWORD dwSessionIdPrev = -1;
- DWORD dwSessionId = -1;
- size_t nSleepTotal = 0;
- UINT uRc = S_FALSE;
- std::wstring strObjPathName = L"";
- std::wstring strCmdLine = L"";
- ns_base::TAG_THREAD_MANAGER_PARAM ThreadManagerParam;
- ns_base::TAG_THREAD_MANAGER_PARAM* pThreadManagerParam = NULL;
- CProcessStarter ProcessStarter;
- WriteLogEx(L">> lsServiceForTest ThreadProcWorker");
- do
- {
- if (NULL == pParam)
- break;
- pThreadManagerParam = (ns_base::TAG_THREAD_MANAGER_PARAM*)pParam;
- ThreadManagerParam.copy((ns_base::TAG_THREAD_MANAGER_PARAM*)pParam);
- SAFE_DELETE(pThreadManagerParam);
- if (NULL == ThreadManagerParam.pThreadManager)
- break;
- while(!ThreadManagerParam.pThreadManager->IsNeedQuitThread())
- {
- if (!ns_base::SleepContinueEx(2000, 100, nSleepTotal))
- continue;
- /// 保证 只有在SessionId变化的时候, 才打印 FindActiveSessionId 的日志
- if (!ProcessStarter.FindActiveSessionId(dwSessionId, bLog)
- || (dwSessionIdPrev == dwSessionId))
- {
- if (bLog)
- bLog = FALSE;
- continue;
- }
- if (!bLog)
- bLog = TRUE;
- /// 用户每次切换一次桌面, 我们就启动一次子程序
- do
- {
- dwSessionIdPrev = dwSessionId;
- if (GetObjProgInfo(dwSessionId, strObjPathName, strCmdLine))
- {
- if (!ns_base::IsFileExist(strObjPathName.c_str()))
- {
- WriteLogEx(L"[error] !ns_base::IsFileExist(%s)", strObjPathName.c_str());
- break;
- }
- /// 确保在多个SessionId的环境下, 也只有当前SessionId上运行唯一一个dlgNotify
- ns_business::StopAndKill_dlgNotify();
- ProcessStarter.Run(
- strObjPathName.c_str(),
- strCmdLine.c_str());
- }
- } while (0);
- continue;
- }
- uRc = S_OK;
- } while (0);
- WriteLogEx(L"<< FzAppService ThreadProcWorker");
- return uRc;
- }
- BOOL ThreadProcStart_Worker()
- {
- BOOL bRc = FALSE;
- ns_base::TAG_THREAD_MANAGER_PARAM* pThreadManagerParam = NULL;
- if (!g_ThreadManager.IsNeedQuitThread()
- && !g_ThreadManager.IsThreadRunning())
- {
- do
- {
- pThreadManagerParam = new ns_base::TAG_THREAD_MANAGER_PARAM;
- if (NULL == pThreadManagerParam)
- break;
- pThreadManagerParam->pThreadManager = &g_ThreadManager;
- g_ThreadManager.SetThreadHandle(
- (HANDLE)_beginthreadex(
- NULL,
- 0,
- &ThreadProcWorker,
- (void*)pThreadManagerParam,
- 0,
- NULL));
- bRc = TRUE;
- } while (0);
- }
- return bRc;
- }
- BOOL ThreadProcStop_Worker()
- {
- g_ThreadManager.StopThread(TRUE, L"g_ThreadManager");
- return TRUE;
- }
- BOOL GetObjProgInfo(DWORD dwSessionId, OUT std::wstring& strObjPathName, OUT std::wstring& strCmdLine)
- {
- ns_base::GetPathName_Me(strObjPathName);
- strObjPathName += FILE_NAME_ObjProgInfo;
- strCmdLine = ns_base::StringFormatV(L"sessionId-%d", dwSessionId);
- return TRUE;
- }
CProcessStarter 实现, 负责以当前用户身份启动一个程序.
- #ifndef _PROCESS_STARTER_H_
- #define _PROCESS_STARTER_H_
- #include "stdafx.h"
- class CProcessStarter
- {
- public:
- CProcessStarter();
- /// 如果没有找到"已经激活的SessionId", 说明还没有进入桌面
- BOOL FindActiveSessionId(OUT DWORD& dwSessionId, BOOL bNeedLog);
- BOOL Run(LPCWSTR pcProcessPathName, LPCWSTR pcCmdLine);
- private:
- HANDLE GetCurrentUserToken();
- private:
- std::wstring m_strProcessPathName;
- std::wstring m_strCmdLine;
- };
- #endif //_PROCESS_STARTER_H_
- #include "stdafx.h"
- #include "ProcessStarter.h"
- #include <userenv.h>
- #pragma comment(lib, "Userenv.lib")
- #include <wtsapi32.h>
- #pragma comment(lib, "Wtsapi32.lib")
- CProcessStarter::CProcessStarter()
- : m_strProcessPathName(L""),
- m_strCmdLine(L"")
- {
- }
- BOOL CProcessStarter::FindActiveSessionId(OUT DWORD& dwSessionId, BOOL bNeedLog)
- {
- BOOL bFindActiveSession = FALSE;
- DWORD dwIndex = 0;
- PWTS_SESSION_INFO pWtsSessionInfo = NULL;
- DWORD dwCntWtsSessionInfo = 0;
- if (bNeedLog)
- WriteLogEx(L">> CProcessStarter::FindActiveSessionId()");
- do
- {
- dwSessionId = (DWORD)(-1);
- if ((!WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pWtsSessionInfo, &dwCntWtsSessionInfo))
- || (NULL == pWtsSessionInfo))
- {
- if (bNeedLog)
- WriteLogEx(L"break 0 CProcessStarter::FindActiveSessionId()");
- break;
- }
- for (dwIndex = 0; dwIndex < dwCntWtsSessionInfo; dwIndex++)
- {
- if (WTSActive == pWtsSessionInfo[dwIndex].State)
- {
- dwSessionId = pWtsSessionInfo[dwIndex].SessionId;
- bFindActiveSession = TRUE;
- break;
- }
- }
- WTSFreeMemory(pWtsSessionInfo);
- if (!bFindActiveSession)
- {
- if (bNeedLog)
- WriteLogEx(L"break 1 CProcessStarter::FindActiveSessionId()");
- break;
- }
- } while (0);
- if (bNeedLog)
- {
- WriteLogEx(L"<< CProcessStarter::FindActiveSessionId(), bFindActiveSession = [%s], dwSessionId = %d",
- bFindActiveSession ? L"TRUE" : L"FALSE",
- dwSessionId);
- }
- return bFindActiveSession;
- }
- HANDLE CProcessStarter::GetCurrentUserToken()
- {
- DWORD dwSessionId = 0;
- HANDLE hCurrentToken = NULL;
- HANDLE hPrimaryToken = NULL;
- WriteLogEx(L">> CProcessStarter::GetCurrentUserToken()");
- do
- {
- if (!FindActiveSessionId(dwSessionId, TRUE))
- {
- WriteLogEx(L"break 0 CProcessStarter::GetCurrentUserToken()");
- break;
- }
- if (!WTSQueryUserToken(dwSessionId, &hCurrentToken)
- || (NULL == hCurrentToken))
- {
- WriteLogEx(L"break 2 CProcessStarter::GetCurrentUserToken()");
- break;
- }
- if (!DuplicateTokenEx(hCurrentToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, 0, SecurityImpersonation, TokenPrimary, &hPrimaryToken))
- {
- WriteLogEx(L"break 3 CProcessStarter::GetCurrentUserToken()");
- break;
- }
- } while (0);
- WriteLogEx(L"<< CProcessStarter::GetCurrentUserToken(), hCurrentToken = 0x%p, hPrimaryToken = 0x%p",
- hCurrentToken,
- hPrimaryToken);
- SAFE_CLOSE_HANDLE(hCurrentToken);
- return hPrimaryToken;
- }
- BOOL CProcessStarter::Run(LPCWSTR pcProcessPathName, LPCWSTR pcCmdLine)
- {
- BOOL bRc = FALSE;
- BOOL bTmp = FALSE;
- HANDLE hPrimaryToken = NULL;
- STARTUPINFOA StartupInfo = {0};
- PROCESS_INFORMATION processInfo = {0};
- std::wstring command = L"";
- LPVOID lpEnvironment = NULL;
- WriteLogEx(L">> CProcessStarter::Run");
- do
- {
- if ((NULL == pcProcessPathName) || (!ns_base::IsFileExist(pcProcessPathName)))
- {
- WriteLogEx(L"break 0 CProcessStarter::Run");
- break;
- }
- this->m_strProcessPathName = pcProcessPathName;
- this->m_strCmdLine = (NULL != pcCmdLine) ? pcCmdLine : L"";
- hPrimaryToken = GetCurrentUserToken();
- if (NULL == hPrimaryToken)
- {
- WriteLogEx(L"break 1 CProcessStarter::Run");
- break;
- }
- StartupInfo.cb = sizeof(STARTUPINFO);
- command = L""";
- command += m_strProcessPathName.c_str();
- command += L""";
- if (m_strCmdLine.length() != 0)
- {
- command += L" ";
- command += m_strCmdLine.c_str();
- }
- WriteLogEx(L"command = [%s]", command.c_str());
- if (!CreateEnvironmentBlock(&lpEnvironment, hPrimaryToken, TRUE))
- {
- WriteLogEx(L"!CreateEnvironmentBlock by hPrimaryToken");
- }
- bTmp = CreateProcessAsUserA(
- hPrimaryToken,
- 0,
- (LPSTR)ns_base::W2Aex(command.c_str()).c_str(),
- NULL,
- NULL,
- FALSE,
- NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT,
- lpEnvironment, // __in_opt LPVOID lpEnvironment,
- 0,
- &StartupInfo,
- &processInfo);
- if (NULL != lpEnvironment)
- DestroyEnvironmentBlock(lpEnvironment);
- WriteLogEx(L"CreateProcessAsUserA = %s", bTmp ? L"TRUE" : L"FALSE");
- if (!bTmp)
- break;
- bRc = TRUE;
- } while (0);
- SAFE_CLOSE_HANDLE(hPrimaryToken);
- WriteLogEx(L"<< CProcessStarter::Run, bRc = [%s]", bRc ? L"TRUE" : L"FALSE");
- return bRc;
- }
http://blog.csdn.net/lostspeed/article/details/47018925
http://download.csdn.net/detail/lostspeed/8925599