| 導購 | 订阅 | 在线投稿
分享
 
 
 

Delphi7 從子線程中發送消息到主線程觸發事件執行

來源:互聯網網民  2006-05-27 08:02:39  評論

在對數據庫的操作時,有時要用一個子線程來進行後台的數據操作。比如說數據備份,轉檔什麽的。在主窗口還能同是進行其它操作。而有時後台每處理一個數據文件,要向主窗口發送消息,讓主窗口實時顯示處理進度在窗口上(可視),同時進行日志處理等。我用的是下面的方法:

[1]用到的API函數:

RegisterWindowsMessage

----------------------

函數功能:該函數定義一個新的窗口消息,該消息確保在系統中是唯一的。返回的消息值可在調用函數SendMessage或PostMessage時使用。

function RegisterWindowMessage(lpString: PChar): UINT; stdcall;

SendNotifyMessage

----------------------

函數功能:該函數將指定的消息發送到一個窗口。

如果該窗口是由調用線程創建的;此函數爲該窗口調用窗口程序,

並等待窗口程序處理完消息後再返回。

如果該窗口是由不同的線程創建的,此函數將消息傳給該窗口程序,

並立即返回,不等待窗口程序處理完消息。

SendNotifyMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam);

BroadcastSystemMessage

----------------------

函數功能:該函數發送消息給指定的接受者。

接受者可以是一個應用程序、安裝驅動器、網絡驅動器、系統級設備驅動器

或這些系統組件的組合。

[2]過程:

type

TForm1 = class(TForm)

...............

...............

private

Msg: Cardinal;

protected

procedure WndProc(var Message: TMessage); override;

public

...............

...............

end;

var

Form1: TForm1;

MsgStrList: TStringList;

MsgStrLock : TCriticalSection;

implementation

uses ThreadCommunication_Unit;

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);

begin

Msg := RegisterWindowMessage('wm_threadmsg');

MsgStrList := TStringList.Create;

end;

procedure TForm1.WndProc(var Message: TMessage);

begin

if Message.Msg = Msg then begin

MsgStrLock.Enter;

if MsgStrList.Count > 0 then begin

Caption := MsgStrList.Strings[0];

MsgStrList.Delete(0);

end;

MsgStrLock.Leave;

ShowMessage('收到消息了'+ inttostr(Message.Msg));

end

else begin

inherited;

end;

end;

procedure TForm1.Button1Click(Sender: TObject);

begin

TThreadCommunication.Create(Msg,Memo1);

end;

...............

...............

initialization

MsgStrLock := TCriticalSection.Create;

finalization

MsgStrLock.Free;

end.

一個子線程類的單元:

unit ThreadCommunication_Unit;

interface

uses

Classes,StdCtrls;

type

TThreadCommunicaiton = class(TThread)

private

FMsg : Cardinal;

FMemo: TMemo;

protected

procedure Execute; override;

procedure SendMsg;

public

constructor Create(aMsg:Cardinal;am:TMemo);virtual;

end;

implementation

uses Messages,Windows, Dialogs,SysUtils, ThreadMsg;

{ TThreadCommunicaiton }

constructor TThreadCommunicaiton.Create(aMsg: Cardinal; am:TMemo);

begin

inherited Create(True);

FMsg := aMsg;

FMemo:= am;

FreeOnTerminate :=True;

Resume;

end;

procedure TThreadCommunicaiton.Execute;

begin

Synchronize(SendMsg);

end;

procedure TThreadCommunicaiton.SendMsg;

var

M: TMessage;

B: DWord;

d: integer;

begin

{ Place thread code here }

sleep(50);

M.Msg := FMsg;

B := BSM_ALLCOMPONENTS;

MsgStrLock.Enter;

MsgStrList.Add('子線程子柄:'+inttostr(ThreadID)+ ' 用BroadcastSystemMessage發送');

d := MsgStrList.Count;

MsgStrLock.Leave;

BroadcastSystemMessage(BSF_POSTMESSAGE, @B , M.Msg, M.WParam, M.LParam );

FMemo.Lines.Add('子線程子柄:'+inttostr(ThreadID)+ ' 用BroadcastSystemMessage發送'+inttostr(d));

end;

end.

我在窗口上放有一Memo控件,可以顯示一些信息。

同時我定義了一個全局的TStringList的變量,用于存在要從子線程傳出的一些值。用BroadcaseSystemMessage發送消息,而消息號由創建子線程時傳入。而消息號在FormCreate中用RegisterWindowsMessage定義,並獲得一個消息號。

而消息觸發後的事件處理寫在WndProc中。

這裏將子線程傳出的字符串寫入窗口的標題。

而TStringList的變量作爲臨界區使用, 因爲當兩個線程訪問全局量時,爲防止它們同時執行,需要使用線程同步。

用TCriticalSection進行操作。

Enter,進入臨界區

Leave,離開臨界區

這樣可以正確的處理從子線程發來的消息。

如果是用SendNotifyMessage函數發送消息的話。

用法如下:

M.Msg := FMsg;

SendNotifyMessage(HWND_BROADCAST,M.Msg , M.WParam, M.LParam);

參數爲HWND_BROADCAST,則消息將被發送到系統中所有頂層窗口,包括無效或不可見的非自身擁有的窗口、被覆蓋的窗口和彈出式窗口,但消息不被發送到子窗口。

由于是用SendNotifyMessage將消息發送到主窗口,而主窗口所在線程與調用線程是同一個線程,所以要等待窗口程序處理完消息後再返回。才會執行子線程中的:

FMemo.Lines.Add('子線程子柄:'+inttostr(ThreadID)+ ' 用SendNotifyMessage發送');

 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
在對數據庫的操作時,有時要用一個子線程來進行後台的數據操作。比如說數據備份,轉檔什麽的。在主窗口還能同是進行其它操作。而有時後台每處理一個數據文件,要向主窗口發送消息,讓主窗口實時顯示處理進度在窗口上(可視),同時進行日志處理等。我用的是下面的方法: [1]用到的API函數: RegisterWindowsMessage ---------------------- 函數功能:該函數定義一個新的窗口消息,該消息確保在系統中是唯一的。返回的消息值可在調用函數SendMessage或PostMessage時使用。 function RegisterWindowMessage(lpString: PChar): UINT; stdcall; SendNotifyMessage ---------------------- 函數功能:該函數將指定的消息發送到一個窗口。 如果該窗口是由調用線程創建的;此函數爲該窗口調用窗口程序, 並等待窗口程序處理完消息後再返回。 如果該窗口是由不同的線程創建的,此函數將消息傳給該窗口程序, 並立即返回,不等待窗口程序處理完消息。 SendNotifyMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam); BroadcastSystemMessage ---------------------- 函數功能:該函數發送消息給指定的接受者。 接受者可以是一個應用程序、安裝驅動器、網絡驅動器、系統級設備驅動器 或這些系統組件的組合。 [2]過程: type TForm1 = class(TForm) ............... ............... private Msg: Cardinal; protected procedure WndProc(var Message: TMessage); override; public ............... ............... end; var Form1: TForm1; MsgStrList: TStringList; MsgStrLock : TCriticalSection; implementation uses ThreadCommunication_Unit; {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); begin Msg := RegisterWindowMessage('wm_threadmsg'); MsgStrList := TStringList.Create; end; procedure TForm1.WndProc(var Message: TMessage); begin if Message.Msg = Msg then begin MsgStrLock.Enter; if MsgStrList.Count > 0 then begin Caption := MsgStrList.Strings[0]; MsgStrList.Delete(0); end; MsgStrLock.Leave; ShowMessage('收到消息了'+ inttostr(Message.Msg)); end else begin inherited; end; end; procedure TForm1.Button1Click(Sender: TObject); begin TThreadCommunication.Create(Msg,Memo1); end; ............... ............... initialization MsgStrLock := TCriticalSection.Create; finalization MsgStrLock.Free; end. 一個子線程類的單元: unit ThreadCommunication_Unit; interface uses Classes,StdCtrls; type TThreadCommunicaiton = class(TThread) private FMsg : Cardinal; FMemo: TMemo; protected procedure Execute; override; procedure SendMsg; public constructor Create(aMsg:Cardinal;am:TMemo);virtual; end; implementation uses Messages,Windows, Dialogs,SysUtils, ThreadMsg; { TThreadCommunicaiton } constructor TThreadCommunicaiton.Create(aMsg: Cardinal; am:TMemo); begin inherited Create(True); FMsg := aMsg; FMemo:= am; FreeOnTerminate :=True; Resume; end; procedure TThreadCommunicaiton.Execute; begin Synchronize(SendMsg); end; procedure TThreadCommunicaiton.SendMsg; var M: TMessage; B: DWord; d: integer; begin { Place thread code here } sleep(50); M.Msg := FMsg; B := BSM_ALLCOMPONENTS; MsgStrLock.Enter; MsgStrList.Add('子線程子柄:'+inttostr(ThreadID)+ ' 用BroadcastSystemMessage發送'); d := MsgStrList.Count; MsgStrLock.Leave; BroadcastSystemMessage(BSF_POSTMESSAGE, @B , M.Msg, M.WParam, M.LParam ); FMemo.Lines.Add('子線程子柄:'+inttostr(ThreadID)+ ' 用BroadcastSystemMessage發送'+inttostr(d)); end; end. 我在窗口上放有一Memo控件,可以顯示一些信息。 同時我定義了一個全局的TStringList的變量,用于存在要從子線程傳出的一些值。用BroadcaseSystemMessage發送消息,而消息號由創建子線程時傳入。而消息號在FormCreate中用RegisterWindowsMessage定義,並獲得一個消息號。 而消息觸發後的事件處理寫在WndProc中。 這裏將子線程傳出的字符串寫入窗口的標題。 而TStringList的變量作爲臨界區使用, 因爲當兩個線程訪問全局量時,爲防止它們同時執行,需要使用線程同步。 用TCriticalSection進行操作。 Enter,進入臨界區 Leave,離開臨界區 這樣可以正確的處理從子線程發來的消息。 如果是用SendNotifyMessage函數發送消息的話。 用法如下: M.Msg := FMsg; SendNotifyMessage(HWND_BROADCAST,M.Msg , M.WParam, M.LParam); 參數爲HWND_BROADCAST,則消息將被發送到系統中所有頂層窗口,包括無效或不可見的非自身擁有的窗口、被覆蓋的窗口和彈出式窗口,但消息不被發送到子窗口。 由于是用SendNotifyMessage將消息發送到主窗口,而主窗口所在線程與調用線程是同一個線程,所以要等待窗口程序處理完消息後再返回。才會執行子線程中的: FMemo.Lines.Add('子線程子柄:'+inttostr(ThreadID)+ ' 用SendNotifyMessage發送');
󰈣󰈤
王朝萬家燈火計劃
期待原創作者加盟
 
 
 
>>返回首頁<<
 
 
 
 
 
 熱帖排行
 
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有