Sys.exit() shows popup window instead of just exiting

We are successfully launching Rhino 7 with command line parameters to run a script. For testing, the script just waits a few seconds and then exits with the sys.exit() command. Except that it always displays a popup window so that a user has to press a button. Our goal is to run the system unattended. Also, we are hoping to capture the “exit number” such as sys.exit(33) but have not been able to get that far yet.

Here is the simple script that Rhino is running:

import rhinoscriptsyntax as rs
import Rhino.Geometry as rg
import os
import sys
import time

time.sleep(3)
rs.DocumentModified(False)
sys.exit(3)

Both the script above and the Python script that runs Rhino are attached below. The output from the Python script running Rhino looks like this…

C:\Users\henry\Documents>python RunRhinoFromPython.py
The executable path exists
The script path exists
“C:\Program Files\Rhino 7\System\Rhino.exe” /nosplash /runscript=“-RunPythonScript ““C:\Users\henry\Documents\rhino_sysexit.py””" /runscript="-Exit”
Starting the application…
Process has a PID = 8528
b’’
b’’

which (I think) is good except that it requires a user to dismiss this popup window.
2023-08-08 22 10 48

RunRhinoFromPython.py (1.5 KB)
rhino_sysexit.py (157 Bytes)

Thanks for your help.

Use https://developer.rhino3d.com/api/rhinocommon/rhino.rhinoapp/exit that takes a boolean instead.

Thank you for the information, Nathan. That removed the dialog when exiting the application. That part is a success. Unlike the sys.exit() function, Rhino.RhinoApp.Exit(True) does not accept any exit code.

I tried to write the stderr and stdout directly using:

sys.stderr.write(‘Using the write command’)
sys.stdout.write(‘Something from stdout’)

in the script but they appear to be eaten by Rhino and do not show up to the calling program. I tried a different type of method to open Rhino and still did not get anything back from stderr or stdout.

Here is the program that opens Rhino using (what I think are) standard Python procedures:
RunRhinoFromPython.py (2.5 KB)

Here is the test program in Rhino:
rhino_sysexit.py (422 Bytes)

What is the proper method to exit Rhino with an exit code or similar method to pass success or failure back to the calling program?

You could try os._exit(errcode), but have no idea if that will work. I don’t know of any way to exit Rhino with an error code other than sys.exit().

@dale is that something that could be added as an overload to Exit(), one that takes an exit code?

Hi @Henry_Wede,

Does this work?

import ctypes
import Rhino
import scriptcontext

def test_exit_without_saving():
    scriptcontext.doc.Modified = False
    hWnd = Rhino.RhinoApp.MainWindowHandle()
    ctypes.windll.user32.PostMessageW(hWnd, 0x0010, 0, 0)
    
test_exit_without_saving()

– Dale

There still does not appear to be an exit code when Rhino closes. Well, technically there is an exit code of zero that I cannot change.

This is the script that Rhino runs

import ctypes
import time
import sys
import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino


# Pause for dramatic effect
time.sleep(3)

# We don't want to save the document
#rs.DocumentModified(False)
sc.doc.Modified = False

# Write to stderr and stdout
sys.stderr.write('Using the write command')
sys.stdout.write('Something from stdout')

hWnd = Rhino.RhinoApp.MainWindowHandle()
ctypes.windll.user32.PostMessageW(hWnd, 0x0010, 0, 0)

# Exit the application without and popup dialogs
Rhino.RhinoApp.Exit(True)

# This will not work
#sys.exit(3)

I couldn’t find understandable documentation on the PostMessageW parameters so I tried
(hWnd, 0x0010, 0, 1) and
(hWnd, 0x0010, 1, 0) but still the exit code was zero.

It looks like we will have to just write exit/error messages to a text file instead of using exit codes.

Thanks for looking into it @dale

RunRhinoFromPython.py (2.5 KB)
rhino_sysexit.py (592 Bytes)

Hi @Henry_Wede,

Rather than launch Rhino from Python, why not run Rhino in Python?

– Dale

That is an interesting idea.

The current system is in production so that kind of a change is out of the question. It is too much change.

Hi @Henry_Wede,

I’m not on a system with Python installed at the moment. But this seems to work:

RunPythonScript.zip (917 Bytes)

– Dale

Not on a system with Python installed? What kind of barbarians do you work for? Even my abacus came with Python installed… sure, it is v2.7 but still not too bad.

Yes, the methods above will all start Python remotely but the original problem was to return an error code the way most(?) applications do. Since Python is running inside Rhino there doesn’t seem to be a way to exit from Python with an error code. It isn’t the end of the world.

The error code is the missing piece.

Sorry I’m late to the thread, but I’ve stumbled on a simple method to do exactly this.

I wouldn’t have figured this out without your example @dale - cheers!

This (ctypes.windll.user32.PostQuitMessage) works from within a Grasshopper Iron Python 2 component too :slight_smile: .

set THIS_BAT_FILES_DIR=%~dp0
call "C:\Program Files\Rhino 8\System\Rhino.exe" /nosplash /runscript="_-RunPythonScript %THIS_BAT_FILES_DIR%\exit_with_ret_code_19.py"
echo %ERRORLEVEL%

exit_with_ret_code_19.py

import ctypes

    
def close_rhino(code=0):    
    ctypes.windll.user32.PostQuitMessage(code)
    
if __name__ == "__main__":
    close_rhino(19)

run_exit_with_ret_code_19_in_Rhino.zip (746 Bytes)