我正在使用一项服务,它应该模拟登录的用户。
到目前为止,我的代码具有基本的错误处理:
// get the active console session ID of the logged on user
if ( !WTSQueryUserToken( WTSGetActiveConsoleSessionId(), &hToken ) )
{
ShowErrorText( "WTSQueryUserToken failed.", GetLastError( ), true );
return;
}
HANDLE hDuplicated;
// duplicate the token
if ( !DuplicateToken( hToken, SecurityImpersonation, &hDuplicated ) )
{
ShowErrorText( "DuplicateToken failed.", GetLastError( ), true );
}
else
{
ShowErrorText( "DuplicateToken succeeded.", 0, true );
}
// impersonate the logged on user
if ( !ImpersonateLoggedOnUser( hToken ) )
{
ShowErrorText( "ImpersonateLoggedOnUser failed.", GetLastError(), true );
return;
}
// retrieve the DC name
if ( !GetPrimaryDC( DC ) )
{
ShowErrorText( "GetPrimaryDC failed.", 0, true );
}
PROFILEINFO lpProfileInfo;
ZeroMemory( &lpProfileInfo, sizeof( PROFILEINFO ) );
lpProfileInfo.dwSize = sizeof( PROFILEINFO );
lpProfileInfo.lpUserName = CurrentUser;
// get type of profile. roaming, mandatory or temporary
int ret = GetTypeOfProfile();
if ( ret == 2 )
{
// if roaming profile get the path of it
if ( !GetRoamingProfilePath( DC, CurrentUser, RoamingProfilePath ) )
{
ShowErrorText( "Failed to retrieve roaming profile path.", GetLastError(), true );
}
}
if ( RevertToSelf( ) )
{
ShowErrorText( "Impersonation ended successfully.", 0, true );
}
if ( !LoadUserProfile( hDuplicated, &lpProfileInfo ) )
{
ShowErrorText( "LoadUserProfile failed.", GetLastError(), true );
}
else
{
ShowErrorText( "LoadUserProfile succeeded.", 0, true );
}
//do some stuff
if ( !UnloadUserProfile( hDuplicated, lpProfileInfo.hProfile ) )
{
ShowErrorText( "UnloadUserProfile failed.", GetLastError( ), true );
}
else
{
ShowErrorText( "UnloadUserProfile succeeded.", 0, true );
}
if ( !ImpersonateLoggedOnUser( hToken ) )
{
ShowErrorText( "ImpersonateLoggedOnUser failed.", GetLastError( ), true );
return;
}
根据 MSDN:
当用户以交互方式登录时,系统会自动加载用户的配置文件。如果服务或应用程序模拟用户,系统不会加载用户的配置文件。因此,服务或应用程序应使用 LoadUserProfile 加载用户的配置文件。
调用 LoadUserProfile 的服务和应用程序应检查用户是否具有漫游配置文件。如果用户有漫游配置文件,请将其路径指定为 PROFILEINFO 的 lpProfilePath 成员。要检索用户的漫游配置文件路径,您可以调用 NetUserGetInfo 函数,指定信息级别 3 或 4。
成功返回后,PROFILEINFO 的 hProfile 成员是打开到用户配置单元根的注册表项句柄。它已以完全访问权限 (KEY_ALL_ACCESS) 打开。如果模拟用户的服务需要读取或写入用户的注册表文件,请使用此句柄而不是 HKEY_CURRENT_USER。不要关闭 hProfile 句柄。而是将其传递给 UnloadUserProfile 函数。
如果我现在使用我的代码,那么它可以工作。但是这有点奇怪,因为首先我必须模拟登录用户,然后结束模拟,以加载用户配置文件。如果我不结束模拟,则 LoadUserProfile 将失败并出现错误 5(访问被拒绝)。LoadUserProfile 成功后我应该再次模拟用户吗?
所以我的问题是,这意味着要这样做,还是我做错了什么?另一个问题是,如果 LoadUserProfile 成功,我可以使用 hProfile 作为登录用户注册表的句柄。问题是如何?因为要使用 RegOpenKeyEy 和 RegSetValueEx,我需要传递 HKEY,而不是 HANDLE。那么我该如何使用这个手柄呢?
谢谢!