I have a Python program which uses
os.system to execute various commands. (It can’t use
subprocess because it has to be backward compatible all the way to Python 2.0.)
On Windows, sometimes the command references DLLs in an unusual directory, and so I get the infamous “The program can’t start because X.dll is missing” error popup.
My question is not about how to make the command find all its DLLs. I already know how to do that. What I want to know is, how do I tell Windows not to show this dialog box when a DLL is missing? Instead, the child process should print the error message to stderr (which has been redirected to a file within the
os.system invocation) and exit unsuccessfully (causing
os.system to return an error code). That way my program could capture the error and report it in its own way, rather than hanging until someone comes along to click OK.
MSDN is normally my friend, but this time I get nothing but advice on how to cope with specific missing DLLs, which is nice and all but not what I need this time.
To reiterate, this is an extreme-backward-compatibility situation: I need a solution that works with Python 2.7 or any older version all the way back to 2.0. It also needs to work on all still-popular versions of Windows (XP, Vista, 7, 8). Working with even older Windows is highly desirable but not 100% required. Further, third-party modules and helper programs written in any other language are not an option. (I suppose a
.BAT file would be okay, if that’s the only way to do it.)
The dialog box can be disabled for the calling process with
SetErrorMode. However, you have to read the
LoadLibrary documentation to discover that “missing DLL at load time” qualifies as one of the “critical errors” covered by
The error mode inherits to child processes, as long as they are not created with
CREATE_DEFAULT_ERROR_MODE, and it appears that CMD.EXE does not set that flag when it creates subprocesses. So setting the error mode on startup in my Python script does in fact suppress the dialog box in the situation I care about…
if sys.platform == 'win32': try: import ctypes # SEM_FAILCRITICALERRORS|SEM_NOGPFAULTERRORBOX|SEM_NOOPENFILEERRORBOX ctypes.windll.kernel32.SetErrorMode(0x0001|0x0002|0x8000) except: pass
This is not an optimal solution: the subprocess terminates with a particular error code (0xC0000135 — not actually documented as “missing DLL”, but evidently so from what comes up when you search on that number) but the details — like which DLL is missing — are dropped on the floor. I still hope to find a setting somewhere that makes the loader report the details to stderr.