Articles   Members Online:
-Article/Tip Search
-News Group Search over 21 Million news group articles.
-Delphi/Pascal
-CBuilder/C++
-C#Builder/C#
-JBuilder/Java
-Kylix
Member Area
-Home
-Account Center
-Top 10 NEW!!
-Submit Article/Tip
-Forums Upgraded!!
-My Articles
-Edit Information
-Login/Logout
-Become a Member
-Why sign up!
-Newsletter
-Chat Online!
-Indexes NEW!!
Employment
-Build your resume
-Find a job
-Post a job
-Resume Search
Contacts
-Contacts
-Feedbacks
-Link to us
-Privacy/Disclaimer
Embarcadero
Visit Embarcadero
Embarcadero Community
JEDI
Links
how to correctly handle Windows shutdown in complex applications Turn on/off line numbers in source code. Switch to Orginial background IDE or DSP color Comment or reply to this aritlce/tip for discussion. Bookmark this article to my favorite article(s). Print this article
Correct handling of Windows shutdown in complex applications 28-Sep-03
Category
Win API
Language
Delphi 3.x
Views
120
User Rating
No Votes
# Votes
0
Replies
0
Publisher:
DSP, Administrator
Reference URL:
DKB
			Author: Eugene Mayevski 

In complex applications it is necessary to correctly process all application 
finalization steps like OnClose and OnDestroy event handlers for all forms and Data 
Modules. However after the application has responded to WM_ENDSESSION message (and 
TApplication does this automatically) lots of API functions fail due to system 
shutwdown. How to ensure, that all OnDestroy handlers will work correctly? 

Answer:

First let's take a look at the following code: 

1   project XXX;
2   {... }
3   var
4     DM: TMyDataModule;
5   
6   begin
7     DM := TMyDataModule.Create;
8     {... }
9     Application.Run;
10    DM.Free;
11  end;
12  
13  procedure TMyDataModule.DataModuleDestroy(Sender: TObject);
14  var
15    I: Integer;
16    J: integer;
17  begin
18    for i := 0 to 5 do
19    begin
20      MessageBeep(MB_ICONQUESTION);
21      if MessageBox(0, PChar('Datamodule destroying - ' + IntToStr(i)), nil,
22        MB_SYSTEMMODAL) = 0 then
23      begin
24        j := GetLastError;
25        MessageBeep(MB_ICONEXCLAMATION);
26        MessageBox(0, PChar('MessageBox error - ' + IntToStr(j)), nil, 
27  MB_SYSTEMMODAL);
28      end;
29    end;
30    MessageBeep(MB_ICONEXCLAMATION);
31    MessageBox(0, 'Datamodule destroyed', nil, MB_SYSTEMMODAL);
32  end;


Our goal is to get 7 messageboxes. 
If you reproduce this code in your application, you will get one message box 
window, that will immediately disappear. That is not what we want. What should we 
do? 
The solution is to not tell windows that the application can be closed until 
OnDestroy is executed. But if the message is processed in window message 
dispatching loop, how can we get out of the loop without returning control to 
Windows? 
Let's take a look at threads. Windows starts to send WM_ENDSESSION after all 
windows return 1 in responce to WM_QUERYENDSESSION. And the solution is simple: 
create a window in another thread and let it process WM_QUERYENDSESSION message in 
the way, that will shutdown our application correctly. The code in brief is: 

33  if Msg.Msg = WM_QUERYENDSESSION then
34  begin
35    Synchronize(CloseApp);
36    WaitForSingleObject(StopWatcherEvent, INFINITE);
37    ResetEvent(StopWatcherEvent);
38    Msg.Result := 1;
39  end
40  else
41    {  ... }


CloseApp function calls Application.MainForm.Close. The application is closed. 
StopWatcherEvent is set only in finalization clause, which is executed after all 
forms and datamodules are destroyed ;). 

Here is the complete code of the watcher unit. It has been tested under Windows NT 
4.0 SP6. 
42  
43  {====================================================}
44  {                                                    }
45  {   EldoS Visual Components                          }
46  {                                                    }
47  {   Copyright (c) 1998-2000, EldoS                   }
48  {                                                    }
49  {====================================================}
50  
51  unit ElShutdownWatcher;
52  
53  interface
54  
55  implementation
56  
57  uses
58    Forms, Classes, Windows, Messages, SysUtils;
59  
60  type
61    TShutdownThread = class(TThread)
62    private
63      Wnd: HWND;
64      procedure WndProc(var Msg: TMessage);
65      procedure CloseApp;
66    protected
67      procedure Execute; override;
68    end;
69  
70  var
71    StopWatcherEvent: THandle;
72  
73  procedure TShutdownThread.CloseApp;
74  begin
75    if (Application.MainForm <> nil) and (not Application.Terminated) then
76      Application.MainForm.Close
77    else
78      PostMessage(Application.Handle, WM_QUIT, 0, 0);
79  end;
80  
81  procedure TShutdownThread.WndProc(var Msg: TMessage);
82  begin
83    if Msg.Msg = WM_QUERYENDSESSION then
84    begin
85      Synchronize(CloseApp);
86      WaitForSingleObject(StopWatcherEvent, INFINITE);
87      ResetEvent(StopWatcherEvent);
88      Msg.Result := 1;
89    end
90    else
91      DefWindowProc(Wnd, Msg.Msg, Msg.wParam, msg.lParam);
92  end;
93  
94  procedure TShutdownThread.Execute;
95  var
96    Msg: TMsg;
97    i: LongBool;
98  begin
99    StopWatcherEvent := CreateEvent(nil, true, false, nil);
100   Wnd := AllocateHWND(WndProc);
101   repeat
102     i := GetMessage(Msg, 0, 0, 0);
103     if i = TRUE then
104     begin
105       TranslateMessage(Msg);
106       DispatchMessage(Msg);
107       if WaitForSingleObject(StopWatcherEvent, 0) = WAIT_OBJECT_0 then
108         break;
109     end;
110   until i <> TRUE;
111   DeallocateHWND(Wnd);
112   CloseHandle(StopWatcherEvent);
113   StopWatcherEvent := 0;
114 end;
115 
116 var
117   Watcher: TShutdownThread;
118 
119 initialization
120 
121   Watcher := TShutdownThread.Create(true);
122   Watcher.FreeOnTerminate := true;
123   Watcher.Resume;
124 
125 finalization
126   if StopWatcherEvent <> 0 then
127     SetEvent(StopWatcherEvent);
128 
129 end.


			
Vote: How useful do you find this Article/Tip?
Bad Excellent
1 2 3 4 5 6 7 8 9 10

 

Advertisement
Share this page
Advertisement
Download from Google

Copyright © Mendozi Enterprises LLC