Title: Delphi message mechanism study notes Keywords: Delphi message mechanism of: dREAMtHEATER Difficulty: Normal [] medium [x] High [] http: //dREAMtHEATER.yeah.netE-Mail: NoteXPad@163.com Completion Date: 2004 On August 12th, in recent days, the implementation of the "Inside VCL" book in Delphi in Delphi in recent days, this is the second time. It was originally understood that the first time was completely understood, but Didn't do notes, I have seen it again, this time I defined to write a note. At the same time, I walked at the Internet and went to see two articles discussed in the Delphi message framework. Some partial analysis was quite in-depth, very good Delphi message mechanism summary. Next, I didn't want to write notes, but later, I wondered that these articles wrote well, but after all, I didn't write it yourself. I want to clarify the news mechanism. I have to write it my own pen. I can't write it. Think that what you think is that it is true. Here I have to say two sentences, Li Wei's book, many places I think it is not very good. Sometimes a topic is written by N long space, it seems that there is no top article in the article. It is well written, for example, MakeObjectInstance This cattle X function represents I think it is not good, so don't worship the so-called boss, huh. In many places in the text, I will write a particularly simple, because in more detail, in Li Wei's book and I have written very clearly in the article I refer, I will not pay back ink again, just put the entire process. And write a few valuable examples. The body always remembers, no matter whether you use SDK or borrow VCL to create a window, you must follow Windows's game rules, first register the window class, then create a window instance, and write a real current code in the message loop. You must also know that Windows has already pre-funded multiple window classes, such as "Edit", "ComboBox", then we have to create these windows directly, no registration window classes; all in Delphi is more simple All VCL is all done for you, you only need to drag the control you want on the design form, you can do it, is it very cool? First, the window of the window creates the VCL, the true window control with the handle (Handle) is all inherited from TWINCONTROL, and then starting from the creation of TwinControl. The establishment of the window in the VCL is not created according to the process we imagined, you will first create all the windows, then call, but create it when you need it. Maybe you still can't understand my meaning of this sentence, look slowly. Inheriting Window Controls from TWINControl will have a Handle property. When you need a handle value in your code, you will get the handle through the getter of this property. At this time, if the form has been established, return the handle, otherwise create a window instance, Return to the handle, so the window creation is implemented in TwinControl.HandLeneedededededededededededededededededededededededededededed The purpose of Borland does I want to save system resources to the greatest extent. There are several important ways in TwinControl.Handleneeded, and they can create a window. TwinControl.HandLeneeded call TwinControl.createHandle to get Handle.
However, createHandle is just a packaging function, which first calls TwinControl.CreateWnd to create a window, createwnd is an important process, first call TwinControl.createParams Settings to create the parameters of the window, call the RegisterClass API registration window class, createwnd, then call TwinControl .CreateWindowHandle, CREATEWINDOWHANDLE is a function that truly calls the CreateWindowEx API creates a window instance. CreateHandle, CreateWnd, CreateParams, CreateWindowHandle are all virtual methods, and the derived class can overload these methods to get more features, where CreateParams is the largest. The method mentioned above, I suggest you have to look at it carefully, deepen the impression, after I mention the method, you have to look at the source code, you will not be able to pay infinite, I will no longer prompt. To this window is established, it is still not possible to run correctly because it has no message loop. Second, the implementation of the message loop is the most exciting place in the entire VCL message framework, because the traditional Windows callback function is a static function, and the form in the VCL is class, when the class method is called, in addition to the function The address of itself, you still need a self, establishing associations between them, is really not an easy thing, requires a lot of code skills, and the message loop must also ensure that hundreds to tens of thousands of messages per second, So the code needs more written. The study of this part of the code may spend more time. We know that the formal callback function is provided when the form is entered, so that this process can be imagined to occur in the call to TwinControl.CreateWnd, in which the static function pointer @initWndProc is assigned to WNDCLASSEX LPFNWNDPROC in the structure, which is where the VCL form establishes a message loop for the first time. InitWndProc first time is called, by SetWindowLong API callback function will replace the message TWindowControl.FObjectInstance, and TWinControl.FObjectInstance is an ordinary Pointer, the assignment is in TWinControl.Create in MakeObjectInstance done by the most Magic function, this The process is very complicated, and the details are described in detail [3]. The result is that the class method TwinControl.mainWndProc has become a real message handling Handler, and the message processing of the corresponding form instance is complete in TwinControl.MainWndProc. Another detail is that the message is to call a purely written static function before being processed by MainWndProc - StdWndProc distributes the message [1]. The completion of the message callback from a normal static function to the transformation of the class method. In fact, TwinControl.mainWndProc is called WindowsProc to actually handle window messages, and WindowsProc is specified in the virtual method WNDPROC in tControl.create. From TControl to the actual VCL form class, many derived classes overload WNDPROC, so that each derived class that overloads the method will add some features. Of course, at the end of the inheritance chain, such as TFORM, you can also overload WndProc to complete some tricky code.
Remember, if you overload WndProc, you always handle yourself you want, and then submit the unprocessed messages to the parent class's WndProc processing. In the WndProc in each inherited class, only the most basic messages of the maintenance form operation should be processed, and other non-processed messages will eventually be passed to Tobject.DiaPatch in TControl.WndProc. TOBJECT.DIAPATCH queries the corresponding message ID in the dynamic method table of ourselves and the parent class, if it is found, then call the corresponding method. All class methods for all processing messages should be defined in keyword message, which ensures that their entry address is in a dynamic method table, so that the message that needs to be processed can be called during the TOBJECT.DIAPATCH execution process. If you can't query the message you need to process in the dynamic table, the TOBJECT.DIAPATCH will continue to call the virtual method defaulthandler, TOBJECT.DEFAULTHANDLER is just a PlaceHold, which is overloaded in TwinControl, and the TwinControl inheritance is fresh. The class of the method can be considered that the chance of the last time being processed is to occur in TwinControl.DefaultHandler. We know that the messages that do not process in the message loop will finally handle the default callback function DefWindowProc API for Windows. TWINCONTROL.DEFAULTHANDLER is to complete this, in addition to this, complete several additional messages [ 2]. The VCL message flow is so that. Maybe you are also assigning a process for the entire message, let me analyze it with examples. Third, VCL complete message dispatching process 1. TButton newly built a button on Form1 (default name button1), write point code in its onclick event, plus breakpoints, before debugging, please open DCU debugging switch (Project-> options-> compiler-> use debug dcus), if this switch is not open, it can't debug VCL, then F9 runs, when staying on the breakpoint, open the Call Stack window (view- > Debug window-> call stack) You can see the order of calls (from bottom to look up):
TFORM1.BUTTON1CLICK ($ 9637c0) Tcontrol.ClickTButton.ClickTButton.cncommand ((48401, 660, 0, 524948, 0)) TControl.WndProc ((48401, 660, 524948, 0, 660, 0, 660, 8, 0) 0)) TwinControl.WndProc ((48401, 660, 524948, 0, 660, 0)) TButtonControl.WndProc ((48401, 660, 524948, 0, 660, 0, 660, 8, 0, 0) TControl.Perform (48401, 660, 524948) Docontrolmsg (524948, (no value)) TwinControl.Wmcommand ((273, 660, 0, 524948, 0)) TCUSTOMFORM.WMCOMMAND ((273, 660, 0 , 524948, 0)) TControl.WndProc ((273, 660, 524948, 0, 0)) TwinControl.WndProc ((273, 660, 524948, 0, 660, 0, 660) , 8, 0, 0)) TCUSTOMFORM.WNDPROC ((273, 660, 524948, 0, 0)) TwinControl.mainWndProc ((273, 660, 524948, 0, 660, 0) , 660, 8, 0, 0) STDWNDPROC (918056, 273, 660, 524948) TWINCONTROL.DEFAULTHANDLER ((NO value)) TControl.wmlbuttonup ((514, 0, 48, 13, (48, 13), 0)) TControl . WndProc ((514, 0, 852016, 0, 0)) TwinControl.WndProc ((514, 0, 852016, 0, 0, 0, 0, 48, 13, 0, 0) ) TBUTTONCONTROL.WndProc ((514, 0, 852016, 0, 0, 0 , 48, 13, 0, 0). TWINCONTROL.MAINWNDPROC ((514, 0, 852016, 0, 0, 0, 0, 48, 13, 0)) STDWndProc (524948, 514, 0, 852016) TAPPLICATION.HandleMessageTApplication. Runproject1 A Button is clicked, two messages occur in TButton inside:
WM_LBUTTONDOWN /
WM_LBUTTONUP, TBUTTON has not processed WM_LButtonup (Problem: Why only respond to WM_LButtonup, these two messages should only happen within Windows native controls unless TButton Subclass "Button", this part of the code I didn't see), just handed over TwinControl.defaulthandler, Then TButton also sent the generated WM_COMMAND message to its Parent, TFORM, passed through a series of messages, WM_COMMAND is processed in TwinControl.WMCommand, and the WM_COMMAND is processed into cn_command through DOCONTROLMSG, and then use tControl.Perform to pass the CN_COMMAND back TButton , Passed through a series of messages to DISPATCH in TButton, found Handler - TButton.cnCommand by querying dynamic method table, which calls virtual methods TButton.click, then call TControl.click, call fonclick in this method, The content of the FONCLICK feature is that the Delphi will automatically specify to TButton's OnClick feature when the programmer uses the object viewer to write TButton, and OnClick is specified as TFORM1.BUTTON1CLICK, so TForm1.button1click is finally called . 2. TFORM New Application, write a point of code for Form1, set the point, F9 run, see Call StackTform1.FormMouseDown (???, ???, [ssleft], 346, 212) TControl .MOUsedown (Mbleft, [SSLEFT], 346, 212) TControl.domousedown ((513, 1, 346, 212, (346, 212), 0), MBLEFT, []) TControl.WmlButtondown ((513, 1, 346, 212) (346, 212), 0) TControl.WndProc ((513, 1, 13893978, 0)) TwinControl.WndProc ((513, 1, 13893978, 0, 1 , 0, 346, 212, 0, 0)) TCUSTOMFORM.WNDPROC ((513, 1, 13893978, 0)) TwinControl.mainWndProc ((513, 1, 13893978, 0) , 1, 0)) STDWndProc (2687598, 513, 1, 13893978) TAPPLICATION.HANDLEMESSAGETAPPLICATION.RUNPROJECT1
Mouse Click on Form, generate two messages
WM_LBUTTONDOWN /
WM_LBUTTONUP
But we only take it
WM_LBUTTONDOWN
. produced
WM_LBUTTONDOWN
After a series of messages to the TOBJECT.DISPATCH, you find the Handler - TControl.WmlButtondown in the parent class TControl of TForm, in Tcontrol.WmlButtondown, TControl.Domousedown, a series of methods called in tControl.WmlButton, TControl.Mousedown The final call to Fonmousedown, FONMOUSEDOWN is assigned to TFORM1.FORMMOUSEDOWN, call fonmousedown to call TForm1.FormMouseDown. Telling a lot of messaging process, what are the applications in the actual situation? Fourth, the actual application of the message If you are a shared software author, you often have troubles for your software, you can do it is to strengthen your software Anti-crack function, pay you a trick today. If you have used Delphi's dedicated disassembly tool DEDE, then you must know that the inlet address of the Event Handler like Button1Click is extremely easy to be positioned, whose principle is obtained according to the TForm's RTTI information (you can get the DFM resource file) Address), in fact, the VCL form has only Published class members to generate RTTI information. Know that this key point plus a deep understanding of the VCL message mechanism you can prevent all this. 1. Anti-crack creates two button, name BTNREGISTER, BTNCANCAN, and double-click these two buttons, generate TFORM1.BTNREGISTERCLICK, TFORM1.BTNREGISTERCLICK EVENT HANDLER Skeleton Code, and then in Object Viewer Cancel BtnRegister.Onclick associations with TFORM1.BTNREGISTERCLICK, then put TFORM1.BTNCANCELCLICK declarations in the private section of TForms1 declarations. Add another part according to the following code content:
unit Unit1; interfaceuses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class (TForm) btnRegister: TButton; btnCancel: TButton; procedure btnCancelClick (Sender: TObject); private procedure btnRegisterClick (Sender: TObject); procedure WMCommand (var Message: TWMCommand); message WM_COMMAND; public {public declarations} end; var Form1: TForm1; implementation {$ R * .dfm} procedure TForm1.btnCancelClick (Sender: TObject); begin Close ; end; procedure TForm1.btnRegisterClick (Sender: TObject); begin ShowMessage ( 'Thx for ur registration.'); end; procedure TForm1.WMCommand (var Message: TWMCommand); begin if Message.NotifyCode = BN_CLICKED then if FindControl (Message .Ctl) = btnregister dam (self); EXIT; END; inherited; end; end. This method is to intercept TFORM1's WM_COMMAND message and process itself. Please analyze the code yourself. After compiling, you can use the DEDE to disassemble, see if you can find the entrance address of TForm1.btnregisterClick. Have you understood the Connected VCL Message Mechanism? Is it especially complicated? One message is often going to pass through 10 methods to Event Handler, don't look at the message passing through such a long road, but the efficiency of the VCL message mechanism is still very high, because many key code is written directly with the assembly, each A stopping time is very small, so the news that needs to be dealt with can still reach the destination quickly. I started learning Windows programming from SDK, I wrote basic Windows programs at that time, I always think that SDK will use Delphi cattle X, now I'm really stupid, compared to the SDK programming The VCL message mechanism is much more complicated. After reading the VCL source code, the maximum feeling is that I have never learned the programming, but it is undeniable that only after you have the foundation knowledge of OOP / ASM / SDK, Do you have a capital that understands the VCL source, do you have some basic knowledge? Reference 1. Li Wei. "In-depth core-VCL architecture analysis" fourth, five chapter, 2004.1 2. Savetime. "Delphi's message mechanism is shown", Jan 20043. Cheka. "VCL window function registration mechanism research, Comparison with MFC ", 2001