1

When my application needs to make an emergency stop, I could call Halt or ExitProcess to terminate it immediately. This shouldn't happen quietly, though; the user needs to be shown a message. Therefore I looked to FatalAppExit but was surprised that it keeps everything (timers, threads) running until the user has closed the dialog.

I understand that showing a UI owned by the process requires the process to keep running. The UI does not need to be owned by my process, however. The dialog presented by FatalAppExit seems to be owned by Windows, even though it keeps the process running as well.

The main problem with FatalAppExit is that it's blocking—I want the dialog but not wait for confirmation—so I still can't terminate right after. To circumvent this, I'd have to start a thread that calls FatalAppExit, wait for a bit and then terminate the process. Not liking the race condition there.

I could also launch a process of my own to show the message, but I'd rather not if Windows can handle it.

Does Windows provide means to both terminate and show a friendly message at the same time? Any other suggestions to handle this as cleanly as possible?

Thijs van Dien
  • 6,516
  • 1
  • 29
  • 48
  • 2
    You seem to want your cake and to eat it.Showing a UI, of necessity, requires at least one thread to be running to pump messages. Depending on the framework showing the UI, additional threads might be necessary so you cant necessarily just pause/halt all other threads without causing deadlocks if the UI involves, say, a COM component in a different apartment. Also, for the duration your process is alive, other processes can create running threads for their own nefarious purposes that won't be halted. – Chris Becke Feb 18 '18 at 14:01
  • 5
    Why does your application need to make an emergency stop? It feels like you're trying to solve either the wrong problem, or trying to solve the problem with the wrong solution. – J... Feb 18 '18 at 14:06
  • @ChrisBecke The process does not need to keep running (in fact, it shouldn't) and the UI doesn't need to be mine. Unfortunately, `FatalAppExit` is blocking, so I'd need to work around that as described above. Then there's `CreateDialog`, but as far as I know it must be owned by my process so would die along with it. Not very familiar with WinAPI, so perhaps there's a better way to create a dialog that will stick around and not stop me from terminating. – Thijs van Dien Feb 18 '18 at 14:08
  • You're not listening. To show a UI the process must have running threads. If you don't want running threads, then the UI must be hosted in a different process. – Chris Becke Feb 18 '18 at 14:10
  • @ChrisBecke I'm fine with the UI being in a different process, but I'd like that process to be something Windows, rather than my own. Just like a dialog created by `FatalAppExit` does stick around even when the process that created it dies. I'm not sure if `FatalAppExit` is the best option, however, because calling it blocks, which is inconvenient if I want to terminate right after the call. – Thijs van Dien Feb 18 '18 at 14:15
  • @J... It's for a legacy application that throughout the code base assumes that the database is always available. When it loses the connection, it starts raining errors. In such case, the only thing a user can do is terminate it in the Task Manager. After closing a ton of dialogs, that is. They shouldn't need to, but handling this case gracefully is not a realistic option. Therefore the best option at this point seems to terminate it for them, but not silently. – Thijs van Dien Feb 18 '18 at 14:19
  • Lots of ways to display a dialog using the system's built-in facilities: [Show a popup/message box from a Windows batch file](https://stackoverflow.com/q/774175/1889329). – IInspectable Feb 18 '18 at 15:00

2 Answers2

1

As far as I know the only option here is to start an external process that displays the message and terminate immediately. You could write your own program for that purpose (which might be the easiest option) or you could start a batch file like this:

msg "%USERNAME%" %*

This sends a message to the given user (%USERNAME% is the currently logged on user) and uses all parameters passed to it as the actual message.

Personally I would write my own program, so I could write a log entry and do other stuff if it becomes necessary later.

dummzeuch
  • 10,975
  • 4
  • 51
  • 158
0

You can have a global variable, such as

var ShutdownMessage: string;

When you need to terminate with an error, do:

ShutdownMessage := 'Error occured';
Application.Terminate;

and in the dpr file after Application.Run:

if ShutdownMessage <> '' then
  MessageBox(0, PChar(ShutdownMessage), 'Error', MB_OK or MB_ICONERROR);

Then the message will be shown after all forms closed and main loop exited.

Or, if that fails, you can try to raise an exception after Application.Run - it should be propagated to OS

WhiteWind
  • 204
  • 1
  • 5
  • This won't terminate any threads of the application though. The only way to do that would be to start an external program to show the message and exit immediately afterwards. – dummzeuch Feb 19 '18 at 13:44
  • You're right. If threads are not hang, they may be terminated with TThread.Terminate, if some thread hang, then it will be terminated after user closes the MessageBox. If that's not acceptable, then external program is the only option – WhiteWind Feb 19 '18 at 14:09