通过Windows服务上的WinSCP下载SFTP文件将冻结

通过Windows服务上的WinSCP下载SFTP文件将冻结,windows,delphi,windows-services,sftp,winscp,Windows,Delphi,Windows Services,Sftp,Winscp,我正在尝试构建一个服务,该服务使用SFTP下载一些日志文件并将它们导入数据库 因为Delphi没有SFTP组件,所以我创建了一个BAT文件来使用WinSCP下载日志 DownloadLogs.bat: WinSCP.com < DownloadLogs.commands DownloadLogs.commands: open sftp://root:password@myserver.com option confirm off get -delete /var/lib/

我正在尝试构建一个服务,该服务使用SFTP下载一些日志文件并将它们导入数据库

因为Delphi没有SFTP组件,所以我创建了一个BAT文件来使用WinSCP下载日志

DownloadLogs.bat:
  WinSCP.com < DownloadLogs.commands

DownloadLogs.commands:
  open sftp://root:password@myserver.com
  option confirm off
  get -delete /var/lib/3cxpbx/Instance1/Data/Logs/CDRLogs files
  exit
这就是我如何称呼BAT文件的:

function ExecAppWait(AppName: string; Params: string = ''; Directory: string = ''; Hidden: boolean = False): Boolean;
var ShellExInfo: TShellExecuteInfo;
begin
  FillChar(ShellExInfo, SizeOf(ShellExInfo), 0);
  with ShellExInfo do begin
    cbSize := SizeOf(ShellExInfo);
    fMask  := see_Mask_NoCloseProcess;
    Wnd    := Application.Handle;
    lpFile := PChar(AppName);
    lpDirectory  := PChar(Directory);
    lpParameters := PChar(Params);
    if Hidden then nShow := sw_Hide
    else nShow := sw_ShowNormal;
  end;
  Result := ShellExecuteEx(@ShellExInfo);
  if Result then
    while WaitForSingleObject(ShellExInfo.HProcess, 100) = WAIT_TIMEOUT do begin
      Application.ProcessMessages; // give processor time to other tasks
      if Application.Terminated then
        Break;
    end;
end;

function TdmLogs.DownloadLogs(Hidden: boolean = True): boolean;
var Path: string;
begin
  Path := TPath.Combine(TPath.GetDirectoryName(Application.ExeName), 'SFTP');;
  ExecAppWait(TPath.Combine(Path, 'LogsCentralita.bat'), '', Hidden);
  Result := Length(TDirectory.GetFiles(TPath.Combine(Path, 'Files'), '*.log')) > 0
end;
在我的应用程序上调试DownloadLogs函数时,它工作正常,但作为服务运行时会冻结。你知道怎么回事吗?我不能从服务调用CMD.exe吗

多谢各位

更新

按照Martin Prikryl的回答,我现在以这种方式执行WinSCP:

function TdmCentralita.DownloadLogs(SaveOutput: boolean = False): boolean;
var IniFile: TIniFile;
    Path, Params, User, Password, Server, Hostkey, RemotePath: string;
begin
  IniFile := TIniFile.Create(TPath.ChangeExtension(GetModuleName(HInstance), '.ini'));
  Server := IniFile.ReadString('Centralita', 'Servidor', '');
  Hostkey := IniFile.ReadString('Centralita', 'Hostkey', '');
  User := IniFile.ReadString('Centralita', 'Usuario', 'root');
  Password := DecryptStr(IniFile.ReadString('Centralita', 'Password', ''), 223);
  RemotePath := IniFile.ReadString('Centralita', 'PathRemoto', '');
  IniFile.Free;
  while (RightStr(RemotePath, 1) = '\') or (RightStr(RemotePath, 1) = '/') do RemotePath := Copy(RemotePath, 1, Length(RemotePath) - 1);
  RemotePath := RemotePath + '/*.log';

  Path := TPath.Combine(TPath.GetDirectoryName(GetModuleName(HInstance)), 'SFTP');
  if not TDirectory.Exists(TPath.Combine(Path, 'files')) then TDirectory.CreateDirectory(TPath.Combine(Path, 'files'));
  Params := '/ini=null /command "open sftp://' + User + ':' + Password + '@' + Server + ' -hostkey=""' + Hostkey + '""" "option confirm off" "get -delete ' + RemotePath + ' files\*" "exit"';
  if SaveOutput then Params := Params + ' /log="' + Path + '\Log.txt" /loglevel=0';
  ExecAppWait('WinSCP.com', Params, Path, True);

  Result := Length(TDirectory.GetFiles(TPath.Combine(Path, 'Files'), '*.log')) > 0
end;

您的脚本不包含SSH主机密钥。由于您提供命令的方式很奇怪(输入重定向而不是
/script
/command
开关),WinSCP以交互模式启动。因此,它会提示主机密钥验证,并挂起

-hostkey
开关添加到
打开
命令。见:


和用于使WinSCP在任何问题上中止,而不是挂起

您还应该读取批处理文件输出,以便将来更好地处理错误

function TdmCentralita.DownloadLogs(SaveOutput: boolean = False): boolean;
var IniFile: TIniFile;
    Path, Params, User, Password, Server, Hostkey, RemotePath: string;
begin
  IniFile := TIniFile.Create(TPath.ChangeExtension(GetModuleName(HInstance), '.ini'));
  Server := IniFile.ReadString('Centralita', 'Servidor', '');
  Hostkey := IniFile.ReadString('Centralita', 'Hostkey', '');
  User := IniFile.ReadString('Centralita', 'Usuario', 'root');
  Password := DecryptStr(IniFile.ReadString('Centralita', 'Password', ''), 223);
  RemotePath := IniFile.ReadString('Centralita', 'PathRemoto', '');
  IniFile.Free;
  while (RightStr(RemotePath, 1) = '\') or (RightStr(RemotePath, 1) = '/') do RemotePath := Copy(RemotePath, 1, Length(RemotePath) - 1);
  RemotePath := RemotePath + '/*.log';

  Path := TPath.Combine(TPath.GetDirectoryName(GetModuleName(HInstance)), 'SFTP');
  if not TDirectory.Exists(TPath.Combine(Path, 'files')) then TDirectory.CreateDirectory(TPath.Combine(Path, 'files'));
  Params := '/ini=null /command "open sftp://' + User + ':' + Password + '@' + Server + ' -hostkey=""' + Hostkey + '""" "option confirm off" "get -delete ' + RemotePath + ' files\*" "exit"';
  if SaveOutput then Params := Params + ' /log="' + Path + '\Log.txt" /loglevel=0';
  ExecAppWait('WinSCP.com', Params, Path, True);

  Result := Length(TDirectory.GetFiles(TPath.Combine(Path, 'Files'), '*.log')) > 0
end;