[Solved] Auto-update running app?

Just starting out? Need help? Post your questions and find answers here.
BarryG
Addict
Addict
Posts: 4219
Joined: Thu Apr 18, 2019 8:17 am

[Solved] Auto-update running app?

Post by BarryG »

SOLVED! The "ren" command in the batch file isn't meant to have the file path included for the new name, which was causing the "ren" command to fail. I didn't show the full path in my hasty example below (sorry). Also, you need to wrap the batch file paths in quotes too, which I didn't show below.

I'm pulling my hair out trying to get my app to auto-update itself while it's running. Downloading the new exe version is easy, but then I can't find a way to quit the app and run the new version with the same exe name. Here's the batch file that my app creates to do it, but it doesn't work all the time and also leaves "Update.bat" alive until the newly-launched exe quits, which is not good. How would you do it?

Code: Select all

; MyApp.new is the new downloaded version.
f=CreateFile(#PB_Any,"Update.bat")
If f
  WriteStringN(f,"ping -n 2 127.0.0.1 >NUL")
  WriteStringN(f,"del MyApp.exe")
  ;WriteStringN(f,"ren MyApp.new MyApp.exe") ; Original snippet with the path missing.
  WriteStringN(f,"ren C:\Path\MyApp.new MyApp.exe") ; How it's supposed to be. Sorry!
  WriteStringN(f,"MyApp.exe")
  WriteStringN(f,"del Update.bat")
  CloseFile(f)
  RunProgram("Update.bat","","",#PB_Program_Hide)
  End
EndIf
Last edited by BarryG on Sat Dec 21, 2024 1:24 pm, edited 4 times in total.
Quin
Addict
Addict
Posts: 1135
Joined: Thu Mar 31, 2022 7:03 pm
Location: Colorado, United States
Contact:

Re: Auto-update running app?

Post by Quin »

To do this for my application, I wrote a tiny Updater application and include it in the executable with a DataSection and IncludeBinary. Then, when I'm updating, I go:

Code: Select all

Protected Temp$ = GetEnvironmentVariable("TEMP")
Protected FileID = CreateFile(#PB_Any, Temp$ + #PS$ + "Updater.exe")
If Not FileID
Debug "There was a problem downloading the update."
ProcedureReturn
EndIf
WriteData(FileID, ?Updater, ?EndUpdater - ?Updater)
CloseFile(FileID)
RunProgram(Temp$ + #PS$ + "Updater.exe", "", GetCurrentDirectory())
Shutdown()
The actual implementation of the updater is up to you, I just made a little window that opens showing a progress bar.
HTH!
AZJIO
Addict
Addict
Posts: 2224
Joined: Sun May 14, 2017 1:48 am

Re: Auto-update running app?

Post by AZJIO »

1. When you click the "update" button, a new file is downloaded.
2. Run the file and pass it the parameters “name of the process” that needs to be killed and “path to the executable file” that needs to be deleted.
3. You can make a window that will offer to close the program in the normal way. After closing the program and confirming by clicking the "OK" button, you check that the process does not exist and delete the executable file and copy the new file instead.
Axolotl
Addict
Addict
Posts: 872
Joined: Wed Dec 31, 2008 3:36 pm

Re: Auto-update running app?

Post by Axolotl »

The deletion will only work when the exe is finished.

Maybe this change helps?

Code: Select all

; MyApp.new is the new downloaded version.
f = CreateFile(#PB_Any, "Update.bat") 
If f 
; WriteStringN(f,"ping -n 2 127.0.0.1 >NUL")
  WriteStringN(f,":Label")
  WriteStringN(f,"del MyApp.exe")
  WriteStringN(f,"if exist MyApp.exe goto :Label") 
  WriteStringN(f,"ren MyApp.new MyApp.exe") 
  WriteStringN(f,"MyApp.exe") 
  WriteStringN(f,"del Update.bat") 
  CloseFile(f) 

  RunProgram("Update.bat","","",#PB_Program_Hide) 
  End
EndIf
Just because it worked doesn't mean it works.
PureBasic 6.04 (x86) and <latest stable version and current alpha/beta> (x64) on Windows 11 Home. Now started with Linux (VM: Ubuntu 22.04).
Axolotl
Addict
Addict
Posts: 872
Joined: Wed Dec 31, 2008 3:36 pm

Re: Auto-update running app?

Post by Axolotl »

Second Idea: (just coded, not tested)
Maybe this is of any help
Thank you in advance for your feedback!

Code: Select all

; ---------------------------------------------------------------------------------------------------------------------
;
;   Updater.exe 0.00 
;
;   call the update with 
;     RunProgram("Updater.exe", "<ExeFile> <ServerFile> [/silent]", "") 
;
;   Parameter: 
;
;     ExeFile     .. executable file to be updated (with path or should be in the same directory as the updater) 
;
;     ServerFile  .. Location of the new file (https://....) 
;
;     bSilent     .. /silent otherwise MessageRequester shows errors 
;
; ---------------------------------------------------------------------------------------------------------------------

EnableExplicit

#ProgramName$   = "Updater"
#ErrorCaption$  = #ProgramName$ + " Error" 
#InfoCaption$   = #ProgramName$ + " " 

; ---------------------------------------------------------------------------------------------------------------------

Procedure GetParentPID()
  Protected hSnapshot
  Protected PROCESSENTRY32.PROCESSENTRY32
  Protected bProcess
  
  hSnapshot = CreateToolhelp32Snapshot_(#TH32CS_SNAPPROCESS, #Null)
  If hSnapshot
    PROCESSENTRY32\dwsize = SizeOf(PROCESSENTRY32)
    bProcess = Process32First_(hSnapshot, @PROCESSENTRY32)
    While bProcess 
      If PeekS(@PROCESSENTRY32\szExeFile, #MAX_PATH) = GetFilePart(ProgramFilename()) 
        CloseHandle_(hSnapshot) 
; Debug "ProcessID = " + PROCESSENTRY32\th32ProcessID 
; Debug "Parent ProcessID = " + PROCESSENTRY32\th32ParentProcessID 
        ProcedureReturn PROCESSENTRY32\th32ParentProcessID    ; return the found parent process id 
      EndIf
      bProcess = Process32Next_(hSnapshot, @PROCESSENTRY32)
    Wend 
    CloseHandle_(hSnapshot)
  EndIf 
  ProcedureReturn 0 ; no parent process id found 
EndProcedure

; ---------------------------------------------------------------------------------------------------------------------

Procedure.s GetProcessPath(PID)
  Protected hSnapshot
  Protected PROCESSENTRY32.PROCESSENTRY32
  Protected bProcess
  
  hSnapshot = CreateToolhelp32Snapshot_(#TH32CS_SNAPPROCESS, #Null)
  If hSnapshot
    PROCESSENTRY32\dwsize = SizeOf(PROCESSENTRY32)
    bProcess = Process32First_(hSnapshot, @PROCESSENTRY32)
    While bProcess 
      If PROCESSENTRY32\th32ProcessID = PID
        CloseHandle_(hSnapshot)
        ProcedureReturn PeekS(@PROCESSENTRY32\szExeFile)    ; return the parent executable file name 
      EndIf
      bProcess = Process32Next_(hSnapshot, @PROCESSENTRY32)
    Wend 
    CloseHandle_(hSnapshot)
  EndIf
  ProcedureReturn "" ; no parent process found 
EndProcedure

; ---------------------------------------------------------------------------------------------------------------------

Procedure Main()
  Protected ExeFile$, DownloadFile$, BakFile$  
  Protected ExeName$, ServerFile$, path$ 
  Protected bSilent 

  ; read the agruments (quick and dirty) 
  ;
  ExeFile$    = ProgramParameter()    ; executable file to be updated 
  ServerFile$ = ProgramParameter()    ; i.e. "https://,,,,"
  bSilent     = Bool(ProgramParameter() = "/silent") 

  ; if ExeFile$ is empty, updater.exe probably called by double click directly 
  ;
  If ExeFile$ = "" 
    ; Not bSilent 
    MessageRequester(#ErrorCaption$, #ProgramName$ + " is not a stand-alone program!") 
    ProcedureReturn 1   ; some error 
  EndIf

  path$ = GetPathPart(ExeFile$) 
  If path$ = "" 
    path$ = GetPathPart(ProgramFilename())  ; Updater and Executable are in the same directory !!! 
  EndIf 

  ExeName$ = GetFilePart(ExeFile$, #PB_FileSystem_NoExtension) 
  BakFile$ = path$ + ExeName$ + ".bak" 

  DownloadFile$ = path$ + ExeName$ + "_New.exe"  ; temporary name for downloaded file 

  ; do the download in some way 
  ; 
  If Not ReceiveHTTPFile(ServerFile$, DownloadFile$) ; 
    If Not bSilent
      MessageRequester(#ErrorCaption$, "Update failed!") 
    EndIf 
    ProcedureReturn 1   ; some error 
  EndIf 

  ; Check if current executable is terminated already 
  ;
  While GetParentPID() 
    Debug "Wait until the exe is finished"  ; show debug message while waiting 
    Delay(2000) 
  Wend 

  ; make a backup of current executable (remove the last one) 
  ;
  DeleteFile(BakFile$) ; maybe no backup file (first update) 
  If RenameFile(ExeFile$, BakFile$) 
    If RenameFile(DownloadFile$, ExeFile$) 
      If Not bSilent 
        MessageRequester(#InfoCaption$, "Update successful", 0)
      EndIf 
      RunProgram(ExeFile$, "", "") 
    EndIf 
  EndIf 

  ProcedureReturn 0 
EndProcedure 

End Main() 
Just because it worked doesn't mean it works.
PureBasic 6.04 (x86) and <latest stable version and current alpha/beta> (x64) on Windows 11 Home. Now started with Linux (VM: Ubuntu 22.04).
PBJim
Enthusiast
Enthusiast
Posts: 296
Joined: Fri Jan 19, 2024 11:56 pm

Re: Auto-update running app?

Post by PBJim »

The way that I would approach this, is with two very simple provisos :

1. Downloaded updates are written to a separate file name called update.exe

2. Always run your application using a calling routine, let's call it caller.exe, which first looks for the directory presence of update.exe before executing RunProgram("application.exe"), and if it first finds update.exe, then it copies it over application.exe before running it.

If you want the automatic update to take effect while the application is running, rather than next time you run it, then you just close it and re-run caller.exe.
User avatar
skywalk
Addict
Addict
Posts: 4242
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: Auto-update running app?

Post by skywalk »

I also use the batch file approach.
It gets created on the fly when the user clicks "upgrade", "check for updates", etc.
Then the app saves and runs the batch file and quits.
I use a simple delay in the batch file to guarantee the app is really exited.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
BarryG
Addict
Addict
Posts: 4219
Joined: Thu Apr 18, 2019 8:17 am

Re: [Solved] Auto-update running app?

Post by BarryG »

Solved. PEBKAC error. See edited first post. :oops:
User avatar
HeX0R
Addict
Addict
Posts: 1218
Joined: Mon Sep 20, 2004 7:12 am
Location: Hell

Re: [Solved] Auto-update running app?

Post by HeX0R »

If you need no instant use of the new version, you could also RENAME your own running application, then download the new one with the old filename.
Next start you'll have the new version (and a corpse, which could be deleted when starting).
But all that would not work, if your app sits in Program Files Dir of course.
Little John
Addict
Addict
Posts: 4803
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: [Solved] Auto-update running app?

Post by Little John »

Why not download the original setup program for the new version?
Then in your program which is to be updated, just run

Code: Select all

RunProgram("<Path>/mysetup.exe")
End
Post Reply