Jump to content

EXE updates itself


PAJ
 Share

Recommended Posts

I need my compiled script.exe to check for newer versions of itself. I can do the file check version code to determine that a new version is available on a network share, and copy the new version to the clients HDD as script.new. How can I get the running script to exit, delete script.exe, rename script.new to script.exe and start. Bearing in mind that users running this script only have normal user access rights.

I've seen this done by other applications.

thanks for any help in advance.

:P

Peter.

Link to comment
Share on other sites

should work (in theory)

rename yourself.

download the new one.

run the new one.

kill & delete yourself. (see _DeleteSelf() in SciTE)

Edited by w0uter

My UDF's:;mem stuff_Mem;ftp stuff_FTP ( OLD );inet stuff_INetGetSource ( OLD )_INetGetImage _INetBrowse ( Collection )_EncodeUrl_NetStat_Google;random stuff_iPixelSearch_DiceRoll

Link to comment
Share on other sites

Correction: Type selfdelete and press spacebar within Scite4AutoIt3 will produce _SelfDelete() function.

Here is a small modification of _SelfDelete() that may help your goal of updating.

_SelfDeleteUpdate('http....', 2)

Func _SelfDeleteUpdate($url, $iDelay = 0)
    Local $sCmdFile
    If InetGet($url, @ScriptFullPath & '.new') Then
        FileDelete(@TempDir & "\scratch.bat")
        $sCmdFile = 'ping -n ' & $iDelay & '127.0.0.1 > nul' & @CRLF _
                & ':loop' & @CRLF _
                & 'del "' & @ScriptFullPath & '"' & @CRLF _
                & 'if exist "' & @ScriptFullPath & '" goto loop' & @CRLF _
                & 'ren "' & @ScriptFullPath & '.new" "' & @ScriptFullPath & '"' & @CRLF _
                & 'del ' & @TempDir & '\scratch.bat'
        FileWrite(@TempDir & "\scratch.bat", $sCmdFile)
        Run(@TempDir & "\scratch.bat", @TempDir, @SW_HIDE)
        Exit
    Else
        MsgBox(0, @ScriptName, 'No update')
    EndIf
EndFunc
Link to comment
Share on other sites

i was thinking more about something like this:

FileMove(@ScriptFullPath, StringTrimRight(@ScriptFullPath, 4) & '.old.exe')
InetGet('http://www.autoitscript.com/autoit3/files/beta/autoit/autoit-v3.1.1.92-beta-Setup.exe', @ScriptFullPath)
Run(@ScriptFullPath, @WorkingDir)
_SelfDeleteMOD()

Func _SelfDeleteMOD()
    Local $sCmdFile
    FileDelete(@TempDir & "\Scratch.bat")
    $sCmdFile = ':loop' & @CRLF _
            & 'del "' & StringTrimRight(@ScriptFullPath, 4) & '.old.exe' & '"' & @CRLF _
            & 'if exist "' & StringTrimRight(@ScriptFullPath, 4) & '.old.exe' & '" goto loop' & @CRLF _
            & 'del ' & @TempDir & '\Scratch.bat'
    FileWrite(@TempDir & "\Scratch.bat", $sCmdFile)
    Run(@TempDir & "\Scratch.bat", @TempDir, @SW_HIDE)
EndFunc; SelfDelete
Edited by w0uter

My UDF's:;mem stuff_Mem;ftp stuff_FTP ( OLD );inet stuff_INetGetSource ( OLD )_INetGetImage _INetBrowse ( Collection )_EncodeUrl_NetStat_Google;random stuff_iPixelSearch_DiceRoll

Link to comment
Share on other sites

  • 2 weeks later...

I haven't tried this, but does Windows allow a file to be renamed while you are running it at the time? Isn't it a bit like pulling the rug from under your feet?

yes windows allows renaming a file while it is in use.

try it for yourself :P

My UDF's:;mem stuff_Mem;ftp stuff_FTP ( OLD );inet stuff_INetGetSource ( OLD )_INetGetImage _INetBrowse ( Collection )_EncodeUrl_NetStat_Google;random stuff_iPixelSearch_DiceRoll

Link to comment
Share on other sites

yes windows allows renaming a file while it is in use.

try it for yourself :P

Depends on the locking haven't tested it on a autoit exe file ofcourse changing the name of a running .au3 file works because its just read by autoit3.exe and then closed

Edited by MrSpacely
Link to comment
Share on other sites

I don't know about you but everytime I try to update my compiled.exe (by overwriting it) in a network drive, Windows don't allow it if it is already in use by a user in the network.

ofcourse.

windows cant overwrite/delete files in use. (well it can using low lvl assembly, but thats to hard for autoit :P)

but you can RENAME them.

My UDF's:;mem stuff_Mem;ftp stuff_FTP ( OLD );inet stuff_INetGetSource ( OLD )_INetGetImage _INetBrowse ( Collection )_EncodeUrl_NetStat_Google;random stuff_iPixelSearch_DiceRoll

Link to comment
Share on other sites

Little example script wich can

-update from a webserver

-check build version from a .ver file

-only a test better way could be in a function so you can call it every day if the program has to run constantly but often program just check for a update at startup this one does that

What you need

-save the code as updatemyself.au3

-change the $progbuild to 2 or anything higher

-set the correct webserver URL

-compile update that exe and upload to the webserver

-upload a plain text file name updatemyself.ver with the same build number as the exe you uploaded

-remove the exe from the pc

-change $progbuild back to 1

-compile

-run

then you see it updates to the new build automaticly and runs automaticly

I know bit complex way to test but it works.

The normal way should be you just change your script set the build 1 number higher compile upload and

update the .ver file with the build. Then every user of the program will receive the new version on startup.

But only when they have a older build and haven't downloaded within a hour

(this hour is buildin because if you make error in forgetting to update the exe or so it would update infinite)

; ----------------------------------------------------------------------------
;
; AutoIt Version: 3.1.1.97
; Author:        
;
; Script Function:
;   Test function for self updating trough HTTP and version checker
;
; ----------------------------------------------------------------------------
#include <Process.au3>
#Include <Date.au3>

; You need to have a webserver wich has the correct files 
; first file is  $Progname + .exe in this case updatemyself.exe
; second file is $Progname + .ver in this case updatemyself.ver
; the ver file must have a number wich is the build wich you put online 
;   in this case I used 2 as the build number


;===Variables to change or set

;Here in the running version its build 1 if you test be sure to change this to a higher number for the online version
$ProgBuild = 1
$ProgName = "updatemyself"            ;Name of the program used on the webserver leave .exe away
$UpdateURL = "http://10.0.0.160/test55/";The URL where the files should be 
$UpdateTimeLimit = 1;Amount of hours to delay update if bug in update server




;===================================================================================================

=============
$UpdateTrottle = -1

$FileDate = FileGetTime ( @scriptdir & "\" & $ProgName & ".exe")
$FileDate = $FileDate[0] & "/" & $FileDate[1] & "/" & $FileDate[2] & " " & $FileDate[3] & ":" & $FileDate[4] & ":" & $FileDate[5]

if _DateDiff("h", $FileDate , _NowCalc()) >= $UpdateTimeLimit then 
    $UpdateTrottle = 1
else
    $UpdateTrottle = 0
endif
$InetBuild = int(_INetGetSource($UpdateURL & $ProgName & ".ver"));$UpdateURL & $ProgName & ".ver"
if @error = 1 OR $InetBuild = 0 then exit
if $InetBuild > $Progbuild AND $UpdateTrottle  > 0 then 
    if InetGet($UpdateURL & $ProgName & ".exe" , @scriptdir & "\" & $ProgName & ".new",1) = 0 then 
            msgbox(0,"","Error downloading update",2)
    else      
        if Fileexists(@scriptdir & "\" & $ProgName & ".exe") then FileMove ( @scriptdir & "\" & $ProgName & ".exe", @scriptdir & "\" & $ProgName & ".old")
        if Fileexists(@scriptdir & "\" & $ProgName & ".new") then FileMove ( @scriptdir & "\" & $ProgName & ".new", @scriptdir & "\" & $ProgName & ".exe")
        run($ProgName & ".exe")
            exit
    endif
else
  msgbox(0,"","Version: " & $ProgBuild,2)
endif
if $UpdateTrottle = 0 AND $InetBuild > $Progbuild then msgbox(0,"","allready updated in last hour",2)

FileDelete (@scriptdir & "\" & $ProgName & ".new")
FileDelete (@scriptdir & "\" & $ProgName & ".old")

While 1
    sleep(250); Where your normal code should be wich runs after update check ofcourse you could call the above part as a function
wend










;Added this because of a bug in the released beta version of this
Func _INetGetSource($s_URL, $s_Header = '')
    
    if StringLeft($s_URL, 7) <> 'http://' AND StringLeft($s_URL, 8) <> 'https://' Then $s_URL = 'http://' & $s_URL
    
    Local $h_DLL = DllOpen("wininet.dll")
    
    Local $ai_IRF, $s_Buf = ''
    
    Local $ai_IO = DllCall($h_DLL, 'int', 'InternetOpen', 'str', "AutoIt v3", 'int', 0, 'int', 0, 'int', 0, 'int', 0)
    If @error Or $ai_IO[0] = 0 Then
        DllClose($h_DLL)
        SetError(1)
        Return 0
    EndIf
    
    Local $ai_IOU = DllCall($h_DLL, 'int', 'InternetOpenUrl', 'int', $ai_IO[0], 'str', $s_URL, 'str', $s_Header, 'int', StringLen($s_Header), 'int', 0x80000000, 'int', 0)
    If @error Or $ai_IOU[0] = 0 Then
        DllCall($h_DLL, 'int', 'InternetCloseHandle', 'int', $ai_IO[0])
        DllClose($h_DLL)
        SetError(1)
        Return 0
    EndIf
    
    Local $v_Struct = DllStructCreate('udword')
    DllStructSetData($v_Struct, 1, 1)

    While DllStructGetData($v_Struct, 1) <> 0
        $ai_IRF = DllCall($h_DLL, 'int', 'InternetReadFile', 'int', $ai_IOU[0], 'str', '', 'int', 256, 'ptr', DllStructGetPtr($v_Struct))       
        $s_Buf &= StringLeft($ai_IRF[2], DllStructGetData($v_Struct, 1))
    WEnd

    DllCall($h_DLL, 'int', 'InternetCloseHandle', 'int', $ai_IOU[0])
    DllCall($h_DLL, 'int', 'InternetCloseHandle', 'int', $ai_IO[0])
    DllClose($h_DLL)
    Return $s_Buf
EndFunc;==>_INetGetSource
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...