2

For the sake of testing and personal proof of concept, I have a .exe file that only outputs a simple string and then calls a system pause (literally system("pause") in C++).

I have a simple Python script I'm testing on a Windows XP VM that does these operations when messing up:

subprocess.call(r'echo Nothing special. > c:\blank.txt', shell=True)
subprocess.call(r'type pause.exe > c:\blank.txt:ads.exe', shell=True)
subprocess.call(r'start c:\blank.txt:ads.exe', shell=True)
subprocess.call(r'del c:\blank.txt', shell=True)

Obviously, those commands all work fine alone on the command line, why don't they work fine when called through Python?

I receive this pop-up error message:

blank.txt:ads.exe has encountered a problem and needs to close. We are sorry for the inconvenience.

If you were in the middle of something, the information you were working on might be lost.

The file is indeed deleted, also. It seems that the system pause is just crushed by the delete command, when I expect the .exe to pop up, wait for me to push enter, and then the script will continue and delete the file.

Joseph Hansen
  • 12,665
  • 8
  • 50
  • 68

3 Answers3

1

What happens is that each subprocess.call(..., shell=True) is immediately returning because they're just telling the shell to execute a command. On the commandline, calling an exe to run using the start command will still immediately return even though the exe has not terminated. The start immediately returned and it needs to be told to wait:

subprocess.call(r'echo Nothing special. > c:\blank.txt', shell=True)
subprocess.call(r'type pause.exe > c:\blank.txt:ads.exe', shell=True)
subprocess.call(r'start /wait c:\blank.txt:ads.exe', shell=True)
subprocess.call(r'del c:\blank.txt', shell=True)
Joel B Fant
  • 24,406
  • 4
  • 66
  • 67
  • 1
    The documentation for subprocess.call: "Run command with arguments. Wait for command to complete, then return the returncode attribute." So I don't think that's it. – Mu Mind May 20 '11 at 20:13
  • @Mu: Right. I found a question elsewhere on SO that suggested using `call()` in order to have it wait. – Joel B Fant May 20 '11 at 20:14
  • 1
    @Xeo The problem with agreeing with Joel at the present is that he is saying his "idea of what's going on is [getting] foggier". LOL ;) – Joseph Hansen May 20 '11 at 20:15
  • @josmh: The edit wasn't there at the moment I made the comment. :) – Xeo May 20 '11 at 20:17
  • I'm going to try and recreate this situation. – Joel B Fant May 20 '11 at 20:23
  • Your current edit is why I'm using a Windows XP VM. And as stated at the top.. this is for legitimate testing purposes. You gotta be able to make security concerns if you're going to stop them. – Joseph Hansen May 20 '11 at 20:37
  • @Joel `subprocess.call(r'start c:\blank.txt:ads.exe', shell=False)` will newer work, should be at least `subprocess.call(['start', r'c:\blank.txt:ads.exe'], shell=False)`. ` – Roman Bodnarchuk May 20 '11 at 21:26
1

Given the symptoms, my understanding is that you can only safely delete an executable in this particular setting (Windows XP, perhaps at a particular patch level, when the executable is from an alternate stream) once this executable has finished initializing. If you delete an executable while it's loading, the program crashes.

When you type these commands at a prompt, some time elapses between running start c:\blank.txt:ads.exe and del c:\blank.txt, giving the program enough time to finish loading. When you're running them from a script, the interval between the two is a lot shorter (start branches off a new process, and the new program's initialization happens asynchronously). There's race condition between the initialization and the deletion; which one wins depends on how soon the deletion is performed.

Try experimenting with a delay before deleting the file:

import subprocess, time
subprocess.call(r'echo Nothing special. > c:\blank.txt', shell=True)
subprocess.call(r'type pause.exe > c:\blank.txt:ads.exe', shell=True)
subprocess.call(r'start c:\blank.txt:ads.exe', shell=True)
time.sleep(42)  # 42 seconds is overkill, but the delay isn't predictable
subprocess.call(r'del c:\blank.txt', shell=True)
Gilles 'SO- stop being evil'
  • 104,111
  • 38
  • 209
  • 254
0

The windows shell start command will launch the program in a new shell and then just continue. To wait for it to complete use call:

subprocess.call(r'call c:\blank.txt:ads.exe', shell=True)
zdan
  • 28,667
  • 7
  • 60
  • 71
  • `call` works to execute the program however when I just edited in that code and ran it, the pause still seemed to be "pushed" out of the way and the file was deleted. I don't get it. – Joseph Hansen May 20 '11 at 20:26
  • Also, it appears "call" has problems with the extra colon in some set-ups. – Joseph Hansen May 22 '11 at 04:04