Recently, one of my clients complained to me that since I installed the software, they should have automatically shut down the server at midnight and will occasionally find that the system is still on the next morning. They suspected it was a bug in my software and hoped I could check it.
Yes, it is annoying to be unable to shut down automatically: for individuals, this means power consumption, computer wear and tear, and unhappy mood. For enterprises, this may mean huge economic losses.
However, myProgramIt's just a simple data processing program. How can it obstruct shutdown? -- This is what I thought when I heard complaints from customers. But when I did a very simple program test, I got a very frustrating result:
(Note: This is the result under. Net framework1.1. This issue has been fixed in MySQL 2.0)
1. Open vistual Studio. NET and create a C # (VB. NET is also supported.CodeTake C # as an example.
2. Assume that the automatically generated form is called form1, and another Windows form is called form2.
3. Add a button on form1 and write it in its Click Event Handler:
Form2 F = New Form2 ();
F. showdialog ();
That's right. It's such a simple program-two forms. When you click the first form button, use the second form as the Modal Dialog (mode dialog box ?) Display.
Well, compile now, run this program (not in the debugging environment), and then press that button to display form2.
Then shut down (or restart or log off ).
You will find that form2 is closed, but form1 is still there; and no matter how long you wait, there is no shutdown you expect (or restart, logoff ).
If this is the case we humans encounter, it is very simple-we can try it multiple times; experienced experts can also open the task manager to find the process that may be the cause and kill it; in the end, you can still press the power switch ...... Unfortunately, our customers cannot arrange a staff member to get up at every night to verify that their servers are disabled.
Therefore, I must find the cause.
I admit that at the very beginning I did neglect this problem-I thought ,. net modal dialog is used by thousands of people every day. If modal dialog is displayed, it cannot be shut down. It must have been noticed for a long time. That is to say, there must be countless online models.ArticleExplain the cause and solution of the problem. If Ms considers this as a bug, it will explain it in msdn and provide a solution. If it is designed in this way, then he will give a reason. -- In short, this must be a well-known phenomenon.
However, I found nothing for an hour (maybe the keyword I used is not good ?), So I had to admit my ignorance. However, no matter how ignorant I am, I am in the awkward position where the customer must solve the problem, so I am at least trying to solve it.
As a prerequisite for analyzing this problem, some basic knowledge must be known. To take care of cainiao like me, I will write them here first:
When Windows finishes a session (shutdown, restart, or logoff), it sends a wm_queryendsession notification to all windows (the int value is 0x11, 10 in hexadecimal Form 17) to ask the application's opinion, and will continue to close after receiving the "agree" answer. The so-called "agree" means that true (OR 1 of the INT) is returned for this message ). Otherwise, if a program returns false (or Int 0) after receiving wm_queryendsession, the system will interrupt the closing action and stop sending the closing notification to other programs, the system will not be shut down.
As we can see, it is written on msdn: by default, the defwindowproc function returns true for this message. (In other words, any window that does not specifically respond to this message will agree to close by default)
In. NET Framework, which is equivalent to defwindowproc in Win32 system, is the form. wndproc method (of course, The wndproc method of each of its parent classes ). Its prototype is:
Protected override void wndproc (ref message m );
M is a message structure, where MSG represents the type of the message, and result is the returned result of this message. For details, see msdn. What we care about is what the default form. wndproc assigns to M. Result when M. MSG is 0x11.
After the system sends the wm_queryendsession to the window to ask the program's opinion, the system will use wm_endsession to notify the result of the closing action (whether to determine the result after asking all programs, or ask one notification, in this regard, Win9x and 2 k series have several differences. If you are interested, refer to msdn ). The value of wm_endsession is 0x16 (decimal 22 ). At the same time, write down wm_close (0x10, 10 hexadecimal 16.
In addition, it may be an external question. We noticed that the above phenomenon only occurs when a modal dialog is displayed, and there is no problem if modeless dialog is created using show. For more information about the form. showdialog method, see the following description on msdn:
Unlike modeless form, when modal dialog is disabled by users, the. NET Framework does not call its close method, but hides it (hide. In this way, when you want to display this dialog box again, you do not have to create a new instance. But at the same time, when you no longer use it, you need to call its dispose method to reclaim resources.
Well, with the above foundation, we can analyze it.
Use a decompilation tool such as ildasm to open windows. form. DLL, find form. the wndproc method is easy to understand. We will soon be able to find several messages related to window closures and hand them over to a method called wmclose for processing.
The method is prototype as follows:
Private voidWmclose (system. Windows. Forms. Message m );
At the beginning of this method, get_modal () is used to determine whether the current window is modal dialog. If it is modal dialog, it simply checks dialogresult and so on, and then returns the result. If it is modeless, it is necessary to verify and call the onclosing method of each word window, and finally obtain the result. The following is a simplified version written with pseudocode (slightly different from the actual situation ):
// Modal Dialog Box
If (Form. ismodal)
If (Form. dialogresult = Dialogresult. None)
Form. dialogresult = Dialogresult. Cancel;
Else // When the modeless dialog box is displayed
// For events that can be canceled, there is such an event parameter. Setting the cancel property to true indicates that the event is to be canceled.
// If it is an MDI container
If (Form. ismdicontainer)
// For each MDI subwindow
Foreach (Childform In Form. mdichil.pdf)
// Call its onclosing method. Once there is a hope that the cancel method will exit the loop.
Childform. onclosing (FLAG );
If (Flag. Cancel = True )
// I also want to finish the work before closing.
Form. onclosing (FLAG );
//The Return Value of the message is that if any sub-window or itself represents cancel, 0 is returned, and 1 is returned.
MSG. Result=Flag. Cancel? 0:1;
Through the above code, we can clearly see that when the window is modal, wndproc does not make any changes to the Message result, that is, the default 0. In other words, the system cannot be closed when the modal dialog box is displayed in. NET Framework.
As I have said before, I am ignorant and do not know whether this is a well-known problem. Therefore, although I have learned through the analysis of Il, this is indeed true. net Framework logic, but still do not know that this is what Ms deliberately did, or there is a special saying, or a bug.
However, since the modal dialog generated using the dialogbox macro in C ++ will not obstruct the shutdown, the defwindowproc will return true to wm_queryendsession on msdn, so at least it can be said. the modal dialog in Net Framework 1.1 violates previous principles.
To solve this problem, you only need to reload the wndproc method. When the form is displayed in modal mode and the return value of the seasonal message that receives the wm_queryendsession message is equal to 1.
Since we have analyzed the default wndproc il code, we can confirm that this will not cause any problems.
In addition, this issue has been fixed in. NET Framework 2.0. If you are interested, you can take a look at wndproc's il code in section 2.0. (If you are not familiar with IL, please use reflector and so on ).
Il is in a hurry. please correct me if there are any mistakes.