How to execute a procedure only when the previous procedure is finished?

1

I have 2 procedures, one compiles the file and the other sends the file to FTP, but the upload procedure is running concurrently with the compression procedure, and tries to send the file before the compression finishes. >

procedure TForm2.compactacao;
var
  sNomeArquivoCompactado, sDiretorioCompactar: string;
begin

  sNomeArquivoCompactado := ObterDiretorioDoExecutavel + 'setup/lib.7z';
  sDiretorioCompactar := ObterDiretorioDoExecutavel + 'bin\*';

  try
      ShellExecute(0, nil, '7z.exe',
      PWideChar(' a -r ' + sNomeArquivoCompactado + ' ' + sDiretorioCompactar),' ', SW_SHOW);


  except
    On E: Exception do
    begin


      ShowMessage('Erro ao compactar: ' + E.Message);

      // interrompe a compactacao
      Abort;
    end;
  end;
  log('Fim da compactação do arquivo de atualização');

end;




procedure TForm2.enviarArquivo;
begin

try        
if ConectarServidorFTP = True then
    IdFTP.Put(ObterDiretorioDoExecutavel+ 'setup\lib.7z','',False);
except
    On E: Exception do
    begin
      // ignora a exceção "Connection Closed Gracefully"
      if E is EIdFTPException then
        Exit;

      ShowMessage('Erro no upload : ' + E.Message);

      // interrompe a atualização
      Abort;
    end;
end;
end;
    
asked by anonymous 24.09.2018 / 23:25

1 answer

5

This problem happens because you are using the shell run, this only calls the third application, but does not wait for the end of its completion. I see two solutions to your problem:

1) If you use a newer version of delphi you can use the class System.Zip.TZipFile , so you can do the entire compaction process in your own application without relying on third-party tools. Ex:

var
  ArquivoCompactado: TZipFile;
begin
  ArquivoCompactado := TZipFile.Create;
  try
    ArquivoCompactado.Open(vArquivoZip, zmWrite); //Cria arquivo zip
    ArquivoCompactado.add(vSeuArquivo); // adiciona arquivo no zip, para diretórios utilizar o método TZipFile.ZipDirectoryContents
  finally
    FreeAndNil(ArquivoCompactado);
  end;
end;

2) If you are required to use a third-party tool for compression, you must use the CreateProcess method that creates a process and gets its handle address, so you can monitor if it is still running with the WaitForSingleObject method. Below is the example of using these procedures, this was taken from the question How can I wait until an external process has completed? , I have already used it in my application for a few years without problem.

procedure ExecuteAndWait(const aCommando: string);
var
  tmpStartupInfo: TStartupInfo;
  tmpProcessInformation: TProcessInformation;
  tmpProgram: String;
begin
  tmpProgram := trim(aCommando);
  FillChar(tmpStartupInfo, SizeOf(tmpStartupInfo), 0);
  with tmpStartupInfo do
  begin
    cb := SizeOf(TStartupInfo);
    wShowWindow := SW_HIDE;
  end;

  if CreateProcess(nil, pchar(tmpProgram), nil, nil, true, CREATE_NO_WINDOW,
    nil, nil, tmpStartupInfo, tmpProcessInformation) then
  begin
    // loop every 10 ms
    while WaitForSingleObject(tmpProcessInformation.hProcess, 10) > 0 do
    begin
      Application.ProcessMessages;
    end;
    CloseHandle(tmpProcessInformation.hProcess);
    CloseHandle(tmpProcessInformation.hThread);
  end
  else
  begin
    RaiseLastOSError;
  end;
end;
    
25.09.2018 / 13:40