Implementation of normal windows in Delphi
Summary In the VCL library of Delphi, for use and implementation, Application Object Application creates a hidden window to process a message response. It is this window that makes the programs developed with VCL have some deformities that are unable to arrange tiles with other windows. This paper gives a solution that requires only a modification of the application project file to solve the problem with a modification of the application project file for 3 line code, and does not require any changes in the original programming.
Keyword VCL, normal window, normalization
1 Introduction to the Windows application written by the VCL class library provided by Delphi, there is a characteristic that the characteristics different from the standard Windows window - the system menu of the main window is different from the system menu on the taskbar. In general, the system menu of the main window has six menu items and the taskbar system menu has only three menu items. In actual use, we found that the procedures developed with VCL have the following aspects: 1) Not beautiful enough. This is sure, and the standard does not seem to be some deformed. 2) There is no animation effect when the main window minimizes. 3) The window does not normalize the tile with other windows. 4) The taskbar system menu has the highest priority. The entire program can still be minimized in the event of a modal window, which is contrary to the design of the modal window. The problem of the main window minimizes the effect of the animation effect is resolved by the showwinnoanimate function in Forms.PAS in the release of Delphi 5.0, but the other problems have always existed. Although this does not affect the application in most cases, it is indeed unacceptable in some cases that pursue professional effects. Since C Builder and Delphi use the same set of class libraries, the above problem is also existing in a Windows application written in C Builder. In the previous article (can be found in the home of Agump), I have discussed this issue, and the narrative that it looks great to a way, and I also found that method in accidents. The task of this article is through some analysis of the VCL class library, which means that the principle is doing, and then gives a method of using only 3 lines of code, completely solving this "non-normal window" in Delphi.
2 Principles 2.1 Application Creation Process Below is a typical application's Delphi engineering file, we note that there is a reference to the initialize method for Application objects at the beginning, our analysis begins here:
PROGRAM Project1;
Uses form, unit1 in 'unit1.pas' {form1};
{$ R * .res}
Begin Application.INITIALIZE; Application.createform (TFORM1, FORM1); Application.Run; End.
The hidden window is created by the Application object, then what is the Application object? In the code editing window of Delphi, press and hold the CTRL Click Application to find that the Application object is one of several global objects defined in the Forms.Pas unit. This is not enough, what we want to know is where the Application object is created, as you must successfully create an instance of the TAPPLICATION class we can reference it. Think about it, what code will execute before Application.initialize? Yes, it is the code in the initialization code segment. Be careful to debug the VCL source code, you can know that many units in the VCL have the initialization code segment. When starting the Delphi program, first perform the code in the Initialization code segment in each unit in order, complete all initialization action, execute Application The Initialize method is initialized Application, so it is clear that the Application object is created in the initialization code segment of a unit. Searching in the VCL source directory in "Tapplication.create", we really found code that created the Application object in the Controls.Pas unit. In the initialization code segment of the Controls.Pas unit, there is a call to the initControls process, and the implementation of InitControls is as follows: UNIT Controls; ... Initialization ... initcontrols;
Procedure initcontrols; begin ... mouse: = tmouse.create; screen: = tscreen.create (nil); application: = tapplication.create (nil); ... END;
Ok, let's get the first step in our analysis, because we must solve the problem of abnormal window, we must do one before the Application object is initialized, so it is very important to understand the initialization process of the application. 2.2 Islibrary Variables ISLibrary variable is one of the global flag variables defined in the System.PAS unit. If the value of IsLibrary is true, it indicates that the program module is a dynamic link library, which is an executable program. Some processes in the VCL class are different from different values of this flag variable. That is, this variable is a key role in solving the non-normal window problem of Delphi. As mentioned earlier, for convenience, the Application object is initialized to create a visible window (that is, the tool to see "Tapplication" as the window of the name "TAPPLICATION"), but it is because this is not seen The window will make the programs developed with Delphi present many deforms. Ok, if we can get rid of this invisible window (to remove the taskbar system menu), don't have all the questions to solve it in our application main window. Talking about it, but does it need to make a big surgery for VCL source? If so, isn't it a bit going to fall? The answer is of course not, otherwise there will be this article. What I want to say here is that in the next analysis, we will see that the so-called "programming, waiting for one heart", TAPPLICATION design is unintentional to insert will will will will will will will will be solved for us. Interface. Do not do the analysis of the source code, you may have to get around the circle, and in fact, we will see that the genius design is left to us, not many, just good. Open the constructor crete of the TAPPLICATION class, we will find such a line of code. Constructor Tapplication.create (Aowner: Tcomponent); Begin ... if not islibrary the cretehandle; ... End;
What is said here is that if the program module is not a dynamic link library, then execute CreateHandle, and CreateHandle does this in the help: "If there is no application window, create a", "application" application The program window is the invisible window mentioned above, that is, the culprit, in the Tapplication class, in the Tapplication class, use FHANDLE variables to save its window handle. Here is based on the value of IsLibrary, because the message loop is generally not required in the dynamic link library, but use the VCL to develop dynamic link libraries or use the Application object, so there is a design here. Ok, we only need to deceive the Application object. You can filter it out of the CREATEHANDLE to remove the execution of CREATEHANDLE before it creates it. The code assigned to IsLibrary is obviously in the initialization code segment of a unit, and since the code in the initialization code segment is performed in the order of the included unit, to ensure that the IsLibrary value is true before the Application object is created. In the project file, we must put the unit containing assignment code before the Forms unit, as follows (assuming the unit is unitdllexe.pas):
Program template;
Uses unitdllexe in 'unitdllexe.pas', forms, formmain in 'formmain.pas' {mainform}, ... UnitdllexE.PAS code list is as follows:
Unit UNITDLLEXE;
Interface
IMPLEMentation
Initialization islibrary: = true; // tells the ApplCIATION object, which is a dynamic link library that does not need to create a hidden window. End.
Ok, compile, we see that because there is no hidden window, the system menu on the original task bar disappears, replaced with the system menu of the main window, and the main window can also be arranged normally with other Windows windows. But the problem brings that the window cannot minimize. What's going on? Still old, track it. 2.3 Main window Minimize Minimization belongs to the system command, and finally you must call the API function DefWindowProc to minimize the window, so we have found the function WMSysCommand in TCUSysCommand messages in TCUSysCommand messages without difficulties. It is clear to the minimization message to be redirected to Application.WndProc process: procedure TCustomForm.WMSysCommand (var message: TWMSysCommand); begin with message do begin if (CmdType and $ FFF0 = SC_MINIMIZE) and (Application.MainForm = Self) then Application.WndProc (TMessage (Message)))).
In Application.WndProc, the Application's Minimize method is called when the message is minimized, so the crux must be in the minimize process.
procedure TApplication.WndProc (var Message: TMessage); ... begin ... with Message do case Msg of WM_SYSCOMMAND: case WParam and $ FFF0 of SC_MINIMIZE: Minimize; SC_RESTORE: Restore; else Default; ... end;
Finally, find Tapplication.minimize, all understand everything. Here is the call to the DEFWINDOWPROC function, why? Since we deceive the Application object in front, filter out the CreateHandle call, and do not create the window required for the Application object response message, so that its handle fhaandle is 0, the call is of course unsuccessful. If Fhaandle can point to our application main window to solve the problem.
Procedure Tapplication.minimize; Begin ... DefWindowProc (Fhandle, WM_SYSCOMMAND, SC_MINIMIZE, 0); // Here the FHANDLE value is 0 ... End;
3 Realize the genius of Borland's innocence, and the design of the willow will make us find a solution to the problem. From the previous analysis we know that there is no hidden window in the dynamic link library developed with the VCL to receive the Windows message (CREATEHANDLE is not executed), but if you want to display the window in the Dynamic Link Library, you need a parent window. How to solve this problem? The VCL designer will save the fhandle variable of the invisible window handle to be writable, so we can actually simply assign a value to the FHANDLE to provide a parent window for the sub-window you need to display. For example, in a dynamic link library plugin to display a form, we usually pass the handle of the Application object through a function of the dynamic link library through the dynamic link library to an application.handle , Similar to: procedure setApplicationHandle (Mainappwnd: hwnd) begin Application.Handle: = MainAppWnd; End;
Ok, since APLICATION.Handle is actually just a window handle used inside to respond to messages, the invisible window that should be created is removed by us, then we only need to give a handle of a window, used to replace that The handle of the original excess hidden window is not? Where is this window going? The main window of the application is the top right, so there is the following code.
Program template;
Uses Unitdllexe in 'Unitdllexe.Pas', Forms, FormMain in 'formmain.pas' {mainform};
{$ R * .res}
Begin Application.INITIALIZE; Application.createform; Application.Handle: = FormMain.handle; Application.Run; end.
So, everything is solved. You don't need any modifications to the VCL source code, do not need any modifications to the original program, just add two lines of code in the project file, plus a line in Unitdllexe.Pas, a total of three lines of code, you can make you The application window is all as normal as any of the standard Windows windows. 1) The taskbar and window title bar have a consistent system menu. 2) There is an animation effect when the main window minimizes. 3) The window is able to arrange tiles with other windows. 4) Do not operate its parent window when there is a modal window.
The above implements code is used in all versions of Delphi.