We have a legacy build infrastructure for nightly builds (implemented in Perl) to compile, link and unit tests our applications/plugins. On Windows, if the unit testing process crashes, this pops up a Modal Dialog which "locks" our build farm.
Is there a way (win32 API call, system config, env var, something...) to disable this behavior to have the child process terminate immediately on crashes, with no Modal Dialog and a non-zero exit status instead?
Thanks, --DD
PS: We compile with SEC (Structured Exception Handling) on Windows, to be able to "catch" crashes using catch (...), therefore avoiding this issue most of the time, but sometime that's not enough, since of course some crashes are not recoverable (if they corrupted the stack for example).
Depending on who's throwing the dialog, you may have to combine multiple approaches.
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
...will shut up one set of dialogs.
You need to add an 'unhandled exception handler' that catches all exceptions: put a call to SetUnhandledExceptionFilter(handler) in your initialisation code and it'll call the handler routine. Really simple.
I use sample code from an old article, include a file called minidumper, call the exposed function, and you're done.
Here's some more example code, this pops a different dialog, but you can change that to simply write a message to a log file or similar.
If you're writing a pure .NET app, then you'll be more interested in this article.
Do not use the "catch(...)" statement because then you can miss the point of having unit tests.
What you need is a non-modal dialog, since the modal dialogs are for blocking the user from any further actions and the program execution (in your case the unit test runs) hangs up until the user makes his/her choice. Now the crash dialogs can't be avoided, but you need to see how your unit test framework handles these situations. I would say you missed something around the unit testing framework because if I have a crash in my applications I got just a log message about that from the Boost.Test stubs.
If you run your unit tests as a child process it shouldn't block your build bot, BUT: if a unit test case fails, you shouldn't continue the building process in my opinion.
You can use WSH to "script" your windows.
With it you can "simulate" that somebody clicked on the "Accept" button of the modal window, or send the ESC key to close that.
Regards.
Related
Qt 4.7.1
I have a qttest setup which has until recently been performing well. I have encountered, and dealt with, the need to interact with modal dialogs by using singleshot timers.
However, I am now seeing the opposite behaviour; calls such as QFileDialog::getSaveFileName are returning straight away with no display of the dialog. This is since I performed a merge so I assume there is some code or build change behind it, but it isn't the function call itself.
As far as example code goes, I can't post my whole framework or AUT but the consider the following inside a test function:
QMessageBox::StandardButton button = QMessageBox::question(NULL,"Thing",
"Do you want to do a thing?",
QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No);
The call returns straight away and button is set to NoButton. I should add that there is a bit of a framework around my tests and I manually start each test with QTest::qExec. (The framework has not changed, of that I'm sure)
Any ideas on what might be causing this?
Edit:
The eventloop started by the messagebox in the above example has quitNow set to true, which is causing exec to return straight away. I'm now looking for why this is set, in the meantime feel free to enlighten me!
This was due to calling qApp->exit() in my cleanup() function. There is no need to do this!
Let me explain my question with an example. In my app, I need to provide a way to automatically close it from within "itself." (An example of such function is when an installer/updater of my app needs it to close before installing an update. Another example is when my app performs actions on schedule and needs to automatically close once it's done.)
I picture that in the simplest situation posting the WM_CLOSE message to the own window will accomplish this task, but there're the following cases that will not work with just that:
My app may be displaying an arbitrary number of child dialog windows.
My app may be displaying a common control window, such as Open File dialog:
or this one, but there could be others:
And lastly what could one do if the close button is not even available:
At the current point, I simply resort to terminating my process (either with the exit() method from within, or with TerminateProcess from outside.)
But I'm curious, if there's a more graceful way of closing my GUI app (from within)?
There is no single answer, it depends on your app's architecture and what it's doing. I don't quite understand why you would want to force close your application while it is in a common dialog, but if you do, then exit() is safe. In that case the process is actually shutdown from the operating system's perspective as opposed to a forced termination (TerminateProcess). In theory TerminateProcess might leave objects in the OS (DLL global data and such) in an inconsistent state, and exit() will be cleaner in that regard.
Generally though I'd avoid having visible UI that is up for the user just disappear and instead close the windows in reaction to some user choice.
But, exit() will work.
You can use exit() but a safer way to close the window would be:
SomewWindow->ShowWindow(SW_HIDE);
You could then destroy the window object or show the window later.
I have a simple assertion macro that prints out a message. This usually works when the application is not a console application (i.e. I get a nice dialog that pops up, and has the expression including the message at which point I can hit retry to debug) but when it is, the console intercepts all the messages. This becomes annoying when the console hides behind the IDE and I have to fish it out, then go back to the assertion dialog, and hit retry to debug.
Is there any way to stop it from intercepting the messages so that the dialog that pops up has all the info.
The macro is this:
#define MyAssert(_Exp, _Msg) assert(_Exp && _Msg)
EDIT: Screenshot
The CRT attempts to work out where you want assert output to go to based on the type of application. It detects this from the type of the executable (/SUBSYSTEM). However, you can override with _set_app_type so that the CRT acts as if your console app is a Windows app. More likely, you just want to impact assertions and so should call _CrtSetReportMode to change to _CRTDBG_MODE_WNDW
You didn't specify your VS version, but these are availble (with subtle naming differences in VS2003) for all recent versions.
Martyn
I have a third party encryption library, which may create a MessageBox if key creation fails. The failure can be caused by bad random number generation or other rarities, and in most cases, trying again will result in success. My code will attempt key creation up to three times before deciding it failed.
Now, the issue is that the program may be used with automation. If a MessageBox is created during automation, it will block the process forever, because there's nobody to click the 'OK' button.
Does anyone know of a way to catch when this message box is created and automatically close it?
Anything is fair game, as long as it's not something that will make security suites angry. This means no hooking or code tunneling.
In summary, I need to catch when a MessageBox is created and close it. The MessageBox's creation is outside of my control. Modifying the code at runtime is not acceptable.
Also, I've noticed there are some other similar questions, but they don't have the same requirements.
EDIT: Additional note, I can find the message box via searching through all windows until I find one with a matching title and then send it a WM_CLOSE message, but I don't think this is a great solution. I also have no guarantee that the message box has been/will be displayed, or how long after my call it will be displayed. It could display instantly, it could display 1200 ms later, or it could not display at all.
Just before you begin the encryption process, install a WH_CBT hook, and in its callback watch for an nCode of HCBT_CREATEWND. If you get a matching class name ('#32770 (Dialog)' ?) and a matching title either return a nonzero value from the callback, or if that doesn't work post a WM_CLOSE (or a BM_CLICK to a relevant button if selecting an option is necessary). Uninstall the hook after the process for not messing with every possible dialog your application pops up.
That sounds like bad design on the part of that library. Generally any sort of utility library (like encryption) has no business invoking any kind of GUI (unless you explicitly ask it to).
Is there possibly some configuration or setting in this library that could disable its use of message boxes?
If not, I'd suggest that you might want to investigate using a different library. After all, if the designers of this library have already made this kind of poor design decision once, then there may be other unfortunate surprises lurking in there.
You can hope that it will be found by GetForegroundWindow, but this may catch other applications. The more brute force way is to iterate over all windows with EnumWindows looking for something that has a caption or text equal to this shown by the library.
I have once "remote controlled" an application by sending mouse click events to some controls. I guess you would have to do this in a separate thread that is watching for Events if a window is opened. Pretty ugly but working...
Create a new thread. If your function fails and a Message Box is opened, obtain a handle to the message box by looping through the windows (GetTopWindow, GetNextWindow) and comparing the window's process id to the one returned from GetCurrentProcessId().
Or, you can avoid all the hard work and just hook the MessageBox API with detours. It's not very hard, and if you don't want to pay for detours, you can do it manually.
Call VirtualProtect and set the memory protection at MessageBox at PAGE_EXECUTE_READWRITE
Create a naked function, and use it as a trampoline.
Create a function identical in parameters to MessageBox (this will be your hook)
Create a jump from MessageBox to your hook function.
I have an MFC application that spawns a number of different worker threads and is compiled with VS2003.
When calling CTreeCtrl::GetItemState() I'm occasionally getting a debug assertion dialog popup. I'm assuming that this is because I've passed in a handle to an invalid item but this isn't my immediate concern.
My concern is: From my logs, it looks as though the MFC thread continues to service a number of windows messages whilst the assert dialog is being displayed. I thought the assert dialog was modal so I was wondering if this was even possible?
The message box that shows the assertion failure has a message pump for its own purposes. But it'll dispatch all messages that come in, not just those for the message box (otherwise things could get blocked).
With a normal modal dialog, this isn't a problem because the parent window is typically disabled for the duration of the dialog.
The code that launches the assertion dialog must've failed to figure out the parent window, and thus it wasn't disabled. This can happen if your main window isn't the active window at the time of the assertion. Other things can go wrong as well.
You can change how Visual Studio's C run-time library reports assertion failures with _CrtSetReportMode. You can make it stop in the debugger and/or log to the output window instead of trying to show the dialog.
Dialogs (even a messagebox) need to pump the message queue, even if they're modal. Otherwise how would they know you clicked on the "OK" button?
If you need to stop everything when an assert triggers it's usually not too difficult to write your own implementation of assert() (or ASSERT() or whatever) that will break into the debugger instead of displaying a messagebox that asks if you want to break into the debugger (maybe only if it determines that the debugger is attached).