Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Cancel Ongoing Program 4

Status
Not open for further replies.

TheLazyPig

Programmer
Sep 26, 2019
96
PH
Hi!

Is there a way where you can cancel an ongoing program like pressing Esc to cancel it, or it is only on the task manager?


Thanks.
 
You can interrupt a running program in the development environment by pressing the ESC key. In the run-time environment, you would need to have a trigger key assigned to CLEAR EVENTS in order to cancel the program using ON KEY command.

Greg
 
Actually not straight forward...

If you're in a modal state - and one example of it is a MessageBox or a report preview, CLEAR EVENTS is just queued for until the modal state ends.
A simple example:
Code:
On Key Label F2 REPORT FORM Home()+"Tools\FileSpec\90frx.frx" PREVIEW
On Key Label F3 CLEAR EVENTS
READ EVENTS
MESSAGEBOX('The End')

Run this, now first press F2, then press F3 while the report preview is active. Exit the report preview and the Messagebox will show. So CLEAR EVENT is not always immediate.
It's still valid to have a READ EVENTS in your VFP project and to have a place where the matching CLEAR EVENTS is run, so that's not saying CLEAR EVENTS doesn't work. A usual place for CLEAR EVENTS is the destroy event of a main application form. Or a menu item for quitting. It's normal that you then will cause it at the right moment, whenever you're in a modal state you can't pick the menu item and can't close the main form, so you never will have the CLEAR in a suspended state that still waits for the ongoing code to stop. So it's all natural and does not need a menu item enforcing the CLEAR EVENTS with prefixed CANCELs, but it does not work ON KEY, as you can be stuck in a modal state.

It's actually the well known problem of exiting an application when the user leaves the workstation with the application in a modal state.

A bit more drastic is
Code:
On Key Label F2 REPORT FORM Home()+"Tools\FileSpec\90frx.frx" PREVIEW
On Key Label F3 QUIT
READ EVENTS
MESSAGEBOX('The End')

Do that and when you press F3 you now get the infamous "Cannot Quit Visual Foxpro"

So lets get even more aggressive:
Code:
On Key Label F2 REPORT FORM Home()+"Tools\FileSpec\90frx.frx" PREVIEW
On Key Label F3 QUIT
On Shutdown QUIT
READ EVENTS
MESSAGEBOX('The End')
Well, in this case F3 will end the report preview, but not the program, you need to press F3 twice to quit. And no, it's not that the first QUIT cancels the PRG and the second exits the IDE, you can check that for yourself. Press F2, then F3 once and the preview vanishes, but click on the Program menu. You'll see the menu items "Cancel" and "Suspend" are active, which means the PRG still runs and now is at the READ EVENTS. The next F3 does QUIT and that does not only end the PRG but also the IDE. And you also see you don't get to the code after READ EVENTS, the messagebox does not appear.

So if you still want something that quits the application in one step you need to go for API and use ExitProcess:

Code:
Declare Long ExitProcess in Win32API Long Exitcode
On Key Label F2 REPORT FORM Home()+"Tools\FileSpec\90frx.frx" PREVIEW
On Key Label F3 ExitProcess()
READ EVENTS
MESSAGEBOX('The End')
Well, it is drastic, it exits the process at any time.

For something that's less drastic you can use CANCEL:
Code:
On Key Label F2 REPORT FORM Home()+"Tools\FileSpec\90frx.frx" PREVIEW
On Key Label F3 CANCEL
READ EVENTS
MESSAGEBOX('The End')

It's like QUIT again, as the first CANCEL ends the preview but not the PRG, but the second F3 will now cancel the PRG, but then it's less aggressive as QUIT and does not quit the IDE. It's still not getting to the point after READ EVENTS, as that needs the CLEAR EVENTS. So ideally you'd have something that does CANCEL until the stack is on the level of the READ EVENTS and then can do CLEAR EVENTS. It may need more than one cancel, though. It's really not easy to get to after READ EVENTS.

The simplest for you as developer debugging is establishing a key for SUSPEND, then you have anything at your hand, like the debugger, to do further steps: So this would be my setup for developing:

Code:
On Key Label F2 REPORT FORM Home()+"Tools\FileSpec\90frx.frx" PREVIEW
On Key Label F3 SUSPEND
READ EVENTS
MESSAGEBOX('The End')

When in suspended mode you can use command window and debugger, you can do CANCEL, for example and then CLEAR EVENTS and are using the intended path and see the messagebox, which in a real scenario may instead be code that handles all open transactions and forms.

You can also do things like SET ESCAPE ON at runtime and allow end users of an EXE to cancel code by pressing ESC. It's not a good thing to allow, therefore the default setting of it is OFF at runtime. Just like there are defaults for all environment settings that can differ in IDE and EXE (runtime mode does not have the opposite settings for everything, though).

For developing and debugging I have SUSPEND on a function key, but not set this up for runtime mode, so you can have your developer belt on with
Code:
If _vfp.StartMode = 0
   On Key Label F12 SUSPEND
Endif
Makes it easy to remember for me as F12 also goes into developer tools/mode in Web browsers, too. CANCEL is possible by ESC key, so no need to define this.

If you want to you can of course allow an ExitProcess at runtime, it does not do more harm than using the task manager to kill the vfp process, which can only be taken away from users under special circumstances like group policies removing that or running Windows in kiosk mode. It shouldn't be made too easy to happen accidentally hitting some function key alone, so perhaps make it a hotkey like ALT+F12. It doesn't have to be ON KEY, but can be a menu item with hot key. Be aware that this solution does not run your code after READ EVENTS. So instead of calling ExitProcess you may set up a function key to call your finalization code, which ends in ExitProcess.

Chriss
 
Surely, the answer to the question depends on why - and under what circumstances - you want to cancel the program.

In particular, do you want to give the user the ability to cancel the program? In other words, do you want to include some sort of control within the user interface, such as a Quit button or a menu option, that would close the program? If so, then basically you need CLEAR EVENTS. But you might also need to do some clean up, such as closing open form, releasing active objects, etc. (Arguably, this is not "cancelling" the program; it is the normal shutdown procedure.)

Or, do you want a way of coming out of the program if the program is hanging? As far as I know, there is no way of doing that natively within VFP. The usual solution would be to use the Task Manager.

Or, do you want to cancel the program after a serious run-time error? If so, then it depends on whether you have an active error handler (that is, a routine that is invoked by ON ERROR). If you haven't, and a run-time error occurs, the user will see a message asking if they want to cancel the program, retry, or ignore the error. This is a terrible user interface design. Nine times out of ten, the user will want to ignore the error, in the mistaken belief that it will make the error go away. In fact, it simply continues execution at the next command, despite the fact that the program is now in an unstable state. This is to be avoided.

If you have a serious runt-time error, and you do have an active error-handler (which is recommended), then you would normally just issue QUIT within the error-handler (after informing the user of the error). However, this raises more problems. If the program is in a modal state, QUIT will generate a "Cannot quit Visual Foxpro" message. Even if that's not the case, there are still several things that could prevent the app from closing. For example, you may have code in a form's QueryUnload that asks the user to confirm that they want to close the form. If the user answers No, the form won't close and the program won't quit - even though the error condition is still in force.

To avoid that, you could do the following: roll back all active transactions; revert all buffered updates in all data sessions; then execute this code:

[tt]DECLARE Integer ExitProcess IN WIN32API
ExitProcess()[/tt]

The above code will kill the application stone dead - no IFs or BUTs - just as if you had cancelled it within the Task Manager. This is not something you would do lightly, but it is better than allowing the program to continue after a serious run-time error has occurred.

Mike


__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
One more comment on finalization code.

You don't need something like this:
Code:
Do While TXNLEVEL()>0
   ROLLBACK
Enddo

Transactions are made for the situation your application crashes or there even is a power outage, to not leave DBFs in an intermediate state.

In a real crash you won't be able to run your finalization code, by definition of what crash means. If at all, a crash situation hands control over to the runtime, a fatal error results in an C5 error and even the C runtime then only logs it and quits. So we'll only need to take care of situations that are not in that drastic fatal error crash scenario. And then just quitting also closes all file handles, rolls back all transactions. What's done when remote connections are closed depends on the mode of the connection, that can be rollbacks or commits, by the way, see SQLSETPROP about Transactions.

So it's actually not harmful to not have own finalization code in terms of health of DBF files and database transactions. Also in terms of open file handles, file and record locks. It's one of the reasons licensing systems limiting users by numbers of concurrent record locks is a nice concept, as a lock is removed even if an exe crashes so there is no need for a graceful normal exit.

So the only need for finalization code is handling something that's not handled automatically. A normal application end could write out to some application state log file, for example. IIRC the codebook framework and frameworks based on codebook do that. That could be picked up at the next start, so an application knows when it terminated abnormally, because the usual finalization entries in such a log are missing, i.e. the main.prg could check the last record or line to be what is expected for a normal termination. And yes, you can fool the start assuming a normal termination when manually adding such a log entry, but not unless you know about it.

I guess your need is during development to get into debugging something like an unexpected endless loop, a too long running state you want to know what's currently going on, then use a hotkey for SUSPEND, that's all you need. ESC or your own hotkey doing CANCEL won't suspend the current code and enable to debug it, you'd just end it and likely won't even know where the endless loop is in your code. So SUSPEND is really the best thing you can do within the IDE with a hotkey.

Chriss
 
Finally, be assured I don't write all this to protest against Gregs answer.

It's working most of the time and where it doesn't you'd intuitively close a messagebox, exit a preview or whatever and end the application anyway.

Just if it happens CLEAR EVENTS doesn't act as expected, you could find out why here. Also ,since READ EVENTS is normally done in a main.prg you do need a matching CLEAR EVENTS, and that can be a hotkey or a menu item with a hotkey, no problem. It's absolutely not wrong, but then not necessarily explicitly quitting.

An open question is, can you force VFP after READ EVENTS somehow? Is there any code that always gets you there? Surely not with ExitProcess, also not with CANCEL and QUIT, as demonstrated. The only way to get after READ EVENTS is CLEAR EVENTS, but it must be done while the runtime is in the state waiting for events, which is READ EVENTS. So a consequence of that is programming in a way to avoid modal states unless absolutely necessary.

Also the question then becomes can you do something that ensures the runtime gets to READ EVENTS, so a CLEAR EVENTS will work? There is some light on the horizon. But it's not a single command or API call.

Chriss
 
Thank yo Mike and Chriss... very comprehensive elaboration as always... Im thinking to use and add to my application... God bless....
 
Here's a minimalistic main.prg that gives a motivation to use an application object to have read events in it instead of having it in main.prg, which enables RETURN TO MASTER to play out its advantage over anything else:
Code:
Clear
On Key Label F10 Return To Master

goApp = Createobject("vfpApplication")
goApp.ReadEvents()
? 'could do finalization code here in the PRG'
goApp = .Null.
Release goApp

On Key Label F10
Messagebox('The End')

Define Class vfpApplication As Custom   
   Procedure ReadEvents()
      ? 'going into read events mode'
      Read Events
   Endproc

   Procedure Destroy()
      ? 'could do finalization code here in DESTROY'
   Endproc
Enddefine

The case of it working easier than CLEAR EVENTS is when you get stuck in an endless loop. So add this to above code, first in the section of ON KEYs:
Code:
On Key Label F2 endlessloop()
On Key Label F9 CLEAR EVENTS

Then add this function somewhere, for example at the end of the PRG:
Code:
Procedure endlessloop()
   Do While .T.
   Enddo
Endproc

Now start the modified code, press F2 to get into an endless loop, press F9 trying CLEAR EVENTS and then see that F10 doing RETURN TO MASTER can exit this. It's good to know all things about READ EVENTS/CLEAR EVENTS, QUIT, CANCEL, ON...ERROR/SHUTDOWN/ESCAPE/... but also RETURN TO MASTER.

Chriss
 
Btw, it is sufficient the READ EVENTS is on another stack level, so a Readevents procedure is enough.

Chriss
 
There still are cases not covered with return to master, a Messagebox, too. but it interrupts a running program, whereas CLEAR EVENTS just is like queuing an exit until the current stack level is left. I often have seen people expect CLEAR EVENTS to immediately jump to the line after READ EVENTS. Just like QUIT is often assumed to exit immediately. Quit causes the ON SHUTDOWN event and for all running forms the QueryUnload with Form.ReleaseType set to 2 (Exit Visual Foxpro). And in QueryUnload you could still stop the QUIT by NODEFAULT.

So the only other hammer that's still available is ExitProcess.

Chriss
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top