プログラムを作成するとき、フォーム(TFORM)とスレッド(TTHREAD)メッセージとの間の通信に関する問題に常に遭遇します。面倒なのは、フォームがスレッド(tthread)にメッセージを送信できないことです(スレッドにはウィンドウハンドルがありません)。数日間のハードワークの後、私は2つの解決策を思いつき、それらを取り出してあなたと話し合いました。
初め。 VC ++のMFCクラスライブラリには、MFCの処理は、メッセージマッピングテーブルを確立することにより、メソッド(関数)または手順(手順)を保存することですマッピングテーブル(メッセージ処理は基本的にメソッドまたはプロセスへの呼び出しです)に加えて、メッセージの受信と送信を実現するためのメッセージ配信メカニズム<VC ++ Technical Insider>を参照してください。そのため、スレッドのメッセージマッピングテーブルを確立し、対応するメッセージ配布メカニズムを確立する必要があります。これにより、フォームで送信されたメッセージをスレッドに処理できます。次のコードは、メッセージマッピングテーブルとメッセージの配布を実装するクラスです(詳細については、<../メッセージ処理デザイン(スレッド)1/messagehandle.pas>を参照)
ユニットメッセージハンドル;
インタフェース
メッセージ、クラス、sysutils、ダイアログを使用します。
const pmsg_base = $ be00; //カスタムメッセージベースアドレス。
PMSG_NUM = 200;
{**カスタムメッセージ処理クラス
*; function =スレッド間でカスタムメッセージテーブルとプロセスを作成する
*メインフォーム(マクロ)のカスタムメッセージ
*}
//メッセージ処理ハンドル
tmessagehandle = Objectの手順(varメッセージ:tmessage);
tpdispatcher = class(tobject)
プライベート
//対応するテーブル(メッセージIDは配列subscript);
メッセージハンドル:tmessagehandleの配列。
//メッセージIDから配列IDを取得します
関数getIndexFrommSGID(const amessageid:cardinal):整数;
公共
コンストラクターCREATE;
デストラクタは破壊します。
//メッセージを送信します
手順sendmessage(varメッセージ:tmessage);
//対応するテーブルにメッセージをメッセージに追加します。
手順Addhandle(const amessageid:cardinal; amessagehandle:tmessagehandle);
終わり;
//
実装
{tpdispatcher}
コンストラクターtpdispatcher.create;
var i:整数;
始める
setLength(messagehandles、pmsg_num); //メッセージの対応テーブル
//メッセージキューを初期化します。
i:= 0 to pred(pmsg_num)はします
messagehandles [i]:= nil;
終わり;
Destructor tpdispatcher.destroy;
始める
{メッセージ通信テーブルをリリース}
freeandnil(messagehandles);
終わり;
手順tpdispatcher.addhandle(const amessageid:cardinal;
amessagehandle:tmessagehandle);
var tid:整数;
始める
TID:= getIndexFrommsGid(AmessageId);
assert((tid> 0)または(tid <pred(pmsg_num)));
assert(assigned(amessagehandle));
messagehandles [tid]:= amessagehandle;
終わり;
関数tpdispatcher.getIndexFrommSgid(const amessageid:cardinal):integer;
始める
結果:= amessageid -pmsg_base;
終わり;
手順tpdispatcher.sendmessage(var message:tmessage);
var tid:整数;
tmsghandle:tmessagehandle;
始める
TID:= getIndExFromMSGID(message.msg);
assert((tid> 0)または(tid <pred(pmsg_num)));
tmsghandle:= messagehandles [tid];
割り当てられている場合(tmsghandle)
tmsghandle(メッセージ);
終わり;
これで、カスタムメッセージを登録してから、メッセージ配布クラス(TPDISPatcher)を使用してスレッドメッセージを処理するだけです。コードは次のとおりです。
ユニットユニット1
const
{カスタムの長期スレッドメッセージ}
my_message2 = pmsg_base + 02;
タイプ
tform1 = class(tform)
addmsglist:tbutton;
Sendthehead:Tbutton;
Sendform:Tbutton;
送信者:Tbutton;
手順SendTheAdClick(送信者:tobject);
手順formcreate(sender:tobject);
手順formdestroy(送信者:tobject);
プライベート
fdispatcher:tpdispatcher;
ファンドル:Tphandler;
fthread:tpthread
公共
{公開宣言}
終わり;
var
form1:tform1;
実装
{$ r *.dfm}
手順tform1.sendtheadclick(sender:tobject);
var Amessage:tmessage;
amessage.msg:= my_message2;
amessage.wparam:= 1;
fdispatcher.sendmessage(amessage);
終わり;
終わり;
手順tform1.formcreate(sender:tobject);
始める
{メッセージマップテーブルクラスを作成}
fdispatcher:= tpdispatcher.create;
fhandle:= tphandler.create;
{スレッドを作成}
fthread:= tpthread.create(false);
{マッピングテーブルにメッセージを追加}
fdispatcher.addhandle(my_message2、fthread.domessage);
終わり;
手順tform1.formdestroy(sender:tobject);
var i:整数;
始める
Freeandnil(fdispatcher);
Freeandnil(fhandle);
i:= 0から3
freeandnil(fthread [i]);
終わり;
2番。ウィンドウには、ウィンドウハンドルがあるため、メッセージを処理できます。スレッドがメッセージを処理するために、対応するウィンドウクラスのスレッドにウィンドウハンドルを追加できます。 (ソースコードは<../メッセージ処理設計(スレッド)2 / pthread.pas>)にあります)
ユニットpthread;
インタフェース
クラス、sysutils、windows、メッセージ、ダイアログを使用します。
const my_message1 = $ bd00 + 01;
タイプ
{**メッセージ処理スレッドクラス
*; function =スレッド処理機能を追加します、
*}
tpmsgthread = class(tthread)
プライベート
//ウィンドウハンドル
fwndhandle:hwnd;
//ウィンドウデータ情報
fwndclass:wndclass;
//ウィンドウコールバック関数へのポインター
fobjectInstance:ポインター;
//ウィンドウデータを初期化します
手順initwnd;
//非表示のウィンドウを作成します
手順Createwnd;
//非表示ウィンドウを登録します
手順RegistWnd;
手順DestroyWnd;
//ウィンドウコールバック関数
手順pwndproc(varメッセージ:tmessage);
保護されています
手順実行;
手順Doterminate;
公共
Constructor create(createSpended:boolean);
プロパティwndhandle:hwnd read fwndhandle write fwndhandle;
終わり;
実装
const wnd_name = 'py20';
{tpmsgthread}
constructor tpmsgthread.create(createSuspended:boolean);
始める
継承されたcreate(createSuspended);
fwndhandle:= integer(nil);
initwnd;
registwnd;
createwnd;
終わり;
手順tpmsgthread.createwnd;
始める
if(wndhandle = integer(nil))then
wndhandle:= createwindow(fwndclass.lpszclassname、fwndclass.lpszclassname、
ws_popupまたはws_captionまたはws_clipsiblingsまたはws_sysmenu
またはws_minimizebox、
getsystemmetrics(sm_cxscreen)div 2、
getsystemmetrics(sm_cyscreen)div 2、
0、0、0、0、fwndclass.hinstance、nil);
//ウィンドウコールバック関数を交換します
SetWindowlong(wndhandle、gwl_wndproc、longint(fobjectinstance));
終わり;
手順tpmsgthread.destroywnd;
始める
unregisterclass(fwndclass.lpszclassname、fwndclass.hinstance);
DestroyWindow(wndhandle);
終わり;
手順tpmsgthread.doterminate;
始める
継承;
DestroyWnd;
終わり;
手順tpmsgthread.execute;
始める
終わり;
手順tpmsgthread.initwnd;
始める
fwndclass.lpszclassname:= pchar(wnd_name);
fwndclass.hinstance:= handle;
fwndclass.lpfnwndproc:= @defwindowproc;
終わり;
手順tpmsgthread.pwndproc(var message:tmessage);
始める
終わり;
手順tpmsgthread.registwnd;
始める
fobjectInstance:= classes.makeObjectInstance(pwndproc);
if(fwndclass.hinstance <> integer(nil))then
RegisterClass(fwndclass);
終わり;