Home page Home page Home page Home page
Pixel Header R1 C1 Pixel
Pixel Header R2 C1 Pixel
Pixel Header R3 C1 Pixel
By Sprezz | Tuesday 18 February 2014 17:22 | 0 Comments

The Problem

A client contacted us recently to complain that when they were running long reports, the OpenInsight Window would freeze and the caption bar would have "(Not Responding)" added. Rather cleverly the client had got around this by generating the source code for the RLIST routine (a trick we haven't used for quite some time) and adding calls to yield().But as they pointed out, it would be a lot of work to do this for every report in the application.

They wanted to know if there was a better way.


Well here at Sprezz Towers, providing better ways is our raison d'être, so we provided an answer. But before examining our response it might be instructive to examine exactly what is going on and why.

Applications running on the Windows desktop run under the control of the Desktop Windows Manager (DWM), which places any messages for the application (such as mouse movements or keystrokes) into a queue for processing. If the application doesn’t check this queue for five seconds the DWM assumes that the application has hung and displays a ghosted bitmap of the application screen with "(Not Responding)" in the caption area. It does this rather cleverly so that the user can move the screen around, minimise it or close it. If it didn't do this clever sleight of hand then the user wouldn't be able to do any of the above because the application is ignoring its message queue and so won't see, for example, the close message.

This might seem a little harsh but five seconds is a long time for an operating system. It'd be like leaving a telephone ringing for a couple of centuries before deciding there's no one there.

So the question remains - how do we allow OpenInsight to process its message queue from within an RLIST statement? There are at least three solutions.

Solution 1 - The end user driven solution 

As discussed above, the ghost bitmap will only appear if there have been no messages processed by the application for five seconds.  If there are no messages to process then the application can do what it wants for as long as it wants without the DWM caring. So you could try telling your end user not to touch ANYTHING after launching the report. (Good luck with this solution).

Solution 2 - The dictionary driven solution

Again, the message will only appear if OpenInsight it unable to process its message queue. If we allow the message queue to be processed ourselves then the message won't appear. This is actually easier than it seems. All we need to do is to include a symbolic dictionary item in our R/List select statement that is ALWAYS false and that yields to allow OpenInsight to process its queue. Of course we don't want to risk having global variables swapped out from underneath us, nor do we want to yield on every iteration. So we could create a formula that looked something like this :-

   //* Only yield every 10 rows processed
   if mod(@Rn.Counter, 10) = 0 then
      goSub safeYield

   @Ans = 0


   saveAtDict_      = @dict
   saveAtRecord_    = @record
   saveAtID_        = @id
   saveAtRecCount_  = @recCount
   saveAtRnCounter_ = @rn.Counter

   call push.Select( A_, B_, C_, D_ )
   call yield()
   call pop.Select( A_, B_, C_, D_ )

   transfer saveAtDict_     to @dict
   transfer saveAtRecord_   to @record
   transfer saveAtID_       to @id
   transfer saveAtRecCount_ to @recCount

   @rn.Counter = saveAtRnCounter_

then assuming the above was called YIELD_SYM we could just append " OR WITH YIELD_SYM" onto our sentence,

Solution 3 - The brute force solution

If you're convinced that your user will NEVER have to see the "(Not Responding)" message as none of your code will ever go recursive then you can simply tell Windows that you don't want to allow ghosting. Simply add this definition to the appropriate DLL_Definition row in SYSPROCS (we use DLL_WINAPI_USER32 as we've explained before) and add the line

VOID STDCALL DisableProcessWindowsGhosting(VOID) as winAPI_DisableProcessWindowsGhosting

Then just run declare_fcns against the appropriate SYSPROCS entry and within your startup program (or anywhere else for that matter) just call winAPI_DisableProcessWindowsGhosting passing it no parameters and you won't be bothered by the message while the current copy of OpenInsight is running. But if you do this, remember that the user won't be able to minimize, move, or close the main window of your application if it is REALLY not responding - they'll have to use the Task Manager if they want to close.
Pixel Footer R1 C1 Pixel