2013-05-08 5 views
0

Я хочу, чтобы отправить электронную почту в другом блоке с другим потоком с indy10.0.52 У меня есть исходный кодDelphi7 отправить электронную почту в другом потоке и блок

unit ThreadEmail; 

interface 

uses Classes, SysUtils, IdGlobal, IdMessage, IdIOHandler, IdIOHandlerSocket, 
    IdSSLOpenSSL, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, 
    IdMessageClient, IdSMTP, IdExplicitTLSClientServerBase, IdSMTPBase, 
    IdIOHandlerStack, IdSSL, ExtCtrls; 

type 
    TThreadEmail = class(TThread) 
    private 
    run  : boolean; 
    counter : Integer; 
    target : Integer; 
    IdSMTP: TIdSMTP; 
    IdSSLIOHandlerSocketOpenSSL: TIdSSLIOHandlerSocketOpenSSL; 
    Messages : Array [0..10] of TIdMessage; 
    procedure checkRun(); 
    protected 
    procedure Execute; override; 
    public 
    constructor Create(timerInS:Integer;host:string;port:integer;username,password:String;readTimeout : integer = 0);reintroduce; 
    function expressSend(recipients,subject,body:string;from:String='';replayTo:String='') :boolean; 
    function makeEmail(recipients,subject,body:string;from:String='';replayTo:String=''): boolean; 
    procedure SendAllEmail(); 
    end; 

implementation 

constructor TThreadEmail.Create(timerInS:Integer;host:string;port:integer;username,password:String;readTimeout : integer = 0); 
var b: byte; 
begin 
    inherited Create(False); 
    Priority:= tpNormal; 
    FreeOnTerminate:= True; 

    IdSMTP := TIdSMTP.Create; 
    IdSSLIOHandlerSocketOpenSSL := TIdSSLIOHandlerSocketOpenSSL.Create(); 
    for b:=low(Messages) to high(messages) do Messages[b] := nil; 

    IdSMTP.IOHandler := IdSSLIOHandlerSocketOpenSSL; 
    IdSMTP.UseTLS := utUseImplicitTLS; 
    IdSMTP.Host  := host; 
    IdSMTP.Port  := port; 
    IdSMTP.Username := username; 
    IdSMTP.Password := password; 

    IdSSLIOHandlerSocketOpenSSL.DefaultPort := 0; 
    IdSSLIOHandlerSocketOpenSSL.Destination := host+':'+inttostr(port); 
    IdSSLIOHandlerSocketOpenSSL.Host   := host; 
    IdSSLIOHandlerSocketOpenSSL.MaxLineAction := maException; 
    IdSSLIOHandlerSocketOpenSSL.Port   := port; 
    IdSSLIOHandlerSocketOpenSSL.ReadTimeout := readTimeout; 
    IdSSLIOHandlerSocketOpenSSL.SSLOptions.Method := sslvSSLv3; 
    IdSSLIOHandlerSocketOpenSSL.SSLOptions.Mode := sslmClient; 

    run:=true; 
    //target := timerInS*10; 
end; 

function TThreadEmail.expressSend(recipients,subject,body:string;from:String='';replayTo:String='') : boolean; 
var IdMessage: TIdMessage; 
begin 
    Result := false; 
    IdMessage := TIdMessage.Create(); 
    IdMessage.Recipients.EMailAddresses := recipients; 
    IdMessage.Subject := subject; 
    IdMessage.Body.Text := body; 
    if from <> '' then IdMessage.From.Address := from; 
    if replayTo <> '' then IdMessage.ReplyTo.EMailAddresses := from; 
    try 
    IdSMTP.Connect(); 
    IdSMTP.Send(IdMessage); 
    Result := true; 
    finally 
    IdSMTP.Disconnect(); 
    end; 
end; 

function TThreadEmail.makeEmail(recipients,subject,body:string;from:String='';replayTo:String='') : boolean; 
var b: byte; 
begin 
    Result := false; 
    for b:=low(Messages) to high(messages) do 
    if Messages[b] = nil then 
    begin 
     Result := true; 
     Messages[b]:= TIdMessage.Create(); 
     Messages[b].Recipients.EMailAddresses := recipients; 
     Messages[b].Subject := subject; 
     Messages[b].Body.Text := body; 
     if from <> '' then Messages[b].From.Address := from; 
     if replayTo <> '' then Messages[b].ReplyTo.EMailAddresses := from; 
    end; 
    if not(result) then 
    begin 
    SendAllEmail(); 
    makeEmail(recipients,subject,body,from,replayTo); 
    end; 
end; 

procedure TThreadEmail.SendAllEmail(); 
var b: byte; 
begin 
    try 
    IdSMTP.Connect(); 
    for b:=low(Messages) to high(messages) do 
     if run and (Messages[b] <> nil) then 
     begin 
     try 
      IdSMTP.Send(Messages[b]); 
     finally 
      Messages[b].Free; 
      Messages[b] := nil; 
     end 
     end; 
    finally 
     IdSMTP.Disconnect(); 
    end; 
end; 

procedure TThreadEmail.checkRun(); 
begin 
    Dec(counter); 
    if counter <= 0 then SendAllEmail(); 
end; 

procedure TThreadEmail.Execute; 
var b: byte; 
begin 
    while run do 
    begin 
    sleep(100); 
    checkRun(); 
    end; 
    IdSMTP.Free; 
    IdSSLIOHandlerSocketOpenSSL.Free; 
    for b:=low(Messages) to high(messages) do 
    if Messages[b] <> nil then Messages[b].Free; 
end; 

end. 

и mainfrom, что я создать

unit Unit1; 

interface 

uses 
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
    Dialogs, StdCtrls, ThreadEmail; 

type 
    TForm1 = class(TForm) 
    Button1: TButton; 
    procedure Button1Click(Sender: TObject); 
    private 
    { Private declarations } 
    public 
    { Public declarations } 
    end; 

var 
    Form1: TForm1; 
implementation 

{$R *.dfm} 


procedure TForm1.Button1Click(Sender: TObject); 
var ThreadEmail : TThreadEmail; 
begin 
    ThreadEmail := ThreadEmail.Create(10,'smtp.gmail.com',465,'xxx.gmail.com','xxx',2000); 
    ThreadEmail.expressSend('[email protected]','TES','TES'); 
end; 

Когда кнопка1 нажата, она всегда «создает ошибку нарушения прав доступа», почему это произошло? Может кто-нибудь мне помочь? как информация, я просил отправить электронное письмо раньше, но я хочу создать сингл-блок, который может работать один. благодаря

ответ

5
ThreadEmail := ThreadEmail.Create(10,'s.... 

это должно быть:

ThreadEmail := TThreadEmail.Create(10,'s.... 

Не уверен, что это просто опечатка? Это, безусловно, вызовет AV, если нет.


В любом случае ThreadEmail.expressSend не будет работать в вашем TThread «s нить так, как вы вызываете его. При запуске TThread код в своем методе Execute будет запускаться в отдельном потоке. Тем не менее, любой из методов публичных членов можно вызвать в экземпляре, как и общедоступные методы любого класса, и они выполняются в потоке, который их вызывает.

Для того чтобы это работало, необходимо, чтобы метод Execute выполнял вызовы для отправки сообщения электронной почты. Поток пользовательского интерфейса должен активировать действие в методе Execute и не выполнять самого действия; это может быть сделано любым количеством средств (с Execute синхронизировать с WaitForSingleObject, путем передачи сообщений и т. д.).

Остальная часть вашего кода выглядит довольно сломанной. Ваш Execute код на самом деле не будет работать, как это - этот цикл:

while run do 
begin 
    sleep(100); 
    checkRun(); 
end; 

никогда не прекращается, как это кажется, что вы не установите run к ложным в любом месте. Кроме того, counter, кажется, нигде не устанавливается (и я не понимаю его цели), поэтому это будет SendAllEmail() каждые 100 мс или около того.

Функция makeEmail никогда не прекратит (переполнение стека), поскольку она вызывает рекурсивно с исходными аргументами, а логика гарантирует повторную запись на каждом проходе. Это также выглядит, как он будет посылать какие бы то ни сообщение одиннадцать раз на каждую рекурсии (так как все 11 элементов Messages будут nil после инициализации и после каждого вызова SendAllEmail()

Даже если вы это исправить. - если вы звоните makeEmail извне (то есть: из пользовательского интерфейса или другого потока), то это, скорее всего, закончится всеми видами ошибок поперечного потока, так как оба Execute и вызывающий поток будут пытаться одновременно вызвать SendAllEmail. Этот код понадобится.