Delphi is an object-oriented visual software development tool from Borland Company. Delphi combines the advantages of both Visual C++ and Visual Basic: easy to use, powerful, and has unique advantages especially in interface design, database programming, and network programming.
Messages in Delphi
A message is a notification sent by Windows that tells an application that an event has occurred. In Delphi, in most cases Windows messages are encapsulated in VCL events. We only need to handle the corresponding VCL events. However, if we need to write our own controls, intercept or filter messages, we must delve into Win32 Message processing mechanism.
In Delphi, messages are defined in the form of TMessage records. Open the Message.pas file, we can see that Tmessage is defined like this:
type
TMessage = packed record
Msg: Cardinal;
case Integer of
0: (WParam: Longint;
LParam: Longint;
Result: Longint);
1: (WParamLo: Word;
WParamHi: Word;
LParamLo: Word;
LParamHi: Word;
ResultLo: Word;
ResultHi: Word);
end;
Among them, Msg is a constant value that is different from other messages. These constant values can be predefined constants in Windows units or user-defined constants. Wparam is usually a constant value related to a message, or it can be a handle to a window or control. LParam is usually a pointer to data in memory.
Result is the return value of message processing. Wparam, Lparam and Result are all 32 bits. If you want to access the lower 16 bits or the upper 16 bits, you can use WparamLo, WparamHi, LParamLo, LparamHi, ResultLo and ResultHi respectively.
In addition to the general Tmessage, a special message record is defined for each Windows in Delphi. We can browse the Message.pas file, and here is the keyboard message record:
TWMKey = packed record
Msg: Cardinal;
CharCode: Word;
Unused: Word;
KeyData: Longint;
Result: Longint;
Keyboard-related messages such as: WM_KEYDOWN, WM_KEYUP, WM_CHAR, WM_SYSKEYDOWN, WM_SYSKEYUP, and WM_SYSCHAR records are also defined as TWMkey. There is the following statement in the Message.pas file:
TWMChar=TWMkey; TWMKeyDown=
TWMkey; TWMKeyUp=TWMkey; TWMSys
-KeyDown=TWMkey; TWMSysKeyUp=
TWMkey;TWMSysChar=TWMkey;
sending of messages
Message processing is to define how the application responds to Windows messages. In Delphi, each message has its own processing process. It must be a method in an object, and can only pass one Tmessage or other special message record. There must be a message command after the method declaration, followed by a message ranging from 0 to A constant between 32767.
The messages we mentioned earlier are all standard Windows messages (WM_X). In addition, there are VCL internal messages, notification messages and user-defined messages.
VCL internal messages usually start with "CM_" and are used to manage things inside the VCL. If you change a property value or some other characteristics of a component, you need to notify other components of the change through internal messages. For example, the activate input focus message is sent to an activated or deactivated component to accept or relinquish input focus.
There are also notification messages. Something happens to a child control in a window and the parent window needs to be notified. This is achieved through notification messages. It only works with standard window controls, such as buttons, list boxes, edit boxes, etc. Open the Message.pas file. After the standard Windows is the declaration of the notification message:
const
{$EXTERNALSYM BN_CLICKED}
BN_CLICKED = 0;
{$EXTERNALSYM BN_PAINT}
BN_PAINT = 1;
{$EXTERNALSYM BN_HILITE}
BN_HILITE = 2;
The above are the notification messages of the button, which respectively indicate that the user clicked the button, that the button should be redrawn, and that the user highlighted the button.
Users can also define their own messages, send messages to themselves and write message processing procedures. The constant value of the message is WM_USER+100 to $7FFF. This range is reserved by Windows for user-defined messages.
There are three methods for sending Delphi messages:
1. Perform object method of Tcontrol class. You can send messages to any form or control, you only need to know the instance of the form or control. Its statement is as follows:
function Tcontrol.Perform(Msg:Cardinal;Wparam,Lparam:Longint):Longint
2. Windows API functions SendMessage() and Postmessage(). Its statement is as follows:
function SendMessage(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
function SendMessage(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall
The PostMessage function adds a message to the application's message queue. The application's message loop will extract the registered message from the message queue and then send it to the corresponding window.
The SendMessage function can send messages directly to the window procedure across the message queue. So SendMessage is used when Windows needs to return a value immediately, and PostMessage is used when different applications need to process messages in sequence. Perform is essentially similar to SendMessage, they are sent directly to the window procedure. The SendMessage and Postmessage functions only need to know the handle of the window to send messages, so they can send a message to a non-Delphi form, but Perform must know the instance of the form or control.
VCL message processing mechanism
There is the statement application.Run in the source code of the Delphi application. Its function is to start the message loop and then call Application.PRocessMessage. This function will find a message in the application's message queue. When a message is retrieved from the message queue, the Application.OnMessage event is triggered. In this way, before Windows itself processes the message, it will respond to the processing of the OnMessage event. It is superior to any message processing and only receives registered messages, that is, the messages sent by PostMessage as mentioned above. The processing process that responds to the Application.OnMessage event must be of type TmessageEvent, which is declared as follows:
type TMessageEvent = procedure (var Msg: TMsg; var Handled: Boolean) of object;
Where TMsg is the message record defined in Windows, we can declare it like this:
Procedure OnMyMessage(var Msg:TMsg;var Handled:Boolean);
Then assign this method to the Application.OnMessage event:
Application.OnMessage :=OnMyMessage;
The OnMessage event will capture all messages sent to the application, which is a very busy event, so it is unwise to set breakpoints during the processing of the OnMessage event for message processing.
The method used by the VCL object to receive messages is called MainWndProc. It is a static method defined in the Twincontrol class and cannot be overloaded. It does not process the message directly. When the message leaves MainWndProc, the message is passed to the object's WndProc method. The WndProc method is a virtual method defined in the Tcontrol class, which calls the Dispatch method. Dispatch searches for the corresponding processing method based on the incoming Message. If it cannot find it in the end, it continues to search for the message processing method in the parent class until it is found. If it cannot find it, it calls Defaulthandler. The Defaulthandler method performs final processing on the message and then passes the message to the Windows DefWindowProc function or other default window procedures.