Windows CreateProcessAsUser不';“我不工作时”;“更改用户”;
首先,我要感谢所有为这个网站工作的人,这对开发者来说非常有用。这是我3天以来第一次在发展中受阻。我在互联网上搜索了解决方案,但没有找到解决这个问题的方法 因此,我开发了一个服务,当用户登录时,它必须在vista/seven/xp上执行一个外部程序。这项服务的一些特点:Windows CreateProcessAsUser不';“我不工作时”;“更改用户”;,windows,delphi,winapi,windows-7,Windows,Delphi,Winapi,Windows 7,首先,我要感谢所有为这个网站工作的人,这对开发者来说非常有用。这是我3天以来第一次在发展中受阻。我在互联网上搜索了解决方案,但没有找到解决这个问题的方法 因此,我开发了一个服务,当用户登录时,它必须在vista/seven/xp上执行一个外部程序。这项服务的一些特点: 自动的 没有互动 检测已登录用户的会话ID 要以交互用户身份运行外部GUI应用程序,请执行以下操作: 为了确保打开了一个用户会话,我列出了所有的“explorer.exe”进程,用msdn函数ProcessIdToSessio
- 自动的
- 没有互动
- 检测已登录用户的会话ID
function RunInteractive(prog_filename: String; sessionID: Cardinal): boolean;
var hToken: THandle;
si: _STARTUPINFOA;
pi: _PROCESS_INFORMATION;
begin
ZeroMemory(@si, SizeOf(si));
si.cb := SizeOf(si);
SI.lpDesktop := nil;
if WTSQueryUserToken(sessionID, hToken)
then begin
if CreateProcessAsUser(hToken, nil, PChar(prog_filename), nil, nil, False, 0, nil, PChar(ExtractFilePath(prog_filename)), si, pi)
then result := true
else result := false;
end
else Begin
result := false;
End;
CloseHandle(hToken);
end;
出了点问题,但我找不到解决办法。感谢您的回答…您通过查找“good”explorer.exe获取会话ID的方法可能不适用于快速用户切换 尝试让您的应用程序向注册会话更改通知。然后,当会话切换时,您将收到通知,并填写当前会话ID 注意以下几点: 要从服务接收会话更改通知,请使用 功能
您不需要枚举正在运行的explorer.exe进程,可以改用
WTSGetActiveConsoleSessionId()
,然后将该SessionId传递给WTSQueryUserToken()
。请注意,WTSQueryUserToken()
返回模拟令牌,但CreateProcessAsUser()
需要主令牌,因此使用DuplicateTokenEx()
进行转换
您还应该使用CreateEnvironmentBlock()
,以便生成的进程具有适合所使用的用户帐户的适当环境
最后,将STARTUPINFO.lpDesktop
字段设置为'WinSta0\Default'
而不是nil
,以便生成的UI可以正确显示
我已经使用这种方法好几年了,没有任何问题。例如:
function CreateEnvironmentBlock(var lpEnvironment: Pointer; hToken: THandle; bInherit: BOOL): BOOL; stdcall; external 'userenv.dll'
function DestroyEnvironmentBlock(lpEnvironment: Pointer): BOOL; stdcall; external 'userenv.dll';
function RunInteractive(prog_filename: String): Boolean;
var
hUserToken, hToken: THandle;
si: _STARTUPINFOA;
pi: _PROCESS_INFORMATION;
SessionId: DWORD;
Env: Pointer;
begin
Result := False;
ZeroMemory(@si, SizeOf(si));
si.cb := SizeOf(si);
si.lpDesktop := 'WinSta0\Default';
SessionId := WTSGetActiveConsoleSessionId;
if SessionId = $FFFFFFFF then Exit;
if not WTSQueryUserToken(SessionID, hToken) then Exit;
try
if not DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, nil, SecurityIdentification, TokenPrimary, hUserToken) then Exit;
finally
CloseHandle(hToken);
end;
try
if not CreateEnvironmentBlock(Env, hUserToken, False) then Exit;
try
Result := CreateProcessAsUser(hUserToken, nil, PChar(prog_filename), nil, nil, False, CREATE_UNICODE_ENVIRONMENT, Env, PChar(ExtractFilePath(prog_filename)), si, pi);
if Result then
begin
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
end;
finally
DestroyEnvironmentBlock(Env);
end;
finally
CloseHandle(hUserToken);
end;
end;
“解雇所有人”可能不是你想说的意思——它的意思是忽略他们或把他们赶走!也许是“鼓掌”或“谢谢”?我们知道你的意思,反正,只是觉得你可能会感兴趣:)太好了!我只使用谷歌翻译这个词(“remercier”法语)。你可以检查它,谷歌返回:谢谢,辞退和致谢。我再也不相信它了sessionID很好,我将这个值记录在一个文件中,并将它与taskmanager中进程的会话Id进行比较。这是相同的值。对于通知,我已经使用了此函数,并使用WTS_SESSION_LOGON作为外部程序执行的条件。对于您的答案,我将此值记录在一个文件中,并将其与taskmanager中进程的会话Id进行比较。这是相同的值。感谢你的出色解释。问题没有解决,但你的回答帮助了我。我用你的代码编译服务:快速用户切换中的问题是相同的。所以我决定运行另一个外部程序,比如notepad.exe:没问题!之后,我尝试使用批处理文件“拒绝访问”简单地运行外部程序。因此,我得出结论,问题不在于服务的源代码,而在于外部程序的源代码,它只在“快速用户切换”中表现糟糕。如果我找到了解决方案,我会查看并返回给您。但是,也许您有一个想法……我忘了说,在错误对话框消息“代码5,访问被拒绝”之后,会出现第二个错误对话框,其中包含以下消息:“无法更改在显示或隐藏时可见”。其他事项:主窗体的FormCreate方法中包含的“write_log”函数似乎不起作用您用于生成程序的用户帐户可能对您尝试写入的日志文件没有权限。请记住,默认情况下,文件由创建它的用户帐户拥有,除非该文件存储在应用较少限制的文件夹中。要让多个用户共享对文件的访问,请将文件存储在%ALLUSERSPROFILE%的子文件夹中,和/或使用
SetFileSecurity()
调整文件的SACL/DACL以允许所有用户访问。@remy:WtsQeuryUserToken a,ready返回一个主令牌,因此无需复制它。我还建议冒充你可以访问他/她的文件,你也可以考虑加载用户配置文件。此外CPAUW也可以更改命令行字符串(参数实际上是一个输入/输出)。所以它不能指向文本字符串(在本例中)。对于se