【问题标题】:Delphi Tokyo Service createprocess only at bootDelphi Tokyo Service 仅在启动时创建进程
【发布时间】:2019-06-22 16:03:19
【问题描述】:

我在 Delphi Tokyo 有一个 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;

【问题讨论】:

    标签: delphi windows-10 windows-services createprocess


    【解决方案1】:

    错误代码 1008 是 ERROR_NO_TOKEN,这意味着在没有用户登录的会话 ID 上调用了 WTSQueryUserToken()

    WTSGetActiveConsoleSessionID() 并不总是最好使用的会话,尤其是在系统启动时,如果您的服务尝试在任何用户登录之前启动进程。附加到本地物理显示器/键盘/鼠标的会话 ID 不能保证在任何给定时间都有用户登录。

    在这种情况下,请改用WTSEnumerateSessions() 来查找实际有用户登录的会话。

    另外,您没有对CreateProcessAsUser() 进行任何错误处理。它不会像您的代码所期望的那样引发错误异常。你的try..except 没用。

    【讨论】:

    • 我试图模拟用户,但返回的不是错误 1008,而是错误 5 访问被拒绝。我添加了用于问题的代码。但是你会如何重写函数来启动一个进程呢?
    • @Daniele 这不是模拟问题,因此请摆脱该代码(无论如何它是有缺陷的)。你有没有尝试过我给的WTSEnumerateSessions() 建议?
    • 奇怪的是,在没有模拟的情况下,它现在可以再次工作,并且没有使用我尚未研究如何实现的建议功能。但我想你的建议有效,所以我接受了答案。
    猜你喜欢
    • 2011-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-21
    • 1970-01-01
    • 2019-05-15
    • 2020-09-09
    • 1970-01-01
    相关资源
    最近更新 更多