服务应用程序如何访问当前登录用户的信息

 
转载自 robinwjbgui
最终编辑 xicao54007

以服务权限,即SYSTEM帐户启动的程序是无法取得用户的profile的,比如startup文件夹的路径。

首先,Shell函数是不行的:


SHGetSpecialFolderPath取得的是C:\Windows\system32\config\systemprofile\

其次,环境变量也得不到。

GetEnvironmentVariable返回203( ERROR_ENVVAR_NOT_FOUND)


注:从服务应用程序可以拿到全局的环境变量,诸如ALLUSERS等等,但是各个用户的就搞不定了。

虽说从服务来访问用户的profile是一种非常不好的设计,但是如果有一些特殊需求的话,,

可以使用下面的方法。

BOOL bRes = FALSE;

char lpPath [ MAX_PATH ];


DWORD RetVal           = 0;

DWORD ErrCode          = 0;

DWORD ConsoleSessionId = 0;


// 函数的句柄

HMODULE hInstKernel32    = NULL;

HMODULE hInstWtsapi32    = NULL;


// Token的句柄

HANDLE hTokenUser        = NULL;

HANDLE hTokenThisProcess = NULL;

HANDLE hTokenThis        = NULL;


// WTSGetActiveConsoleSessionId 函数,得到当前登录用户的会话ID

// 这里的代码用的是VC6,新版的SDK已经包括此函数,无需LoadLibrary了。

typedef DWORD ( WINAPI * WTSGetActiveConsoleSessionIdPROC)();

WTSGetActiveConsoleSessionIdPROC WTSGetActiveConsoleSessionId = NULL;

hInstKernel32 = LoadLibrary( "Kernel32.dll");

if ( ! hInstKernel32)

{

return FALSE;

}


WTSGetActiveConsoleSessionId = ( WTSGetActiveConsoleSessionIdPROC) GetProcAddress( hInstKernel32 , "WTSGetActiveConsoleSessionId");

if ( ! WTSGetActiveConsoleSessionId)

{

return FALSE;

}


// WTSQueryUserToken 函数,通过会话ID得到令牌

typedef BOOL ( WINAPI * WTSQueryUserTokenPROC)( ULONG SessionId , PHANDLE phToken );

WTSQueryUserTokenPROC WTSQueryUserToken = NULL;

hInstWtsapi32 = LoadLibrary( "Wtsapi32.dll");

if ( ! hInstWtsapi32)

{

return FALSE;

}


WTSQueryUserToken = ( WTSQueryUserTokenPROC) GetProcAddress( hInstWtsapi32 , "WTSQueryUserToken");

if ( ! WTSQueryUserToken)

{

return FALSE;

}


// 得到当前激活用户的会话ID

ConsoleSessionId = WTSGetActiveConsoleSessionId();


// 得到当前登录用户的令牌

bRes = WTSQueryUserToken( ConsoleSessionId , & hTokenUser);

if ( ! bRes)

{

return FALSE;

}


// 模仿成当前登录用户

bRes = ImpersonateLoggedOnUser( hTokenUser);

if ( ! bRes)

{

return FALSE;

}


// 取得当前用户的Startup文件夹路径

bRes = SHGetSpecialFolderPath( NULL , lpPath , CSIDL_STARTUP , TRUE);

if ( ! bRes)

{

return FALSE;

}

else

{

MessageBox( NULL , lpPath , "Startup" , MB_OK);

}


// 终止模拟,返回

RevertToSelf();
 
在其它session中(如远程桌面的session)弹出窗口
弹出窗口,可以按照下述方法来实现,注:执行这段代码的进程就是你的服务进程,当前运行在session0中。还有一个前提,在本地登录时已经能弹出窗口。
HANDLE hThisProcess = GetCurrentProcess(); // 获取当前进程句柄
// 打开当前进程令牌
HANDLE hTokenThis = NULL;
OpenProcessToken(hThisProcess, TOKEN_ALL_ACCESS, &hTokenThis);
// 复制一个进程令牌,目的是为了修改session id属性,以便在其它session中创建进程
HANDLE hTokenDup = NULL;
DuplicateTokenEx(hTokenThis, MAXIMUM_ALLOWED,NULL, SecurityIdentification, TokenPrimary, &hTokenDup);
DWORD dwSessionId = WTSGetActiveConsoleSessionId(); // 获取活动session id,这里要注意,如果服务器还没有被登录而使用了远程桌面,这样用是可以的,如果有多个session存在,不能简单使用此函数,需要枚举所有session并确定你需要的一个,或者干脆使用循环,针对每个session都执行后面的代码
SetTokenInformation(hTokenDup, TokenSessionId, &dwSessionId, sizeof(DWORD)); // 把session id设置到备份的令牌中
// 好了,现在要用新的令牌来创建一个服务进程。注意:是“服务”进程!如果需要以用户身份运行,必须在前面执行LogonUser来获取用户令牌
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(STARTUPINFO));
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = "WinSta0\\Default";
LPVOID pEnv = NULL;
DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE; // 注意标志
CreateEnvironmentBlock(&pEnv, hTokenDup, FALSE); // 创建环境块
// 创建新的进程,这个进程就是你要弹出窗口的进程,它将工作在新的session中
CreateProcessAsUser(hTokenDup, NULL, _T("D:\\GetUserName.exe"), NULL, NULL, FALSE, dwCreationFlag, pEnv, NULL, &si, &pi);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值