Saat menulis program, Anda selalu menghadapi masalah dengan komunikasi antara formulir (Tform) dan pesan utas (TTHREAD). Yang menjengkelkan adalah formulir tidak dapat mengirim pesan ke utas (TTHREAD) (utas tidak memiliki pegangan jendela). Setelah beberapa hari kerja keras, saya datang dengan dua solusi dan membawanya keluar untuk berdiskusi dengan Anda.
Pertama. Kami tahu bahwa Pustaka Kelas MFC di VC ++ telah merangkum pemrosesan pesan (BeginMessage, EndMessage) Tabel pemetaan (pemrosesan pesan pada dasarnya adalah panggilan ke metode atau proses), ditambah mekanisme distribusi pesan untuk mewujudkan penerimaan dan transmisi pesan <lihat VC ++ Technical Insider> untuk detailnya. Jadi kita hanya perlu membuat tabel pemetaan pesan untuk utas dan membuat mekanisme distribusi pesan yang sesuai. Ini memungkinkan Anda untuk memproses pesan yang dikirim oleh formulir ke utas. Kode berikut adalah kelas yang mengimplementasikan tabel pemetaan pesan dan distribusi pesan (lihat <../ Desain Pemrosesan Pesan (Thread) 1/MessageHandle.pas> untuk detailnya)
Unit MessageHandle;
antarmuka
menggunakan pesan, kelas, sysutils, dialog;
const PMSG_BASE = $ BE00; // Alamat Basis Pesan Kustom;
PMSG_NUM = 200;
{** kelas pemrosesan pesan khusus
*; Function = Buat tabel pesan khusus dan proses antar utas
* dan pesan khusus dengan formulir utama (makro)
*}
// pegangan pemrosesan pesan
TmessageHandle = Prosedur (pesan var: tmessage) objek;
Tpdispatcher = class (tobject)
Pribadi
// Pesan Tabel yang sesuai (ID pesan adalah subskrip array);
MessageHandles: Array of TMessageHandle;
// Dapatkan ID Array dari ID Pesan
fungsi getIndexFrommsgid (const amessageid: cardinal): integer;
publik
konstruktor membuat;
Destructor menghancurkan;
// Kirim pesan
Prosedur SendMessage (Pesan VAR: TMessage);
// tambahkan pesan khusus ke tabel yang sesuai pesan;
prosedur addhandle (const amessageid: cardinal; amessageHandle: tmessageHandle);
akhir;
//
Pelaksanaan
{Tpdispatcher}
konstruktor tpdispatcher.create;
Var I: Integer;
Mulai
SetLength (MessageHandles, PMSG_NUM);
// inisialisasi antrian pesan;
untuk i: = 0 ke pred (pmsg_num) lakukan
MessageHandles [i]: = nil;
akhir;
Destructor tpdispatcher.destroy;
Mulai
{Tabel korespondensi pesan rilis}
Freeandnil (pesan pesan);
akhir;
Prosedur tpdispatcher.addhandle (const amessageid: cardinal;
amessageHandle: tmessageHandle);
Var Tid: Integer;
Mulai
tid: = getIndexFrommsgid (amessageId);
Assert ((tid> 0) atau (tid <pred (pmsg_num)));
Assert (ditugaskan (amessageHandle));
MessageHandles [tid]: = amessageHandle;
akhir;
fungsi tpdispatcher.getIndexFrommsgid (const amessageid: cardinal): integer;
Mulai
Hasil: = amessageId - pmsg_base;
akhir;
Prosedur tpdispatcher.sendMessage (pesan var: tmessage);
Var Tid: Integer;
tmsghandle: tmessageHandle;
Mulai
tid: = getIndexFrommsgid (message.msg);
Assert ((tid> 0) atau (tid <pred (pmsg_num)));
TMSGHandle: = MessageHandles [tid];
Jika ditugaskan (tmsghandle) lalu
tmsghandle (pesan);
akhir;
Sekarang kita hanya perlu mendaftarkan pesan khusus dan kemudian menggunakan kelas distribusi pesan (TPDispatcher) untuk memproses pesan utas. Kode ini adalah sebagai berikut <lihat ../ Desain Pemrosesan Pesan (Thread) 1/test/unit1.pas> untuk detailnya:
Unit unit1
const
{Pesan utas jangka panjang khusus}
My_message2 = pmsg_base + 02;
jenis
Tform1 = class (tform)
AddMSglist: tbutton;
SendTheHead: Tbutton;
Sendform: tbutton;
Sendother: tbutton;
Prosedur SendTheadClick (Pengirim: Tobject); // Kirim pesan
Prosedur FormCreate (pengirim: Tobject);
Prosedur Formdestroy (pengirim: TOBJEK);
Pribadi
FDispatcher: TPDispatcher;
Fhandle: tphandler;
FThread: TpThread;
publik
{Deklarasi Publik}
akhir;
var
Form1: tform1;
Pelaksanaan
{$ R *.dfm}
Prosedur TFORM1.SendTheadClick (pengirim: TOBJEKS);
var amessage: tmessage;
amessage.msg: = my_message2;
amessage.wparam: = 1;
Fdispatcher.sendMessage (amessage);
akhir;
akhir;
Prosedur TFORM1.FORMCREATE (Pengirim: Tobject);
Mulai
{Buat kelas tabel peta pesan}
Fdispatcher: = tpdispatcher.create;
Fhandle: = tphandler.create;
{Buat utas}
FThread: = tpThread.create (false);
{Tambahkan pesan ke tabel pemetaan}
Fdispatcher.addhandle (my_message2, fthread.domessage);
akhir;
Prosedur TFORM1.FORMDESTROY (Pengirim: TOBJEKS);
Var I: Integer;
Mulai
Freeandnil (fdispatcher);
Freeandnil (fhandle);
untuk i: = 0 hingga 3 lakukan
Freeandnil (fThread [i]);
akhir;
Kedua. Jendela dapat menangani pesan karena memiliki pegangan jendela. Agar utas menangani pesan, kami dapat menambahkan pegangan jendela ke utas kelas jendela yang sesuai. (Kode sumber ada di <../ Desain Pemrosesan Pesan (Thread) 2 / pthread.pas>)
unit pthread;
antarmuka
menggunakan kelas, sysutils, windows, pesan, dialog;
const my_message1 = $ bd00 + 01;
Jenis
{** Kelas Thread Pemrosesan Pesan
*; Fungsi = tambahkan kemampuan pemrosesan utas,
*}
Tpmsgthread = class (tThread)
Pribadi
// pegangan jendela
Fwndhandle: hwnd;
// informasi data jendela
Fwndclass: wndclass;
// pointer ke fungsi panggilan balik jendela
FobjectInstance: pointer;
// Inisialisasi data jendela
prosedur initwnd;
// Buat jendela tersembunyi
Prosedur CreateWnd;
// Daftarkan Jendela Tersembunyi
Prosedur Registwnd;
Prosedur Destroywnd;
// Fungsi panggilan balik jendela
Prosedur PWNDPROC (Pesan VAR: TMessage);
terlindung
Prosedur Eksekusi;
Prosedur Doterminate;
publik
Konstruktor Create (CreatesUspended: Boolean);
Properti Wndhandle: hwnd baca fwndhandle tulis fwndhandle;
akhir;
Pelaksanaan
const wnd_name = 'py20';
{Tpmsgthread}
konstruktor tpmsgthread.create (createsUspensi: boolean);
Mulai
warisan create (createsUspended);
Fwndhandle: = integer (nil);
Initwnd;
Registwnd;
Createwnd;
akhir;
Prosedur tpmsgthread.createWnd;
Mulai
if (wndhandle = integer (nil)) kemudian
Wndhandle: = createWindow (fwndclass.lpszclassname, fwndclass.lpszclassname,
WS_POPUP atau WS_CAPTION atau WS_CLIPSIBLING atau WS_SYSMENU
atau ws_minimizebox,
GetSystemMetrics (sm_cxscreen) div 2,
GetSystemMetrics (sm_cyscreen) div 2,
0, 0, 0, 0, fwndclass.hinstance, nil);
// ganti fungsi panggilan balik jendela
SetWindowlong (wndhandle, gwl_wndproc, longint (fobjectInstance));
akhir;
Prosedur tpmsgthread.destroywnd;
Mulai
Unregisterclass (fwndclass.lpszclassname, fwndclass.hinstance);
DestroyWindow (wndhandle);
akhir;
Prosedur tpmsgthread.doterminate;
Mulai
diwariskan;
Hancur;
akhir;
Prosedur TPMSGTHREAD.EXECUTE;
Mulai
akhir;
Prosedur tpmsgthread.initwnd;
Mulai
Fwndclass.lpszclassname: = pchar (wnd_name);
Fwndclass.hinstance: = handle;
Fwndclass.lpfnwndProc: = @DefWindowProc;
akhir;
Prosedur tpmsgthread.pwndproc (pesan var: tmessage);
Mulai
akhir;
prosedur tpmsgthread.registwnd;
Mulai
FobjectInstance: = class.makeObjectInstance (pwndproc);
if (fwndclass.hinstance <> integer (nil)) kemudian
RegisterClass (FWNDClass);
akhir;