2013-05-08 204 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運行的線程您呼叫的方式。當您運行TThread時,其Execute方法中的代碼將在單獨的線程中運行。但是,任何公共成員方法都可以在實例上調用,就像任何類的公共方法一樣,並且它們在調用它們的線程上執行。

爲了讓這個工作,你需要有Execute方法執行調用來發送電子郵件。 UI線程需要在Execute方法中觸發操作,而不是執行操作本身;這可以通過許多方式完成(具有ExecuteWaitForSingleObject同步,通過消息傳遞等)。

其餘的代碼看起來相當破碎。你Execute代碼是不是真的要工作,因爲它是 - 這個循環:

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

不會終止,因爲它似乎你不設置run假的任何地方。此外,counter似乎沒有設置任何地方(我也沒有真正瞭解它的目的),所以這將只是SendAllEmail()每隔100毫秒左右。

makeEmail函數將永遠不會終止(堆棧溢出),因爲它使用原始參數遞歸調用自身,並且邏輯保證每次傳遞都會重新輸入。它也像它會發送任何消息十週一次每個遞歸(因爲Messages所有11個元素將初始化後每次調用SendAllEmail()nil

即使你解決這個問題 - 如果你在外部調用makeEmail(即:從UI或另一個線程),那麼這可能最終會出現各種交叉線程錯誤,因爲Execute和調用線程將嘗試同時調用SendAllEmail。此代碼需要一些工作。

相關問題