Problema com Thread

14/03/2013

12

Olá...

Tenho uma Thread em minha aplicação que faz envio de Email!
porem esta Thread usa os componentes que estão na tela que chamou a Thread!
o problema esta na seguinte situação:
da minha tela principal chamo o método da Thread varias vezes, pois o cliente vai clicando em enviar Email e o sistema vai chamando a Thread para enviar o Email...
ou seja, varias instancias ficam tentando enviar o Email!

quando meu cliente fecha a tela principal, todos os emails que ainda não foram enviados pois a Thread ainda não terminou a execução não serão enviados!
preciso impedir meu cliente de fechar a tela principal enquanto todas as threads não terminarem suas execuções!




aqui esta o código da minha Thread:
unit Thread;

interface

uses
  Classes, spdNFe, ActiveX, FatNFE, clipbrd, SysUtils;

type
  Enviaemail = class(TThread)
  private
     Nfeenvia: TspdNFe;
    { Private declarations }
  protected
    procedure Execute; override;
  public
    constructor enviar(Nfe: TspdNFe; SID_nota, SID_Numero : String);
  end;

var
  SIdentificador, SNumero : string;

implementation

{ Enviaemail }

constructor Enviaemail.enviar(Nfe: TspdNFe; SID_nota, SID_Numero : String);
begin
  Create(False);
  Nfeenvia := Nfe;
  SIdentificador := SID_nota;
  SNumero        := SID_Numero;
  FreeOnTerminate := True;
  WaitFor;
end;

procedure Enviaemail.Execute;
begin
  CoInitialize(nil);
  Try
     Nfeenvia.EnviarNotaDestinatario(SIdentificador);
     Form_NFe.RzStatusPane_Informa.Caption := 'Email da Nota: '+SNumero+' enviado com sucesso  ';
     Form_NFe.RzRichEdit_LogEmail.Lines.Add('Email da Nota: '+SNumero+' enviado com sucesso  ');
     //FatNFE.SStatus := 'Enviado com Sucesso';
  Except
    on E: Exception do
    begin
      Form_NFe.RzStatusPane_Informa.Caption := 'Erro ao enviar o Email da Nota: '+SNumero+'  ';
      Form_NFe.RzRichEdit_LogEmail.Lines.Add('Erro ao enviar o Email da Nota: '+SNumero+'  ');
      Form_NFe.RzStatusPane_Informa.Blinking := True;
      //FatNFE.SStatus := 'Erro ao enviar nota';
      Clipboard.AsText := E.message;
    end;
  end;
  { Place thread code here }
end;

end.




Aqui esta a chamada:
procedure TForm_NFE.vClick(Sender: TObject);
var
  email : EnviaEmail;
begin
  try
    email := EnviaEmail.enviar(NFe, Q_Notas_Prontasid_a03.AsString, Q_Notas_Prontasnnf_b08.AsString);
  except
    on E: Exception do
      begin
        ShowMessage('Atenção: Falha no Email.' +
                     #13 + E.Message);
        raise;
      end;
  end;
end;



Alguma sugestão?
Responder

Post mais votado

14/03/2013

É complicado, pois você vai criando uma thread para cara click. Eu utilizo threads de uma forma totalmente diferente, não fecho ela nunca durante a aplicação.
Você poderia utilizar uma especie de contador, que a cada thread criada, adicione um neste contador. No momento em que envia o email, diminui um.
Na tentativa de fechar o form, você verifica se este contador é maior que zero.
É só uma ideia...
Responder

Mais Posts

14/03/2013

Luiz Menin

Você deve utilizar o método Synchronize.
Dê uma olhada neste artigo: http://www.planetadelphi.com.br/dica/6353/construindo-threads-com-delphi
Responder
Olá.

Bom para impedir o fechamento do FORM utilize o evento OnCloseQuery do FORM, fazendo uso da variavel CanClose.

Exemplo disponivel em Planeta Delphi >
[url]http://www.planetadelphi.com.br/dica/4179/impedir-que-o-form-seja-fechado-com-alt+f4[/url]

Assim voce so deixara CanClose = true caso nao exista nenhum Thread em execução.

Para isso implemente algum tipo de controle, como um contador, etc.

Espero que ajude.
Responder

14/03/2013

Km Sistemas

Você deve utilizar o método Synchronize.
Dê uma olhada neste artigo: http://www.planetadelphi.com.br/dica/6353/construindo-threads-com-delphi



Alterei o código da Thread para ficar da seguinte forma:

unit Thread;

interface

uses
  Classes, spdNFe, ActiveX, FatNFE, clipbrd, SysUtils;

type
  Enviaemail = class(TThread)
  private
     Nfeenvia: TspdNFe;
     msg: String;
    { Private declarations }
  protected
    procedure Execute; override;
    procedure IncLabel; virtual;
  public
    constructor enviar(Nfe: TspdNFe; SID_nota, SID_Numero : String);
  end;

var
  SIdentificador, SNumero : string;

implementation

{ Important: Methods and properties of objects in visual components can only be
  used in a method called using Synchronize, for example,

      Synchronize(UpdateCaption);

  and UpdateCaption could look like,

    procedure Enviaemail.UpdateCaption;
    begin
      Form1.Caption := 'Updated in a thread';
    end; }

{ Enviaemail }

constructor Enviaemail.enviar(Nfe: TspdNFe; SID_nota, SID_Numero : String);
begin
  Create(False);
  Nfeenvia := Nfe;
  SIdentificador := SID_nota;
  SNumero        := SID_Numero;
  FreeOnTerminate := True;
end;

procedure Enviaemail.Execute;
begin
  CoInitialize(nil);
  Try
     Nfeenvia.EnviarNotaDestinatario(SIdentificador);
     msg := 'Email da Nota: '+SNumero+' enviado com sucesso  ';
     Synchronize(IncLabel);
     //Form_NFe.RzStatusPane_Informa.Caption := 'Email da Nota: '+SNumero+' enviado com sucesso  ';
     //Form_NFe.RzRichEdit_LogEmail.Lines.Add('Email da Nota: '+SNumero+' enviado com sucesso  ');
  Except
    on E: Exception do
    begin
      msg := 'Erro ao enviar o Email da Nota: '+SNumero+'  ';
      //Form_NFe.RzStatusPane_Informa.Caption := 'Erro ao enviar o Email da Nota: '+SNumero+'  ';
      //Form_NFe.RzRichEdit_LogEmail.Lines.Add('Erro ao enviar o Email da Nota: '+SNumero+'  ');
      Form_NFe.RzStatusPane_Informa.Blinking := True;
      Clipboard.AsText := E.message;
    end;
  end;
  { Place thread code here }
end;

procedure Enviaemail.IncLabel;
begin
   Form_NFe.RzStatusPane_Informa.Caption := msg;
   Form_NFe.RzRichEdit_LogEmail.Lines.Add(msg);
  { o Contador será executado em modo protegido por uma Seção Critica do Windows}
end;

end.


Porém ainda continua fechando a tela sem terminar de enviar os Email's!
Como faço para verificar se ainda tem alguma Thread sendo executada?
Responder

14/03/2013

Km Sistemas

Olá.

Bom para impedir o fechamento do FORM utilize o evento OnCloseQuery do FORM, fazendo uso da variavel CanClose.

Exemplo disponivel em Planeta Delphi >
[url]http://www.planetadelphi.com.br/dica/4179/impedir-que-o-form-seja-fechado-com-alt+f4[/url]

Assim voce so deixara CanClose = true caso nao exista nenhum Thread em execução.

Para isso implemente algum tipo de controle, como um contador, etc.

Espero que ajude.


Com relação a impedir a form de fechar ta tranquilo... o problema é saber quando pode fechar?
Ou seja, todas as instancias da Thread já terminaram sua execução...
Responder
De forma simples, acredito que você terá que fazer uso de uma fila.
Responder
Para esta tarefa eu criaria um robô, usando uma fila. Para cada NF-e autorizada ele processaria o envio do email.

Responder

14/03/2013

Km Sistemas

É complicado, pois você vai criando uma thread para cara click. Eu utilizo threads de uma forma totalmente diferente, não fecho ela nunca durante a aplicação.
Você poderia utilizar uma especie de contador, que a cada thread criada, adicione um neste contador. No momento em que envia o email, diminui um.
Na tentativa de fechar o form, você verifica se este contador é maior que zero.
É só uma ideia...


Essa ideia parece ser simples de implementar! Vou tentar fazer desta forma!
Responder

14/03/2013

Luiz Menin

Fico no aguardo do resultado.
Responder

18/11/2015

Km Sistemas

Eu sei que já faz um bom tempo mas apenas para manter documentado a solução proposta pelo Luiz Antônio Menin resolveu meu problema!
Incrementando uma variável e cada nova instancia e decrementando no termino da execução...
Grato!
Responder

18/11/2015

Luiz Menin

Eu sei que já faz um bom tempo mas apenas para manter documentado a solução proposta pelo Luiz Antônio Menin resolveu meu problema!
Incrementando uma variável e cada nova instancia e decrementando no termino da execução...
Grato!


Fico feliz pelo feedback e por você ter conseguido resolver!
Obrigado.
Responder