前言
今天和同事聊起感知用户登录的方法. 想起以前做过一个<<在服务中以当前用户身份启动一个程序>>的试验, 里面有当不同用户身份登录(在服务程序中轮询时, 得到不一样的SessionID)时, 会以当前用户身份启动一个示例程序.这就已经感知了不同用户登录.
回家做了一个试验, 验证不同用户登录时, 收集用户登录的信息, 只是做验证(记录当前用户登录的用户名, 其他用户信息没取(可以取到更多的信息)).
Demo下载点
DetectUserLogin.zip
有些函数在vc6里没有,改起来需要花更多时间, 就用vs2013做了一个工程.
关键API
WTSEnumerateSessions
WTSQuerySessionInformation
WTSFreeMemory
程序片段
试验结果
[09588] 2017-02-23 00:09:51 << CProcessStarter::FindActiveSessionId(), bFindActiveSession = [TRUE], dwSessionId = 1
[09588] 2017-02-23 00:09:51 m_strSessionInfo = LostSpeed
[09588] 2017-02-23 00:09:53 >> CProcessStarter::FindActiveSessionId()
[09588] 2017-02-23 00:09:53 << CProcessStarter::FindActiveSessionId(), bFindActiveSession = [TRUE], dwSessionId = 1
[09588] 2017-02-23 00:12:43 m_strSessionInfo = stdUser1
[09588] 2017-02-23 00:12:46 >> CProcessStarter::FindActiveSessionId()
[09588] 2017-02-23 00:12:46 << CProcessStarter::FindActiveSessionId(), bFindActiveSession = [TRUE], dwSessionId = 2
[09588] 2017-02-23 00:13:48 m_strSessionInfo = stduser2
[09588] 2017-02-23 00:13:51 >> CProcessStarter::FindActiveSessionId()
[09588] 2017-02-23 00:13:51 << CProcessStarter::FindActiveSessionId(), bFindActiveSession = [TRUE], dwSessionId = 3
[09588] 2017-02-23 00:14:30 m_strSessionInfo = LostSpeed
服务程序
// @file LsServcie.cpp
// @brief 在服务中感知用户登录
#include "stdafx.h"
#include <windows.h>
#include "ThreadManager.h"
#include "UtilityHelper.h"
#include "SCM.h"
#include "ProcessStarter.h"
#define SERVICE_NAME_W L"ls_test_service"
#define SERVICE_VER_W L"1, 0, 0, 2"
#define PROJECT_MODIFY_TIME L"2017-0222-1959"
#define LOG_FILE_NAME_DLG_NOTIFY L"log_dlg_notify.txt"
#define LOG_FILE_NAME_LSSERVICEFORTEST L"log_lsServiceForTest.txt"
#define FILE_NAME_NOTIFY _T("notepad.exe")
// X64下的notepad.exe的原始名称为NOTEPAD.EXE.MUI
#define FILE_ORGNAME_NOTIFY _T("NOTEPAD.EXE.MUI")
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();
VOID ExecuteAsService();
VOID WINAPI ServiceHandler(DWORD fdwControl);
std::wstring GetLogPathName_lsServiceForTest();
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 = 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();
}
// #ifdef _DEBUG
// // 要调试线程时, 这里要等着, 要不主线程退出时, 子线程也结束了
// while(1) {
// Sleep(10);
// }
// #endif
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;
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 bFirstRun = TRUE; // 标记-首次运行
BOOL bLog = TRUE;
DWORD dwSessionIdPrev = -1;
DWORD dwSessionId = -1;
size_t nSleepTotal = 0;
UINT uRc = S_FALSE;
std::wstring strObjPathName = L"";
std::wstring strOrgObjPathName = L"";
std::wstring strCmdLine = L"";
std::wstring strCmdLineAll = 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 (bFirstRun) {
bFirstRun = FALSE;
} else {
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;
}
dwSessionIdPrev = dwSessionId;
// 只是演示, 验证可以在服务中, 经过轮询, 得知SessionID的变化(不同用户登录的SessionID不同)
// 由SessionID可以得到登录的用户名和其他登录信息
// 通过记录日志, 来演示不同用户登录时, 可以在服务中感知到.
WriteLogEx(_T("m_strSessionInfo = %s\r\n"), ProcessStarter.GetSessionInfo());
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;
}
std::wstring GetLogPathName_lsServiceForTest()
{
std::wstring strPathName = L"";
ns_base::GetPathName_Me(strPathName);
strPathName += LOG_FILE_NAME_LSSERVICEFORTEST;
return strPathName;
}
取登录信息的工具类
#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);
const TCHAR* GetSessionInfo() {
return m_strSessionInfo.c_str();
}
private:
HANDLE GetCurrentUserToken();
private:
std::wstring m_strProcessPathName;
std::wstring m_strCmdLine;
std::wstring m_strSessionInfo;
};
#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(_T("")),
m_strCmdLine(_T("")),
m_strSessionInfo(_T(""))
{
}
BOOL CProcessStarter::FindActiveSessionId(OUT DWORD& dwSessionId, BOOL bNeedLog)
{
BOOL bFindActiveSession = FALSE;
DWORD dwIndex = 0;
PWTS_SESSION_INFO pWtsSessionInfo = NULL;
DWORD dwCntWtsSessionInfo = 0;
LPTSTR pBuffer = NULL;
DWORD dwRc = 0;
if (bNeedLog) {
WriteLogEx(L">> CProcessStarter::FindActiveSessionId()");
}
m_strSessionInfo = _T("");
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;
if (WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE,
dwSessionId,
WTSUserName,
&pBuffer, &dwRc)) {
if (NULL != pBuffer) {
m_strSessionInfo += (LPTSTR)pBuffer;
m_strSessionInfo += _T("\r\n");
}
}
if (NULL != pBuffer) {
WTSFreeMemory(pBuffer);
}
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;
}