BBC BASIC for Windows
« Cascaded ON CLOSE »

Welcome Guest. Please Login or Register.
Apr 5th, 2018, 10:58pm



ATTENTION MEMBERS: Conforums will be closing it doors and discontinuing its service on April 15, 2018.
Ad-Free has been deactivated. Outstanding Ad-Free credits will be reimbursed to respective payment methods.

If you require a dump of the post on your message board, please come to the support board and request it.


Thank you Conforums members.

BBC BASIC for Windows Resources
Online BBC BASIC for Windows documentation
BBC BASIC for Windows Beginners' Tutorial
BBC BASIC Home Page
BBC BASIC on Rosetta Code
BBC BASIC discussion group
BBC BASIC for Windows Programmers' Reference

« Previous Topic | Next Topic »
Pages: 1  Notify Send Topic Print
 thread  Author  Topic: Cascaded ON CLOSE  (Read 1397 times)
Michael Hutton
Developer

member is offline

Avatar




PM

Gender: Male
Posts: 248
xx Cascaded ON CLOSE
« Thread started on: Jun 19th, 2010, 03:55am »

Richard,

I was wondering what your thoughts would be to add cascaded ON CLOSE handling to BB4W?

It could be a useful feature for library writers who would like to cleanup any objects their library creates without having the user to clean them in the main program.

For instance:
Code:
      REM Cascaded ON CLOSE Handling?
      
      ON CLOSE PROCCleanup:END
      
      PROC_INIT_MYLIB
      
      REPEAT
        WAIT 1
      UNTIL FALSE
      
      
      END
      
      DEFPROCCleanup
      PRINT "Cleaning!"
      ENDPROC
      
      DEFPROC_INIT_MYLIB
      PRIVATE MYLIBVARS{}
      PROCPRIVATE(MYLIBVARS{})
      MYLIBVARS.close% = !392
      ON CLOSE PROC_MYLIB_Cleanup : END
      
      REM Create my objects here and add their handles to the MYLIBVARS.handles%()

      ENDPROC
      
      
      DEF PROC_MYLIB_Cleanup
      PRINT "Cleaning the Library"
      PRIVATE MYLIBVARS{}
      PROCPRIVATE(MYLIBVARS{})
      
      REM Cleanup the objects
      LOCAL I%
      FOR I% = 0 TO 10
      IF MYLIBVARS.handle%(I%) THEN SYS"DeleteObject", MYLIBVARS.handle%(I%)
      NEXT

      !392 = MYLIBVARS.close%
      WM_CLOSE = &10
      SYS "SendMessage", @hwnd%, WM_CLOSE, 0,0
      
      ENDPROC
      
      DEF PROCPRIVATE(RETURN t{})
      PRIVATE p{}
      DIM p{close%. handle%(10)}
      !(^t{}+0) = !(^p{}+0)
      !(^t{}+4) = !(^p{}+4)
      ENDPROC
 


Although this works, it is not guaranteed to work if an ON CLOSE statement is defined after initialising the library...

An ON CLOSE LOCAL is obviously not appropriate for the library.

I think it could be a useful feature so that any ON CLOSE statement (not ON CLOSE LOCAL) adds a pointer to a linked list of pointers for code to be processed when a WM_CLOSE message is received by a window.

It may be a feature which would help with library encapsulation?

Michael
User IP Logged

admin
Administrator
ImageImageImageImageImage


member is offline

Avatar




PM


Posts: 1145
xx Re: Cascaded ON CLOSE
« Reply #1 on: Jun 19th, 2010, 10:11am »

on Jun 19th, 2010, 03:55am, Michael Hutton wrote:
I was wondering what your thoughts would be to add cascaded ON CLOSE handling to BB4W?

Well, as you know, I am treating the BBC BASIC for Windows interpreter as effectively frozen. So the question to ask is not what changes might be made to BB4W, but what workarounds are available without needing to make any changes.

It seems to me that the approach you've adopted is the right way to proceed. However, rather than restoring the ON CLOSE vector and sending another WM_CLOSE message, as you do, I would have been inclined to jump directly to the original handler, as below. It's easier and quicker.

Quote:
Although this works, it is not guaranteed to work if an ON CLOSE statement is defined after initialising the library...

I don't see that as an issue; the library simply has to specify that its initialisation function must be called after any ON CLOSE. Any theoretical extension to BB4W would need to impose a similar constraint, because automatically cascading ON CLOSE wouldn't be compatible with existing programs (and imagine what might happen if the ON CLOSE was in the main loop, something I quite often do!). By default a later ON CLOSE would have to replace the existing vector as now.

Code:
      REM Cascaded ON CLOSE Handling?
      
      ON CLOSE PROCCleanup:END
      
      PROC_INIT_MYLIB
      
      REPEAT
        WAIT 1
      UNTIL FALSE
      
      END
      
      DEFPROCCleanup
      PRINT "Cleaning!"
      ENDPROC
      
      DEFPROC_INIT_MYLIB
      PRIVATE MYLIBVARS{}
      PROCPRIVATE(MYLIBVARS{})
      MYLIBVARS.close% = !392
      ON CLOSE PROC_MYLIB_Cleanup : END
      
      REM Create my objects here and add their handles to the MYLIBVARS.handles%()
      
      ENDPROC
      
      
      DEF PROC_MYLIB_Cleanup
      PRINT "Cleaning the Library"
      PRIVATE MYLIBVARS{}
      PROCPRIVATE(MYLIBVARS{})
      
      REM Cleanup the objects
      LOCAL I%
      FOR I% = 0 TO 10
        IF MYLIBVARS.handle%(I%) THEN SYS"DeleteObject", MYLIBVARS.handle%(I%)
      NEXT
      
      PROC(^MYLIBVARS.close%)
      ENDPROC
      
      DEF PROCPRIVATE(RETURN t{})
      PRIVATE p{}
      DIM p{close%,handle%(10)}
      !(^t{}+0) = !(^p{}+0)
      !(^t{}+4) = !(^p{}+4)
      ENDPROC 

Richard.
User IP Logged

Michael Hutton
Developer

member is offline

Avatar




PM

Gender: Male
Posts: 248
xx Re: Cascaded ON CLOSE
« Reply #2 on: Jun 20th, 2010, 08:09am »

weird, I thought I had replied earlier on.... anyway:

I see your point about the problem if the ON CLOSE statement is in a loop.

I'll develop my thoughts a bit further, maybe a CLEANUPLIB could be fashioned to keep track of objects created by the user. For example, if someone creates an object

PROC_CLEANUPLIB_addObject( type )

and then the CLEANUPLIB could auto clean at any ON CLOSE event....

Michael
User IP Logged

admin
Administrator
ImageImageImageImageImage


member is offline

Avatar




PM


Posts: 1145
xx Re: Cascaded ON CLOSE
« Reply #3 on: Jun 20th, 2010, 09:36am »

on Jun 20th, 2010, 08:09am, Michael Hutton wrote:
weird, I thought I had replied earlier on

I've never known Conforums lose a post. Almost certainly what you did was click Preview but never click Post. You don't get any warning if you navigate away from the page without posting your message (the Wiki is better in that respect).

You didn't comment on my suggested modification to your code of jumping directly to the old ON CLOSE handler, rather than messily restoring the vector and sending another WM_CLOSE message. I think that's a very worthwhile improvement.

Richard.
User IP Logged

Michael Hutton
Developer

member is offline

Avatar




PM

Gender: Male
Posts: 248
xx Re: Cascaded ON CLOSE
« Reply #4 on: Jun 22nd, 2010, 12:33am »

on Jun 20th, 2010, 09:36am, Richard Russell wrote:
Almost certainly what you did was click Preview but never click Post.

Yes, I was pretty sure that is what I did. Frustrating.

Quote:
You didn't comment on my suggested modification to your code of jumping directly to the old ON CLOSE handler, rather than messily restoring the vector and sending another WM_CLOSE message. I think that's a very worthwhile improvement.

Although sending the message is clumsier, it could be safer. For example, what happens if, the main ON CLOSE statement ends with a RETURN (unlikely, but possible):

Code:
ON CLOSE RETURN
 


jumping with the PROC(^MYLIBVARS.close%) will give a "not in a subroutine" error, whereas sending a message to the window will produce the expected behaviour.

Michael
« Last Edit: Jun 22nd, 2010, 12:34am by Michael Hutton » User IP Logged

admin
Administrator
ImageImageImageImageImage


member is offline

Avatar




PM


Posts: 1145
xx Re: Cascaded ON CLOSE
« Reply #5 on: Jun 22nd, 2010, 08:48am »

on Jun 22nd, 2010, 12:33am, Michael Hutton wrote:
jumping with the PROC(^MYLIBVARS.close%) will give a "not in a subroutine" error, whereas sending a message to the window will produce the expected behaviour.

ON CLOSE RETURN is used to ignore the Close button (and Alt-F4) entirely, the idea being that the program will continue execution as if nothing happened.

In that case your suggestion won't produce "the expected behaviour". If the user presses Close or Alt-F4 it won't be ignored, instead your library will perform its cleanup but the program will keep running! The result is likely to be a failure when the program subsequently attempts to use one of your library functions.

So, in fact, my code is actually better than yours, precisely because it results in a 'Not in a subroutine' error! It alerts the user to the fact that he's used an ON CLOSE in a way that is not compatible with your 'cascaded' handling.

Nice try, but no cigar!

Richard.
« Last Edit: Jun 22nd, 2010, 08:51am by admin » User IP Logged

Michael Hutton
Developer

member is offline

Avatar




PM

Gender: Male
Posts: 248
xx Re: Cascaded ON CLOSE
« Reply #6 on: Jun 22nd, 2010, 10:08am »

I did think of that, as you say, using the RETURN statement with an ON CLOSE would invoke the cleanup of the Library objects potentially creating an error when they are encountered again.

The upshot is to warn the user of the Library not to use a RETURN with the ON CLOSE statement when using the library.

However, I don't see another explicit advantage of jumping straight to the ON CLOSE vectors code rather than sending a WM_CLOSE message to the window, except maybe the length of code. Isn't it six of one and half a dozen of the other?

Michael
User IP Logged

admin
Administrator
ImageImageImageImageImage


member is offline

Avatar




PM


Posts: 1145
xx Re: Cascaded ON CLOSE
« Reply #7 on: Jun 22nd, 2010, 11:40am »

on Jun 22nd, 2010, 10:08am, Michael Hutton wrote:
However, I don't see another explicit advantage of jumping straight to the ON CLOSE vectors code rather than sending a WM_CLOSE message to the window, except maybe the length of code. Isn't it six of one and half a dozen of the other?

Well, I gave you one good reason why jumping to the vector is better: it will result in a 'Not in a subroutine' error if the user has an ON CLOSE RETURN. Issuing an error must be better than relying on the user noticing a warning in the library documentation!

Another thing is that your code has a potential weakness. After you send the WM_CLOSE message, you immediately exit from PROC_MYLIB_Cleanup, and then you execute an END statement:

Code:
      ON CLOSE PROC_MYLIB_Cleanup : END 

END disables ON CLOSE altogether, so it's possible the user's handler may never be called, if the END gets executed before the WM_CLOSE message has worked its way through the system.

Admittedly this is an unlikely scenario, because the chances are that the user's ON CLOSE will have been activated (as a result of your WM_CLOSE message) before the interpreter reaches the END statement - but this could easily change if I modified BB4W. For example, one thing I've considered more than once is testing for an 'interrupt' not every statement but (say) every five statements, to reduce the overhead. If I made that change your code would be guaranteed to fail.

Of course you could overcome this problem by following the SYS "SendMessage" with an 'infinite loop', rather than exiting via the ENDPROC to the END statement:

Code:
      SYS "SendMessage", @hwnd%, WM_CLOSE, 0,0
      REPEAT : WAIT 0 : UNTIL FALSE 

But why use a complicated solution when a simpler, faster, more straightforward one is available?

Richard.
User IP Logged

admin
Administrator
ImageImageImageImageImage


member is offline

Avatar




PM


Posts: 1145
xx Re: Cascaded ON CLOSE
« Reply #8 on: Sep 24th, 2010, 4:32pm »

It's taken a while, but I've finally worked out how to do this elegantly. The technique is described in this Wiki article:

http://bb4w.wikispaces.com/Cascaded+ON+CLOSE+handling

Here's the code of a demo program:

Code:
      PRINT "Click Close  to test cascaded ON CLOSE handling"
      PRINT "Press Escape to test cascaded ON ERROR handling"
      PRINT
 
      ON ERROR PRINT "Error handled in Main: " REPORT$ : END
      ON CLOSE PRINT "Close handled in Main" : END
      PROC0
      END
 
      DEF PROC0
      LOCAL dummy
      ON CLOSE LOCAL ERROR 111, "Close"
      ON ERROR LOCAL RESTORE LOCAL \
      \ IF ERR = 111 PRINT "Close handled in PROC0" : PROCclose ELSE \
      \ PRINT "Error handled in PROC0" : ERROR ERR,REPORT$
      dummy = FN1
      ENDPROC
 
      DEF FN1
      ON CLOSE LOCAL ERROR 111, "Close"
      ON ERROR LOCAL RESTORE LOCAL \
      \ IF ERR = 111 PRINT "Close handled in FN1" : PROCclose ELSE \
      \ PRINT "Error handled in FN1" : ERROR ERR,REPORT$
      PROC2
      = 1
 
      DEF PROC2
      ON CLOSE LOCAL ERROR 111, "Close"
      ON ERROR LOCAL RESTORE LOCAL \
      \ IF ERR = 111 PRINT "Close handled in PROC2" : PROCclose ELSE \
      \ PRINT "Error handled in PROC2" : ERROR ERR,REPORT$
      REPEAT
        WAIT 1
      UNTIL FALSE
      ENDPROC
 
      DEF PROCclose
      IF !392 PROC(^@%+392) ELSE QUIT
      ENDPROC 

Richard.
« Last Edit: Oct 8th, 2010, 3:20pm by admin » User IP Logged

Michael Hutton
Developer

member is offline

Avatar




PM

Gender: Male
Posts: 248
xx Re: Cascaded ON CLOSE
« Reply #9 on: Oct 8th, 2010, 12:37pm »

I think I understood the code but surely this is still a ON CLOSE LOCAL solution. I am not sure I can see how to incorporate this code into a library which would take care of it's own clean up of objects it creates unless you ask the programmer to put their main program in a PROC (in this case PROC2) which the library calls. Hence if an ON CLOSE is detected in PROC2 the cascading clean up is performed.

As soon as you exit the PROC2 all the ON CLOSE LOCALs are 'forgotten'. Or yet again have I missed the point.

Michael

User IP Logged

admin
Administrator
ImageImageImageImageImage


member is offline

Avatar




PM


Posts: 1145
xx Re: Cascaded ON CLOSE
« Reply #10 on: Oct 8th, 2010, 3:17pm »

on Oct 8th, 2010, 12:37pm, Michael Hutton wrote:
I am not sure I can see how to incorporate this code into a library which would take care of it's own clean up of objects it creates

Sorry, I'm being a bit slow today (it doesn't help having a nasty cough for the last 7 weeks that won't go away). You'll have to explain what you mean in more detail.

As an experiment I've transferred PROC2 into a library, to simulate the situation you describe. There's nothing 'shared' between the library and the main prog as far as I can see (I've chosen a different error code and called PROCclose something different) and the main prog doesn't have to know that any 'local' CLOSE handling happens in the library. But it all seems to work as it did before.

Quote:
As soon as you exit the PROC2 all the ON CLOSE LOCALs are 'forgotten'.

In what sense "forgotten"? If I move the WAIT code out of PROC2 and instead put it in FN1 after the PROC2 statement, a CLOSE still seems to be trapped at each 'level'.

Richard.

Don't put an apostrophe in ITS unless you mean IT IS: http://www.youtube.com/watch?v=Vc2aSz9Ficw
User IP Logged

admin
Administrator
ImageImageImageImageImage


member is offline

Avatar




PM


Posts: 1145
xx Re: Cascaded ON CLOSE
« Reply #11 on: Oct 8th, 2010, 4:58pm »

on Oct 8th, 2010, 12:37pm, Michael Hutton wrote:
I think I understood the code but surely this is still a ON CLOSE LOCAL solution.

The title of this thread is Cascaded ON CLOSE so of course it's an ON CLOSE LOCAL solution, because that's what you need in that case! In the same way, the solution to the Cascaded ON ERROR problem is an ON ERROR LOCAL solution.

If you're asking about a situation where a library creates a global object, which then needs to be cleared up when the program is eventually closed, that's got nothing to do with cascaded ON CLOSE or ON ERROR handling, and is off-topic for this thread.

The solution to that issue is for the library to provide its own cleanup procedure that the user must call from the main program in his global cleanup code, typically activated from both his ON ERROR and ON CLOSE handlers. Many libraries have just that:

  • COMLIB has PROC_comexit
  • GDIPLIB has PROC_gdipexit
  • MDILIB has PROC_exitmdi
  • SOCKLIB has PROC_exitsockets
etc.

Richard.
User IP Logged

Pages: 1  Notify Send Topic Print
« Previous Topic | Next Topic »

| |

This forum powered for FREE by Conforums ©
Terms of Service | Privacy Policy | Conforums Support | Parental Controls