To the main page...The list of my products...Some texts...Sample applications, tips, tricks...If you need support...
 

 
Advanced interactive service
Step 2. Testing the simple interactive service configuration

Well, our service in it`s current state should be able to show form and survive logoff and logon. To ensure in it install the service using the /install switch and start it using control panel. As you see the service successfully starts and form shows immediately after it. Do not close it and try to logoff and logon again. As you see the service successfully survives logoff and logon, the service form is visible.

One could stop at this point and say that our aim is reached. Unfortunately it is not so. It occurs that logoff and logon changes some essential data that are used by VCL. I've spent a lot of time trying to understand two strange effects1.

The first one concerns FindControl function and docking functionality. The thing is that Delphi uses global atoms to link window handle and Delphi control class. To do it Delphi calls SetProp API function. The second parameter of this function is a global atom registered with GlobalAddAtom call. Delphi do registers necessary atoms in the initialization section of the Controls unit. So far so good. The only thing is that global atoms are the property of desktop. When logoff occurs the interactive desktop destroys and all global atoms destroys too. When users log on again the new interactive desktop is created by operating system and it does not contain previously registered atoms. As a result calls to SetProp method may fail2 causing malfunction of docking mechanism, FindControl function and all other methods that use atoms.

The second problem is inability to create new forms after logoff/logon occurs. Let's modify our example to test it. At first add a couple of controls to the service form. Then add a button that will create one more instance of service form when clicked:



 
 

 
 

 




 
 

procedure TServiceMainForm.BnNewMainFormClick(Sender: TObject);
begin
    with TServiceMainForm.Create(Self) do
    begin
        Caption:=Caption+' - It is a child form';
        Show;
    end;
end;

procedure TServiceMainForm.FormClose(Sender: TObject;
  var Action: TCloseAction);
begin
    Action:=caHide;
end;

The resulting code will look like this one (zip, 3kb). Well, now this example can be tested. Do not forget to reinstall the service if you've compiled it in another directory. Use /reinstall switch for this purpose.

Ok, start the service. You will see that service form appears. Click the button to create the new form. As you see the form`s created successfully. Now try to logoff and logon again. Both service forms survive it. Well, click a button to create a new form instance. You will see something like this:

Corrupted form screenshot

Nice result. All form controls are visible while the form itself does not paint itself. On the screenshot the Control Panel window was below the service form so it`s footprint remains on the service form. Another problem: in spite all controls are visible they do not work, buttons do not react on clicks, for example. This problem is much more wide then it seems on the first look. It occurs that all other forms do not work too, including ShowMessage window, MessageDlg window, database dialogs and so on. Even exception window becomes corrupted after logoff/logon occurs! The worst of it is that all these windows are modal and inability to normally close them results to the reboot necessity3!

To illustrate it add corresponding event handlers to buttons:





 
 



 
 



 
 


 
 
 


 
 
 


procedure TServiceMainForm.BnShowMessageTestClick(Sender: TObject);
begin
    ShowMessage('This message is shown from service');
end;

procedure TServiceMainForm.BnFileOpenDialogTestClick(Sender: TObject);
begin
    OpenDialog.Execute;
end;

procedure TServiceMainForm.BnMessageDlgTestClick(Sender: TObject);
begin
    MessageDlg('It is show from service',mtInformation,[mbOk],0);
end;

procedure TServiceMainForm.TimerTimer(Sender: TObject);
begin
    SBrCurrentTime.SimpleText:=DateTimeToStr(Now);
end;

procedure TServiceMainForm.BnAddInputClick(Sender: TObject);
begin
    MInput.Lines.Add(EdInput.Text);
end;

As you see I've added some more code to our example. It is done to implement more functionality and test it`s behavior after logoff/logon. The full example code in it`s current state can be downloaded here (zip, 3kb). Test it and you will see that standard system dialog (File Open) successfully survives logoff/logon while Delphi windows becomes non-operated. Screenshot below shows for example what occurs with MessageDlg window:

MessageDlg window after logoff/logon

Well, the problem is evident. The solution follows on the next step.

1. This example shows not only "how to" but "what would be if" too. Most negative effects described here concern Windows NT and Windows 2000 only.

2. I guess it depends on installed NT Service Pack. I've tried to reproduce the FindControl errors writing this example and I was unable to do it! In any case it is strange: if SetProp really works without registering global atom then why to register it as it stated in the MS documentation?

3. For debug purposes the starting Task Manager in the Local System account is acceptable. The AT command can be used for it. Similar example with regedit was considered earlier. After Task Manager starts in Local System account it has rights to kill any application including our dead example. Be accurate and do not kill your system!

<< | Index | Step 1 | Step 2 | Step 3 | Step 4 | Step 5 | Conclusions | >>
Add your comment | Read comments


 
© 1998-2001 Alexey Dynnikov
My ICQ # is 18267212