在服务中以当前用户身份启动一个程序
发布日期:2021-06-30 22:06:12 浏览次数:2 分类:技术文章

本文共 14408 字,大约阅读时间需要 48 分钟。

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

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

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

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

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

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

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

工程下载点: 

编译环境: vs2010 vc++

备注 :  

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

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

效果图:

工程预览:

// lsServiceForTest.cpp : Defines the entry point for the application.//#include "stdafx.h"#include 
#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\n", 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 
#pragma comment(lib, "Userenv.lib")#include
#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;}

转载地址:https://lostspeed.blog.csdn.net/article/details/47018925 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:使用 autoruns.exe 来查看自动启动的程序
下一篇:MFC : 在主窗口不透明的情况下, 建立一个半透明的子窗体带透明的TreeCtrl

发表评论

最新留言

很好
[***.229.124.182]2024年04月28日 20时07分52秒