Sublime Forum

ExecCommand not displaying win32 windows

#1

In the default package, exec.py file there is the next piece of code:

class AsyncProcess(object):

    def __init__(self, cmd, shell_cmd, env, listener, path="", shell=False):
        ...

        # Hide the console window on Windows
        startupinfo = None
        if os.name == "nt":
            startupinfo = subprocess.STARTUPINFO()
            startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW

Because the way startupinfo is being setup on window, when running win32 executables (not pure console ones) the windows won’t be shown.

I mean, I understand if you’re running a pure console executable this will prevent showing the flashy console… but… because of this a lot of executables won’t be shown at all, am I missing something here or maybe doing something wrong?

Thanks.

0 Likes

#2

just launch it using start or cmd

1 Like

#3

I’ve been playing around in this general area recently w/regards to adding the ability to run external GUI diff tools in OverrideAudit and investigated this particular phenomenon a bit.

More specifically I was curious what this was actually doing and looked at the source code in Python 3.3 itself to see what was happening. Note however that Sublime doesn’t necessarily use that version of the code as I believe the devs have their own version of it.

In any case, in Lib\subprocess.py the Popen.__init__() method invokes self._execute_child() in order to start the child process, and the windows version of that method contains this:

if shell:
    startupinfo.dwFlags |= _winapi.STARTF_USESHOWWINDOW
    startupinfo.wShowWindow = _winapi.SW_HIDE
    comspec = os.environ.get("COMSPEC", "cmd.exe")
    args = '{} /c "{}"'.format (comspec, args)

That is, regardless of what Sublime may or may not be doing with the startupinfo object itself, if you pass shell=true to the Popen contructor, it’s going to set that flag anyway and also specifically tell it to hide the window.

More importantly however, it starts your command by giving the command interpreter the /c argument, which tells it to run the following command and then exit. So in essence the flag is actually just stopping the console window from briefly being displayed while the actual process starts.

Presumably this is also why the code in kill() in the Sublime AsyncProcess command has to do something more complex to terminate the running application under Windows; it can’t just stop what it tried to start because that process automatically terminated as soon as it launched the subtask.

If you look at the code for exec.py, you’ll see that shell is always set to True when you use shell_cmd, so this just automatically works if you do that. If you want to use cmd instead, you need to specifically set shell to True in the command to ensure that the Python library does the right thing.

If I had to guess, I would say that Sublime is doing it this way on purpose for the same reason that the Python library seems to be doing it; so that it’s possible for you to launch an application hidden if you want it to be hidden, or not hidden if you don’t. On the other hand, possibly it’s just a happy accident that it works out that way. I would imagine that at least some subset of running a task in the background benefits from it not being visible, at any rate.

2 Likes

#4

@OdatNurd Thanks for the answer, I’ve always avoided using shell_cmd each time I’ve needed to run ExecCommand from my plugins but in this particular case it works well. Also, the fact I don’t need to have AsyncProcess tweaked (I really dislike patching sublime core code, not good when updating) is a win.

In any case, I find quite strange this decission of preventing visible windows when using cmd instead shell_cmd. For instance, using both cmd & shell_cmd should run properly 100% windows exes, no matter which type.

Anyway, I’ll use shell_cmd for this one, so… yeah, thanks once again :wink: !

0 Likes

#5

Note that as seen in my GIF above, if you use cmd, you can still get it to work if you explicitly set shell to True in the call, so that the Popen call will use the command processor to start the application for you.

0 Likes