0

I'm trying to implement an auto-update functionality, so I'm programmatically downloading the update_myprog.exe (created with Inno Setup), and then I want to close the program immediately and run update_myprog.exe. Currently I am using subprocess.Popen() to run it, but for some reason when the update_myprog.exe runs, I get an error: "Setup was unable to automatically close all applications. It is recommended that you close all applications using files that need to be updated by Setup before continuing.". When I run update_myprog.exe myself (not through the original program), it works just fine.

So, I'm wondering, is it a problem with my Python, with Inno Setup, or something else?

Below is a simplified version of my problem, extracting just the relevant code.

Here is my python code (autoupdate.py):

import wx
import subprocess
import win32process
import tempfile

class Main(wx.Frame):
    def __init__(self,*args,**kwargs):
        wx.Frame.__init__(self,*args,**kwargs)
        self.SetTitle('MyProg v1')
        self.updatebutton=wx.Button(self,label='Update')
        self.updatebutton.Bind(wx.EVT_BUTTON,self.update)
    def update(self,event):
        canupdate=True
        if(canupdate):
            tempdir=tempfile.mkdtemp()
            fname=os.path.join(tempdir,'update_myprog.exe')
            proc = subprocess.Popen('"update_myprog.exe" /SP- /silent /noicons /nocancel /password="pw"', creationflags=win32process.DETACHED_PROCESS,shell=True)
            self.Destroy()
            sys.exit()

app = wx.App(False)
Main(parent=None).Show(True)
app.MainLoop()

I then compiled it with:

pyinstaller "autoupdate.py" --distpath="make\dist" --workpath="make\build"

And then I made the installer (update_myprog.exe) with the following Inno Setup Script:

[Setup]
AppId={{7FBA93BE-7DC4-4114-91DF-DD524A078F63}
AppName=My Program
AppVersion=1
AppPublisher=My Company, Inc.
AppPublisherURL=http://www.example.com/
AppSupportURL=http://www.example.com/
AppUpdatesURL=http://www.example.com/
DefaultDirName={pf}\My Program
DefaultGroupName=My Program
AllowNoIcons=yes
OutputDir=make/Installer
OutputBaseFilename=update_myprog
Password=pw
Compression=lzma
SolidCompression=yes

[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"

[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked

[Files]
Source: "C:\Python27\My Projects\Test Update\make\dist\autoupdate\autoupdate2.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Python27\My Projects\Test Update\make\dist\autoupdate\*"; DestDir: "{app}";

[Icons]
Name: "{group}\My Program"; Filename: "{app}\autoupdate.exe"
Name: "{commondesktop}\My Program"; Filename: "{app}\autoupdate.exe"; Tasks: desktopicon

[Run]
Filename: "{app}\autoupdate.exe"; Description: "{cm:LaunchProgram,My Program}"; Flags: nowait postinstall

Then I run the installer (works fine), and copy the installer into the directory it installed to. Then I run my program, and click the button, and it gives me an error. Why?

It might help me if somebody else could run do the above steps on their computer, and let me know if they have the same problems. All help is appreciated.

Old Question:

So, I basically have the same question as Spawning a non-child process in python but for Windows.

I'm trying to implement an auto-update functionality, so I'm programmatically downloading the update_myprog.exe (created with Inno Setup), and then I want to close the program immediately and run update_myprog.exe. Currently I am using subprocess.Popen() to run it, but it seems like it is still a child of the original program, and thus cannot overwrite the exe file of the original to update it.

Would os.system be what I'm looking for, or is there some other solution?

Community
  • 1
  • 1
Lambda
  • 270
  • 2
  • 12

2 Answers2

0

If you want to completely detach the process you can use:

from win32process import DETACHED_PROCESS
from subprocess import Popen
Popen(["python","xyz.py"],creationflags=DETACHED_PROCESS,shell=True).pid

Update

Compiling it could lead to it's own little nightmare with the use of temporary directories, but that's another question, and god knows how wx is behaving here. Be sure that download is actually finishing and try execfile(filename) instead of Popen. If no luck there, try the following:

from subprocess import Popen, CREATE_NEW_CONSOLE,CREATE_NEW_PROCESS_GROUP
Popen(["python", 'xyz.py'],shell = True | CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE)

Failing that, repost the question and let someone else have a look. Sorry I couldn't be of more help. Let me know how you sussed it in the end.

ajsp
  • 2,512
  • 22
  • 34
  • I tried it, and unfortunately it didn't work. Perhaps I misunderstood my problem...editing question now. – Lambda Jul 24 '15 at 11:47
  • I do know the download is finishing, because running the "update_myprog.exe" which was downloaded works successfully. From my understanding (from documentation), `execfile` is only for running python code, and I want to run an executable. I will your other option, although, in the documentation, it says that CREATE_NEW_PROCESS_GROUP is ignored if CREATE_NEW_CONSOLE is set, and that CREATE_NEW_CONSOLE is set by default if shell=True. Thanks so much for the suggestions. – Lambda Jul 24 '15 at 18:41
0

I implemented auto-update using Inno Setup and PyInstaller over a year ago. You need to call self.destroy() before the subprocess. This is so that after you call Inno, you can exit immediately. You can also use the /FORCECLOSEAPPLICATIONS flag so that Inno-Setup can close your program in case the sys.exit() was not fast enough.

Elijah
  • 1,814
  • 21
  • 27