Delphi 东京服务仅在启动时创建进程
Delphi Tokyo Service createprocess only at boot
我在 Delphi 东京有 Windows 的服务脚本。该服务在系统启动时启动并正确创建进程 x。启动一个计时器,循环检查进程是否已启动,如果未启动,它会尝试启动它但失败,错误代码为 1008。
function TMyservice.CreaProcessoComeUtenteX(const FileName, Params: string;
WindowState: Word): Boolean;
var
SessionID: DWORD;
UserToken: THandle;
CmdLine: PChar;
si: _STARTUPINFOW;
pi: _PROCESS_INFORMATION;
ExitCode: Cardinal;
begin
SessionId:= WtsGetActiveConsoleSessionID;
if SessionID = $FFFFFFFF then
begin
ADDLOG('Exit from CreaProcessoComeUtenteX '+IntToStr(SessionID));
Result := false;
Exit;
end;
if WTSQueryUserToken(SessionID, UserToken) then
begin
CmdLine:= PWideChar(FileName+Params);
ZeroMemory(@si, SizeOf(si));
si.cb := SizeOf(si);
SI.lpDesktop := PChar('winsta0\Default');
SI.dwFlags := STARTF_USESHOWWINDOW;
if WindowState = 1 then
SI.wShowWindow := SW_SHOWNORMAL;
if WindowState = 0 then
SI.wShowWindow := SW_MINIMIZE;
ZeroMemory(@pi, SizeOf(pi));
try
CreateProcessAsUser(UserToken, nil, CmdLine, nil, nil, False,
0, nil, nil, si, pi);
ADDLOG(' Create process Ok');
result := true;
except on E: Exception do
begin
// Log exception ...
result := false;
ADDLOG('Err proc: '+ E.Message);
end;
end;
CloseHandle(UserToken);
end else
begin
// Log GetLastError ...
Result := false;
ADDLOG('QToken: '+IntToStr(GetLastError));
end;
end;
此代码模拟当前用户
function TInfBabeleDS.ConnectAs(const lpszUsername,
lpszPassword: string): Boolean;
var
hToken : THandle;
begin
Result := LogonUser(PChar(lpszUsername), nil, PChar(lpszPassword), LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, hToken);
if Result then
Result := ImpersonateLoggedOnUser(hToken)
else
RaiseLastOSError;
end;
错误代码 1008 是 ERROR_NO_TOKEN
,这意味着 WTSQueryUserToken()
是在没有用户登录的会话 ID 上调用的。
WTSGetActiveConsoleSessionID()
并不总是最好的会话,尤其是在系统启动时,如果您的服务试图在任何用户登录之前启动进程。附加到 本地物理 monitor/keyboard/mouse 的会话 ID 不能保证用户在任何给定时间登录,如果有的话。
在这种情况下,请改用 WTSEnumerateSessions()
来查找实际有用户登录的会话。
此外,您没有对 CreateProcessAsUser()
进行任何错误处理。它不会像您的代码所期望的那样引发错误异常。你的try..except
没用。
我在 Delphi 东京有 Windows 的服务脚本。该服务在系统启动时启动并正确创建进程 x。启动一个计时器,循环检查进程是否已启动,如果未启动,它会尝试启动它但失败,错误代码为 1008。
function TMyservice.CreaProcessoComeUtenteX(const FileName, Params: string;
WindowState: Word): Boolean;
var
SessionID: DWORD;
UserToken: THandle;
CmdLine: PChar;
si: _STARTUPINFOW;
pi: _PROCESS_INFORMATION;
ExitCode: Cardinal;
begin
SessionId:= WtsGetActiveConsoleSessionID;
if SessionID = $FFFFFFFF then
begin
ADDLOG('Exit from CreaProcessoComeUtenteX '+IntToStr(SessionID));
Result := false;
Exit;
end;
if WTSQueryUserToken(SessionID, UserToken) then
begin
CmdLine:= PWideChar(FileName+Params);
ZeroMemory(@si, SizeOf(si));
si.cb := SizeOf(si);
SI.lpDesktop := PChar('winsta0\Default');
SI.dwFlags := STARTF_USESHOWWINDOW;
if WindowState = 1 then
SI.wShowWindow := SW_SHOWNORMAL;
if WindowState = 0 then
SI.wShowWindow := SW_MINIMIZE;
ZeroMemory(@pi, SizeOf(pi));
try
CreateProcessAsUser(UserToken, nil, CmdLine, nil, nil, False,
0, nil, nil, si, pi);
ADDLOG(' Create process Ok');
result := true;
except on E: Exception do
begin
// Log exception ...
result := false;
ADDLOG('Err proc: '+ E.Message);
end;
end;
CloseHandle(UserToken);
end else
begin
// Log GetLastError ...
Result := false;
ADDLOG('QToken: '+IntToStr(GetLastError));
end;
end;
此代码模拟当前用户
function TInfBabeleDS.ConnectAs(const lpszUsername,
lpszPassword: string): Boolean;
var
hToken : THandle;
begin
Result := LogonUser(PChar(lpszUsername), nil, PChar(lpszPassword), LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, hToken);
if Result then
Result := ImpersonateLoggedOnUser(hToken)
else
RaiseLastOSError;
end;
错误代码 1008 是 ERROR_NO_TOKEN
,这意味着 WTSQueryUserToken()
是在没有用户登录的会话 ID 上调用的。
WTSGetActiveConsoleSessionID()
并不总是最好的会话,尤其是在系统启动时,如果您的服务试图在任何用户登录之前启动进程。附加到 本地物理 monitor/keyboard/mouse 的会话 ID 不能保证用户在任何给定时间登录,如果有的话。
在这种情况下,请改用 WTSEnumerateSessions()
来查找实际有用户登录的会话。
此外,您没有对 CreateProcessAsUser()
进行任何错误处理。它不会像您的代码所期望的那样引发错误异常。你的try..except
没用。