Delphi object becomes a previous life of Windows control (key is handle and callback function)

Source: Internet
Author: User

----------------------------------------------------------------------
The first step, preparation: Predefined a global win control variable, and a streamlined win control class
Var
Creationcontrol:twincontrol = nil; Defines a global variable that represents the win control that you just created

Twincontrol = Class (Tcontrol)
Private
Fdefwndproc:pointer; Records the original window procedure, but only when the handle is actually created. Only Windows controls have default window processing, and Tcontrol has fwindowproc, not the same thing
Fobjectinstance:pointer; Normal pointers (not even function pointers). When forwarding a message, use this normal window function address (Not the class window function address). When the control is created, the conversion is done.
Fhandle:hwnd; Real handle to Windows window
Fparentwindow:hwnd; The handle of the parent window should also be recorded. The parent control (class, with many extra features) is not the same as the parent handle (the Windows pointer, extra simple). This property is not used in the General VCL control, only ActiveX may use
Protected
Procedure Mainwndproc (var message:tmessage); Non-virtual functions, call the WindowProc function, do not want to be overwritten (overwrite the WndProc function if you want to overwrite it, and this is not the only way)
Procedure WndProc (var message:tmessage); Override Virtual functions, processing small portions of messages, and finally calling the parent class with the same name function
Create and Destroy window handles in the order in which they are called:
Procedure CreateHandle; Virtual Virtual functions, key portals, are called by updateshowing and handleneeded, and the fact is that subclasses have never been overwritten.
Procedure Createwnd; Virtual virtual function, registering the window class. Many subclasses cover it to add some extra functionality, such as Tedit
Procedure CreateParams (var params:tcreateparams); Virtual The first time it appears. Only Windows controls need to prepare a lot of content
Procedure Createwindowhandle (const params:tcreateparams); Virtual Virtual functions, simple functions, call API, look at the name is very clear function. Subclasses sometimes cover it, Tedit and TMemo
End

----------------------------------------------------------------------
In the second step, the control constructor is called to request the memory space of the Delphi control object. At this point the in-memory control:
1. There is no windows handle,
2. Prepare a makeobjectinstance converted window callback function pointer fobjectinstance, which encapsulates the Mainwndproc function (or, it is the Mainwndproc function). Mainwndproc encapsulates the window callback function WndProc that programmers need to use. But this step is just the Prep window function pointer fobjectinstance, and does not do any use and settings to make it associated with a Windows window.
At this point, the memory is simply a simple Delphi memory object, and does not associate it with the Windows operating system so that it really becomes a Windows window object.

Tbutton.create;
Call inherited Create (Aowner);

Twincontrol.create;
Call inherited Create (Aowner);
Call Fobjectinstance: = Classes.makeobjectinstance (Mainwndproc); A global function that converts a class function pointer mainwndproc to a normal pointer (not even a function pointer). Note Only Windows controls have this

----------------------------------------------------------------------
third, call the function in turn, register the Windows window class, and associate it with the current Delphi object .(In fact, the Delphi object contains it, because the Delphi object includes a lot of other content), the most important is:
0. In CreateHandle (that is, the entry function), it calls the Createwnd function, and CreateHandle itself is called by updateshowing and handleneeded. Where the updateshowing will be twincontrol.updatecontrolstate; Updatecontrolstate will be called by Twincontrol.insertcontrol, Insertcontrol will be tcontrol.setparent call, details see:
Http://www.cnblogs.com/findumars/p/3917061.html
Http://www.cnblogs.com/findumars/p/3667031.html
1. In Createwnd, depending on the value of the Delphi control, prepare the params
2. In Createwnd, forcibly unregister the current Delphi class (such as TButton), and then set the window function Params.WindowClass.lpfnWndProc: = @InitWndProc;
3. In Createwnd, re-registered Windows window Windows.registerclass (params.windowclass)
4. In Createwnd, execute creationcontrol: = self; At this point the Creationcontrol represents the Delphi memory control
5. In Createwnd, execute Createwindowhandle (Params); Actually create the Windows window and immediately send the Wm_nccreate message to this window, before the function returns, jump to the callback function Initwndproc execution (that is, the following 6~10), The handle is then assigned to the Delphi control property Fhandle (this assignment is superfluous, so it's okay to remove the assignment, because it's already assigned in the callback function).
Note 1 that the experiment found that the wm_nccreate message was sent before CreateWindowEx the WINAPI returned, so the Initwndproc callback function is executed before WINAPI returns. It can be understood that the internal implementation of the CREATEWINDOWEX function is to create fhandle first, then SendMessage (Fhandle, Wm_nccreate), the callback function will work immediately, At this point there is no CreateWindowEx function, because there are two messages to be sent, plus other aftercare matters.
My understanding is that whenever a successful creation of this Windows window has a handle (which is the only basis for future messages to find this window), regardless of whether the Windows window is displayed, or whether it is associated with a Delphi object, Windows will send it wm_ Nccreate message. Note that this Windows window function is already in existence (that is, Initwndproc) when registering the Windows window class, so it is certain that this message can be executed and processed.
Note 2, because the Fhandle property has been assigned to the callback function, so fhandle: = CreateWindowEx (ExStyle ...), here the Fhanle assignment can be removed, run a few demo are normal. ButThe best solution is to put initwndproc creationcontrol.fhandle: = Hwindow; shield off, leave fhandle: = CreateWindowEx (ExStyle ...) However, the error is always a call to an OS function failed. After detection, found that the return value of CreateWindowEx at this time is 0, do not understand why.
6. In the Initwndproc,when the first message (Wm_nccreate) comes, it executes creationcontrol.fhandle: = Hwindow, so that the current Delphi control has a handle for the first time (the most critical first step).
Note that this step must be performed, and if you block this sentence there will be an error in the a call to an OS function failed. Eventhink of a trick (this will allow the main form and button to create a normal, and then dynamically create tedit with the button, and edit.tag=100, so that can be dedicated testing), if (creationcontrol.tag<>100) Creationcontrol.fhandle: = Hwindow; Or not. The statement of the error is obviously if Fhandle = 0 then raiselastoserror; With a single step test, Initwndproc still performs normally, but does not know why fhandle: = CreateWindowEx (ExStyle ...) The return value is changed by 0.
7. In the Initwndproc,The window function of the Windows window instance (that is, the Delphi control instance) represented by Hwindow is reset to the preset fobjectinstance, so the window callback function of the current Delphi control is Fobjectinstance, The virtual function that points to the Delphi class is WndProc (the second most critical step).
8. In Initwndproc, the 4 parameters required for the callback function are stacked sequentially to match the stdcall flavor of the Windows standard callback function
9. In Initwndproc, the Creationcontrol address value is transferred to EAX, and the Creationcontrol is emptied, that is, the temporary task for the Delphi control instance represented by Creationcontrol is completed. Ready for the next new Delphi control instance to be used
10. In Initwndproc, use EAX to find the current Delphi control in memory, convert it to Twincontrol, and then directly call its fobjectinstance function to process the message, parameters are just the parameters of the stack, So the first message is finished. There are several purposes for handling this message, which is important:
1) record the handle of the Windows control into the properties of the Delphi object
2) Replace the callback function of this Windows window with the fobjectinstance of the Delphi object, so that it indirectly calls the virtual function WndProc of the Delphi object, which makes it easy for the programmer to rewrite
3) Three ways to record the ID of this Windows handle globally
4) The above three main purposes have been achieved, so although the wm_nccreate message itself is not used (in general, because the programmer can still rewrite), but the message has to be processed, so through the transformation means, using the new callback function fobjectinstance the message processing. If programmers also need to use wm_nccreate messages to perform certain logic, they can still be executed in WndProc and dynamic functions.There is a doubt that if the screening of this Assembly will be wrong, the error stays in Twincontrol.defaulthandler CallWindowProc (Fdefwndproc,fhandle,msg,wparam,lparam); To change this assembly to call DefWindowProc is also the same error, perhaps because the message must be processed?
11. In CreateHandle, based on the Fhandle property of the current Delphi control, the call SetWindowPos shows the Windows window, and for the general Programmer's understanding, it shows the Delphi control
It should be emphasized that the above 11 steps, each generation of TButton instances to do so, especially the second step to rewrite the Delphi class (such as TButton) callback function, and then re-register, re-replace the callback function is fobjectinstance.

The actual invocation relationship is as follows:
Twincontrol.createhandle;
Call Createwnd;
Call SetWindowPos (Fhandle,swp_nomove + swp_nosize + swp_noactivate);

Twincontrol.createwnd;
Application for Params:tcreateparams;
Call CreateParams (Params);
Call Fdefwndproc: = Params.WindowClass.lpfnWndProc; Log the class attribute to Delphi before changing it
Call Params.WindowClass.lpfnWndProc: = @InitWndProc; Change to Delphi's global function, with the same parameters.
Call Creationcontrol: = self; Global variables, which are used only in one place, are recorded for initwndproc use. Note that the self value is different each time, and is actually the address value of a different Delphi object.

Twincontrol.createparams;
Application for Params:tcreateparams; is a record that allocates memory on the stack. Out of this function, this part of the memory is retracted.
Call CreateParams (Params); A virtual function, a class function, is called in this place.
Call Params.WindowClass.lpfnWndProc: = @DefWindowProc; API, a default window function for a Delphi, is quickly replaced. This is just a window function for the class, but for each instance, each of their window functions is replaced.

Twincontrol.createwindowhandle;
Call Fhandle: = CreateWindowEx (ExStyle, Winclassname, Caption, Style, X, Y, Width, Height, wndparent, 0, Windowclass.hinstanc E, Param);
This API sends Wm_nccreate, Wm_nccalcsize, and wm_create, actually executes the first two messages corresponding to the function, the function of the last message is replaced by the constructor function.
Create a window handle after creation, stored in the Fhandle attribute of the Delphi object

Global function Initwndproc (Hwindow:hwnd; Message, WParam, lparam:longint): Longint;
Call Creationcontrol.fhandle: = Hwindow;
Call SetWindowLong (Hwindow, GWL_WNDPROC, Longint (creationcontrol.fobjectinstance)); Use pre-prepared fobjectinstance as normal window function address
Call
Push LParam//press stack 4 lattice
PUSH WParam
PUSH Message
PUSH Hwindow
MOV Eax,creationcontrol//Put the control address you just created in the EAX register. mixed with the Assembly and Delphi, directly referencing the Delphi variable, the next function to prepare parameters.
MOV creationcontrol,0//empty immediately after use, ready to let the next new control use
Call [EAX]. Twincontrol.fobjectinstance//The control is found in memory based on the memory address in the register, converted to the win control, and called its window function, the parameters are in the stack
MOV Result,eax//After processing (wm_nccreate) message, the results are sent back

Here Creationcontrol and its window functions have been replaced. Left is a Delphi object, with the correct handle value, and has a separate window function (fobjectinstance points to Mainwndproc Point WndProc). The default window function address is even logged with Fdefwndproc.

-----------------------------------------------------------
The fourth step, the aftermath of the work

Twincontrol.destroy;
Call if Fobjectinstance <> nil then classes.freeobjectinstance (fobjectinstance); Global function, freeing the memory of the window function

Delphi object becomes a previous life of Windows control (key is handle and callback function)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.