I just spent a couple hours trying to figure out why a Windows program would run from Command Prompt but not when double clicked from Explorer. Evidently, trying to write to stdout results in Tango throwing an exception if the program is started by double clicking, but not when run from the console.
It took me a while to figure out because by default a non-console program silently swallows an unhandled exception, and the process just disappears. Programs on Windows normally show a "ProgramName has stopped working" dialog when they crash. This happens by default for any program (even console programs) written in C, C++, or .NET without the programmer doing anything. I believe Windows Error Reporting shows the dialog:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb513641%28v=vs.85%29.aspx
The crash dialog usually supports uploading stack traces to MS servers, but at a minimum, the native crash dialog should show. (I would want to upload stack traces to my own server instead of Microsoft's because you have to buy a VeriSign certificate to access the traces on Microsoft's site. That would probably take a separate project, like Google Breakpad.)
To reproduce, compile this program:
extern(Windows)
int MessageBoxW(void* hWnd, const(wchar)* lpText, const(wchar)* lpCaption, uint uType);
void main() {
throw new Exception("You can't see this.");
MessageBoxW(null, "The program opened.", "Opened", 0);
}
using this command:
rdmd -ofmain.exe -L/EXETYPE:NT -L/SUBSYSTEM:WINDOWS:4.0 main.d
Try double clicking it in Explorer, and you don't see the message box or a crash dialog.
Comment #1 by dlang-bugzilla — 2014-01-04T22:51:42Z
https://github.com/D-Programming-Language/druntime/pull/703
With this patch, we'll show the uncaught exception details in a standard Windows message box. These are usually more useful than the standard Windows crash dialog, since they contain the exception type, the exception message, and (if the program was compiled with debug info), a stack trace.
Currently it is not possible to disable the D standard top-level exception handler from within the program or via a compiler/linker switch. It is disabled automatically if the program was started under a debugger, though.
Comment #2 by dlang-bugzilla — 2014-01-04T23:02:36Z
> I would want to upload stack traces to my own server instead of Microsoft's
So, do I understand correctly that D's standard uncaught exception handler does not apply to your problem, and you need uncaught exceptions to go to WER?
If so, would the standard uncaught exception handler being disabled when a variable is present in the environment be an acceptable solution for you? Since you mentioned a custom WER server, you're already using a custom configuration on the users' PCs, so adding an environment variable shouldn't be very different, right?
Comment #3 by jminer7 — 2014-01-05T18:31:08Z
Thanks for writing the patch. Sounds like a good improvement that I'll use during development.
Reading about WER more, I think I'd rather bypass it and handle everything myself. Could there be a way to set a delegate that is called when there is an uncaught exception and have an easy way to get the exception type, name, and stack trace?
In the delegate, I could start a helper process that reads the information from the crashed process and uploads it (to avoid doing too much in a crashed process). For others who want to use WER, it looks like they could call WerReportCreate() and WerReportSubmit() from the delegate to trigger WER. The default delegate could write the info to the console or show a dialog, depending on whether there is a console. What do you think?
Comment #4 by github-bugzilla — 2014-01-06T00:03:17Z
Comment #5 by dlang-bugzilla — 2014-01-06T00:18:46Z
(In reply to comment #3)
> Could there be a way to set a delegate that is called when there is an
> uncaught exception and have an easy way to get the exception type, name, and
> stack trace?
Yes. In fact, something like that existed in the runtime a while ago. However, you can achieve mostly the same by writing your own WinMain as shown here:
http://dlang.org/windows.html
This page is a bit outdated. Note the exceptionHandler parameter: this is the mechanism mentioned above that no longer works, and those overloads of Runtime.initialize/terminate are now deprecated. (Martin Nowak removed them in b95be7e55e57a4ff065f1dc5f3362fc476d85f4d. Before that, Walter Bright wrote in a comment: "Note that if we get here, the runtime is in an unknown state. I'm not sure what the point of calling dg is."). However, the general idea still works, if you don't care about exceptions thrown during runtime initialization / deinitialization (this includes static constructors/destructors). Just replace the MessageBoxA call with your custom error-handling code.
Comment #6 by github-bugzilla — 2014-04-23T00:17:48Z