Delphi is a new Windows programming development tool provided by Borland Corporation. Thanks to its resilient and reusable object-oriented Pascal (object-orientedpascal) language, it has a powerful database engine (BDE), Fast code compiler, and a host of excellent artifacts. By the vast number of programmers of all ages. Stand out in a multitude of programming languages, such as Vb,powerbuilder,powerpoint. One of the areas where Delphi is stronger than other programming languages (such as VB4.0) is the ability to customize messages in Delphi and to process messages directly. This is for those who want to write their own artifacts (Component), or want to intercept. The user who filters the message is essential. Because writing artifacts is typically done with the corresponding messages. The following is an introduction to the message processing mechanism in Delphi.
One. Delivery of messages in DELPHIVCL
Each of the VCL (Visualcomponentlibrary) components in Delphi (such as Tbutton,tedit, etc.) has an intrinsic message processing mechanism, the basic point of which is that the component class receives some messages and sends them to the appropriate processing methods. If there is no specific processing method, the default message handling handle is called.
Where Mainwndproc is a static method defined in the Twincontrol class and cannot be overloaded (override). Instead of processing the message directly, it is referred to the WndProc method and provides an exception handling module for the WndProc method. The Mainwndproc method declaration is as follows:
Procedure Mainwndproc (varmessage:tmessage);
WndProc is a virtual method defined in the Tcontrol class that calls the dispatch method for the distribution of messages, and the WndProc method declares the following:
Procedure WndProc (varmessage:tmessage); Virtual
The dispatch method is defined in the TObject root class and is declared as follows:
Procedure TObject. Dispatch (varmessage); The message parameter passed to dispatch must be a record type, and the first in point of this record must be a field of type cardinal, which contains the message number of the message to be assigned. For example:
Type
Tmessage=record
msg:cardinal;
Wparam:word;
Lparam:longint;
Result:longint;
End
The dispatch method, in contrast, invokes the handle method of this message in the last generation class of the component, based on the message number. The dispatch method calls the DefaultHandler method if there are no handle handles for this message in this artifact and its ancestor classes. The DefaultHandler method is a virtual method defined in TObject and is declared as follows:
Procedure DefaultHandler (varmessage); Virtual
The DefaultHandler method in the TObject class simply implements a simple return without any processing of the message. We can implement the default handling of messages in subclasses by overloading this virtual method. For components in VCL, the DefaultHandler method starts the Windows API function DefWindowProc processing the message.
Two. Message Handling Handles in Delphi
In Delphi, users can customize the message and message handling handles. The definition of a message handling handle has several principles:
1. The message-handling handle method must be a procedure and only pass a tmessage variable argument.
2. The method declaration is followed by a message command followed by an integer constant of 0 to 32767.
3. The message-handling handle method does not require an override command to explicitly indicate a message-handling handle to an overloaded ancestor, and it is generally declared in the protected or private area of the component.
4. In a message handling handle, it is generally the user's own handling of the message, and finally the processing handle of the message in the ancestor class is called with the inherited command (in some cases it may be the opposite). Because the name and argument type of the handle to this message in the ancestor class might not be clear, calling command inherited avoids this hassle, as well if there is no handle to the message in the Ancestor class. Inherited will automatically call the DefaultHandler method (if you want to block this message, you don't have to inherited the command).
The message handling handle method is declared as:
Procedure Mymsgmethod (var message:tmessage); message msgtype;
Users can also define their own messages, and user-defined messages should start with Wm_user.
Examples of custom messages and message handling handles are:
Const MY_PAINT=WM_USER+1;
Type
Tmypaint=record
msgid:cardinal;
Msize:word;
Mcolor:longint;
Msgresult:longint;
End
Type
Tmycontrol=class (Tcustomcontrol)
Protected
Procedure change (var message:tmypaint); Message my_paint;
End
Procedure Tmycontrol.change (var message:tmypaint);
Begin
Size:=message.msize; {Set Tmybutton Dimension property}
Color:=message.mcolor; {Set Tmybutton Color property}
{Do something else}
inherited; {submitted to Tcustomcontrol processing}
End
Three. Filtering messages
Filter messages are also known as message traps. In some cases, users may need to block certain messages. or intercept some messages for processing. From the above introduction, we can see that there are three ways to filter messages:
(1). The virtual method WndProc inherited by the overloaded component.
(2). Writes a message handling handle for a message.
(3). An overloaded component inherits the virtual method Defhandler, in which the message is processed. The usual method is method (2), which is described in the previous section, and Method (1) is similar to Method (3), here is a brief introduction to the method (1).
The general process for overloading virtual method WndProc is as follows:
Procedure Tmyobject.wndproc (var message:tmessage);
Begin
{Determine if this message is processed}
Inherited WndProc (message);
{The unhandled message was handed to the parent WndProc method}
End
It can be seen that the advantage of processing messages in the WndProc method is that the entire range of messages can be filtered without having to specify a handle to each message, in fact the Tcontrol widget uses it to filter and process all mouse messages (from Wm_mousefirst to Wm_ Mouselast, as shown in the following code). It can also be used to prevent certain messages from being sent to processing handles.
Procedure Tcontrol.wndproc (var message:tmessage);
Begin
if (Message.msg>=wm_mousefirst) and (message.msg <= wm_mouselast)
Then
If dragging then Dragmousemsg (Twmmouse (Message)) {Handling Drag events}
else {handling other mouse messages}
End
Dispatch (Message);
{Otherwise send message normally}
End
The following example is an example of a simple custom artifact:
The Tmyedit class is a new class derived from the Tedit class, which is characterized by the inability to get focus in the run and not by the keyboard input (a bit like the Tlabel component). We can filter out the Wm_setfocus,wm_mousemove message in its WndProc method and process it to achieve the above requirements, the source program is as follows:
Unit Myedit;
Interface
Uses
Windows, Messages, Sysutils, Classes, Graphics, Controls, Forms, Dialogs,stdctrls;
Type
Tmyedit = Class (Tedit)
Protected
Procedure WndProc (Var message:tmessage); override;
End
Procedure Register;
Implementation
Procedure Register;
Begin
Registercomponents (' Samples ', [Tmyedit]);
End
Procedure Tmyedit.wndproc (var message:tmessage);
Begin
If Message.msg=wm_mousemove Then
Begin
Cursor:=crarrow; {Set the cursor to Crarrow instead of the default Crbeam cursor}
Exit
End
If Message.msg=wm_setfocus then exit;
{Wm_setfocus message is blocked, Tmyedit control is not getting input focus}
Inherited WndProc (message);
{Other messages to parents wndproc processing}
End
End.
You can test its performance by adding Tmyedit to component palette.
As can be seen from the above introduction, only clear the DELPHIVCL in the message processing mechanism, grasp the method and timing of processing various messages (if necessary, with the help of various tools, such as Winsight32,spy, etc.), and combined with the characteristics of OOP language, we can compile high-quality components. This, of course, relies on the reader to constantly explore and accumulate experience in practice.
===============================================================
The above is very good, but after reading, a problem is raised, that is, three kinds of message function trigger order. After my research, it should be WndProc the most priority, it after processing, but also to see whether it continues to pass. If you continue to pass, you can continue to trigger the next message function. Where the message handling handle function has a higher priority , if it exists, it is triggered, and then it is seen whether it continues to pass. If you continue delivery, you can also pass to the DefaultHandler method. Such a message can trigger three message handler functions at the same time.
However, if the message-handling handle function does not exist, then WndProc will pass the message directly to DefaultHandler (in fact, WndProc cannot find the message-handling handle function, the dispatch of TObject sends the message to DefaultHandler).
Unit unit1;interfaceuses Windows, Messages, sysutils, variants, Classes, Graphics, Controls, Forms, Dialogs, Stdctrls;co NST wm_test=wm_user+100; Type TFORM1 = Class (Tform) Edit1:tedit; Edit2:tedit; Button1:tbutton; Button2:tbutton; Procedure Button1Click (Sender:tobject); Procedure Button2click (Sender:tobject); Private {Private Declarations} procedure WndProc (Var message:tmessage); Override First priority procedure Mymessage (Var msg:tmessage); Message wm_test; Second priority procedure DefaultHandler (Var Message); Override Third priority public {public declarations} End;var form1:tform1;implementation{$R *.dfm}procedure Tform1.wndproc (var M essage:tmessage); Begin case Message.msg of Wm_test:begin showmessage (' Message in WndProc '); End Here, with exit, the end is no longer passed; Be sure to add this sentence, or compile the pass. Because most of the news no one handled inherited WndProc (message); Will call up all the way up until Tcontrol.wndproc calls dispatch to find the message handler function End;procedure Tform1.mymessage (var msg:tmessage); Begin// The message number handler function will first ringShould dispatch function ShowMessage (' Message in mymessage function '); After processing, you can choose whether to continue to pass to DefaultHandler inherited; Plus this sentence will continue to pass, otherwise it's over. End;procedure Tform1.defaulthandler (var Message); var p:pchar;begin with tmessage (message) do C ASE MSG of Wm_test:begin showmessage (' message in DefaultHandler '); Exit; End Add no exit here does not affect the else//must add this sentence, otherwise compiled pass. Because some basic information is not handled, the program will not work properly. (There is no default message handler, messages cannot be terminated naturally) inherited DefaultHandler (message); It calls Tcustomform.defaulthandler, and then proceeds to pass End;end;procedure Tform1.button1click (sender:tobject); Begin SendMessage (Handle, wm_test, 0, 0); The first method of sending messages is End;procedure Tform1.button2click (sender:tobject); Begin Perform (wm_test, 0, 0); The second method of sending messages is end;end.
But if you write this:
Procedure Tform1.wndproc (var message:tmessage); Begin //must add this sentence, otherwise compile pass. Because most of the news is not handled inherited WndProc (message);//will be invoked all the way up until Tcontrol.wndproc calls dispatch to find the message handler case Message.msg of Wm_test:begin showmessage (' message in WndProc ');//Add exit here to no longer pass End;end;
Although WndProc still has the highest priority, the result of processing messages itself is displayed at the end because of the invocation relationship.
Question: Those two compiled places, should not have been a problem. However, in the process of establishing the form and initialization, Delphi uses some message processing, and still needs to return the value, so there will be a problem with no processing. Be free to do a test study.
============================================================
New method: You can change the WndProc pointer of an existing control (without modifying the source code of the control): intercepts the DBGrid scroll bar message. This approach is actually equivalent to the subclass of Windows technology. The reason is "equivalent" because there is no direct replacement of the window class callback function, but instead of replacing the Delphi function between the substitution.
Foldproc:twndmethod;procedure tform1.formcreate (sender:tobject); begin Foldproc: = Dbgrid1. WindowProc; //Simple Replace Window function end;procedure tform1.myproc (var message:tmessage); Begin if message. MSG = Wm_vscroll then showmessage (' vscroll ') else if message. MSG = Wm_hscroll then showmessage (' HScroll '); //On the spot using the function pointer of the old window function, simple and perfect end;
Summary: Delphi's charm is really infinite ah, in addition to WndProc, another two methods are provided by Delphi itself. Even the wndproc becomes different--with Delphi's own functions, without handles, and can be replaced and passed on to each other, unprecedented flexibility and great power. It can even be protected with a try Catch statement, which causes the program not to crash at all.
How to implement Window message interception in Delphi (2)