|Interactive Service Instability: What Occurs and What to Do|
|Published Apr 2, 2001|
I had some experience developing interactive services even before SvCom project was started but these services were simple enough. When SvCom project was started I've realized that it must support creation interactive services too. The first step in this direction was publication of an example how to implement interactive service using SvCom. At that time the main problem was the multi-threading nature of service application while VCL is not thread-safe. This problem was solved by placing interactive part of service into separate dll that had its own copy of VCL code and data.
Another approach to the same problem was to use synchronization to place all interactive forms back into main thread of application. But when it was done the new problem have arose: after logoff/logon the newly created forms were corrupted! You can see a screenshot of such form below:
It seems that the form is simply transparent but it is not so. This form simply does not process windows messages. The only exception are "basic" windows messages such as resize, closing, drawing caption and so on.
The investigation of this problem shown that something wrong occurs with WindowProc of every form that is created after logoff/logon. To work around this problem the special TsvSurviver component was developed. You can see the example of its usage in the Advanced Interactive Service example.
So far so good, but approximately at the Summer of 2000 I've got several messages from SvCom users. They informed me about strange problem: it occurred that from time to time interactive service causes and AV and fails after logoff/logon on Windows 2000. Quick tests shown that the problem is not caused by SvCom. Further investigation performed by Dejan Maksimovich shown that likely the reason of the problem is inside code of VCL. This conclusion was drawn from the fact that interactive services created without Delphi do not demonstrate such instability.
Of course I'm not the only person who observed or investigated this problem. You can find a lot of related topics in the Borland's Newsgroups for example. The only aim of this article is to demonstrate the reason of the problem and (which is even more important) to suggest you the solution.
First of all a several words about the reason of interactive service fault.
It should be evident that Windows do not know anything about Delphi applications and VCL. It deals with window handles, handles of menus, accelerators and other pure Windows stuff. On the other side Delphi should be able to find controls using giving window handles. This operation is necessary in various situations: to process drag'n'drop operations, mouse tracking and many other tasks. Delphi has special functions FindControl that returns TWinControl that owns given window handle. This function lives inside of Controls unit. Look on it:
As you see the GetProp API function is used to retrieve control pointer from window handle. Of course this pointer was placed there using SetProp function when window handle was allocated. The most important thing in this code is usage of ControlAtom. It is the global atom registered by Delphi application at startup.
The idea to store control's pointer as property of window is really perfect - but for regular applications only. The thing is that the table of global atoms is a property of desktop and it is cleared when logoff/logon occurs. So after logoff/logon it becomes possible to receive an invalid value using GetProp method. As you see the FindControl does not perform any checks of returned value. As a result an attempt to use returned value as a Delphi control can cause access violation. It is this reason cause service instability after logoff/logon.
Well, now we are ready to proceed with solution. Below you see links to the updated version of TsvSurviver component:
The usage of the TsvSurviver component was not changed, you can refer the Advanced Interactive Service example for details. In any case please read the readme.txt file inside archives.
And finally a link that can be helpful if you intend to use common Windows controls in your interactive services: http://support.microsoft.com/support/kb/articles/Q238/7/21.ASP (many thanks to Danny Thorpe for posting this link into my Forum). Please note the TsvSurviver does not solves this problem yet (how it could to do it?)
Finally I would like to thank everybody who helped me with ideas, experience and time.