-
Jan 25th, 2018, 07:10 AM
#1
Thread Starter
Addicted Member
[RESOLVED] How to install an exe on itself ?
Hi,
When I compile a new version of my software it is advisable to copy the .exe at the same place because the folder also contains own user files.
Of cause the software cannot copy the .exe to itself because it is in use.
I give a message saying a new release is available which also gives the path where the .exe should be downloaded.
But often the user downloads at another place and is not happy because he has lost his childs.
How can I download myself onto myself, or start another .exe which does the job ?
Thanks for your help.
-
Jan 25th, 2018, 09:43 AM
#2
Re: How to install an exe on itself ?
Hi Herve_be,
It's been a while ago, but I actually used to do this. I had to put several "checks" in it to get it all working, but here's the gist of it.
* Make a copy of myself (the EXE).
* Execute that copy.
* Copy waits until main copy has terminted.
* Main program terminates.
* Copy kills main copy.
* Copy downloads update (and places it where main copy was, same name).
* Copy executes new program.
* Copy terminates.
* New program detects copy, and keeps trying to kill until successful.
* New program shows its menu/interface, and we're back.
That's all from memory as I abandoned the whole idea several years ago. But it did work.
At this point, my users are all savvy enough to just download an update, delete the old, and replace it with the new. Also, many like keeping the old versions just as a double-check that everything is going to work correctly.
Good Luck,
Elroy
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Jan 25th, 2018, 09:55 AM
#3
Thread Starter
Addicted Member
Re: How to install an exe on itself ?
Thank you but I don't understand why you use a copy of the program, it could be another simple "Upgrader" program as this
Main program detects there is a new version.
Main program downloads the Upgrader.
Main program starts the Upgrader.
Upgrader waits for main program to terminaite : my question is "how does it knows the main program is finished ?
Upgrader downloads main program new version.
Upgrader starts main program new version.
Upgrader terminates.
It is not necessary to kill the Upgrader.
My problem is that my users do not download the new version at the same place (directory) as the old one so the associated files are also elsewhere.
-
Jan 25th, 2018, 10:01 AM
#4
Re: How to install an exe on itself ?
Hi Herve,
Well, if you've got an "Upgrader", then it seems that most of your problems are solved. The only problem you have is that you can't kill a program's EXE while it's running. Therefore, you need a second EXE to help you out. I suppose there are several ways to get this done, but it seems that you have the solution at hand.
Good Luck,
Elroy
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Jan 25th, 2018, 10:07 AM
#5
Re: How to install an exe on itself ?
Ahhh, I also see that you're wanting to figure out if the other program is running.
I can see a couple of solutions.
1) Here's a KillProcess procedure. You could certainly use it. Also, it could be fairly easily modified to just detect to see if the program is still running. It does use the WMI, and dilettante will pop on and say that the WMI may not always be present, but I've never had a problem with it.
Code:
Public Sub KillProcess(ByVal sProcessName As String)
' Kill process using Visual Basic 6 0 and WMI.
' The full .exe name (including the .exe) is supplied, but no path.
' Example: KillProcess "excel.exe"
' BE CAREFUL: No prompt for saving takes place.
' ALSO, it kills all occurrences.
Dim oWMI As Object
Dim ret As Long
Dim oServices As Object
Dim oService As Object
Dim sServiceName As String
Dim bFoundOne As Boolean
'
On Error Resume Next
sProcessName = LCase$(sProcessName)
Set oWMI = GetObject("WinMgmts:")
Set oServices = oWMI.InstancesOf("win32_process")
'
Do
For Each oService In oServices
sServiceName = LCase$(Trim$(CStr(oService.Name)))
If sServiceName = sProcessName Then
ret = oService.Terminate
bFoundOne = True
End If
Next oService
If Not bFoundOne Then Exit Do
If Err Then Exit Do
bFoundOne = False
Loop
On Error GoTo 0
End Sub
Okay, being called to a meeting. I'll post more later.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Jan 25th, 2018, 10:08 AM
#6
Thread Starter
Addicted Member
Re: How to install an exe on itself ?
How does the Upgrader knows that the main program is not running thus it can kill it ?
-
Jan 25th, 2018, 10:20 AM
#7
Re: How to install an exe on itself ?
Originally Posted by Elroy
* Make a copy of myself (the EXE).
* Execute that copy.
* Copy waits until main copy has terminted.
* Main program terminates.
* Copy kills main copy.
* Copy downloads update (and places it where main copy was, same name).
* Copy executes new program.
* Copy terminates.
* New program detects copy, and keeps trying to kill until successful.
* New program shows its menu/interface, and we're back.
Hi, Elroy.
You can rename already running EXE.
- Rename myself;
- Download the new EXE with the actual name;
- Run the new exe;
- Wait until the old exe will be terminated and delete it (in the new EXE code).
You can pass handle or PID of process in any IPC (for example command line).
-
Jan 25th, 2018, 10:39 AM
#8
Re: How to install an exe on itself ?
This is how I used to do it. I would remotely copy the new version to the customer's server. When a user connected to the server, it would compare it's own file date to the file date on the server. If the server file date was newer, it would create a batch file to rename the old file to ".bak" and copy the newer file from the server. If it was one of the sub programs, that was it. If it was the main program, the user would be instructed to restart.
Code:
Private Function CheckFileVer(FileName$) As Boolean
Dim ThisFileName$, ThatFileName$, Runfile%, Response%
Dim ThisFileDate As Double, ThatFileDate As Double
Dim sErr As String
Const sProc As String = "CheckFileVer"
On Error GoTo CheckFileVerErr
ThisFileName$ = App.Path + "\" + FileName$
ThatFileName$ = DataPath + FileName$
ThisFileDate = FileDateTime(ThisFileName$)
ThatFileDate = FileDateTime(ThatFileName$)
If ThisFileDate < ThatFileDate Then
Response% = MsgBox(ThisFileName$ + " is Dated: " + vbCrLf + Format$(ThisFileDate, "dd-mmm-yy hh:nn:ss") _
+ vbCrLf + "A newer version:" _
+ vbCrLf + ThatFileName$ + " Dated: " + vbCrLf + Format$(ThatFileDate, "dd-mmm-yy hh:nn:ss") _
+ vbCrLf + "is available." + vbCrLf + "DOWNLOAD IT?", 4)
If Response% = 6 Then
If FileName$ = VBApp + ".exe" Then
Runfile% = OpenFile(App.Path + "\Update.Bat", 1, 0, 80)
If Runfile% = 0 Then
MsgBox "Problem incurred creating Update File", 16, "ABORT UPDATE"
Exit Function
Else
Print #Runfile%, "copy %1 %2"
Print #Runfile%, "pause New file will now be copied!"
Print #Runfile%, "copy %3 %1"
Print #Runfile%, "REM When finished close this window and restart the program!"
Print #Runfile%, "exit"
Close #Runfile%
End If
Shell App.Path + "\Update.Bat " + ThisFileName$ + " " + App.Path + "\manta.old " + ThatFileName$, 1
End
ElseIf FileName$ = "BackMan.exe" Then
FileCopy ThatFileName$, ThisFileName$
ElseIf FileName$ = "Mantacct.exe" Then
FileCopy ThatFileName$, ThisFileName$
End If
End If
End If
CheckFileVer = True
Exit Function
CheckFileVerErr:
sErr = msModule & gsDelimiter & sProc _
& gsDelimiter & Err.Number & gsDelimiter & Err.Description
Call LogError(sErr)
End Function
J.A. Coutts
-
Jan 25th, 2018, 10:57 AM
#9
Re: How to install an exe on itself ?
Here's an example of The trick's suggestion:
Originally Posted by Bonnie West
This example shows how a single EXE can replace a currently running instance of itself with a new version (for simplicity, this demo just copies the old EXE). It relies on the fact that executables can be renamed even while they're running. This example also shows how the old version can instruct the new version to delete the old executable file after it terminates. Compile the following code first before trying it:
Code:
Option Explicit 'In a standard module
Private Const DELETE_THIS As String = " /DeleteThis "
Private Declare Sub Sleep Lib "kernel32.dll" (Optional ByVal dwMilliseconds As Long)
Private Sub Main()
Dim sExeFileName As String, sTmpFileName As String
If ProcessCmdLineArgs(" " & Command$ & " ") Then Exit Sub
sExeFileName = App.Path & "\" & App.EXEName & ".exe"
sTmpFileName = App.Path & "\" & App.EXEName & ".tmp"
'If sTmpFileName exists, delete it
On Error Resume Next
Select Case (GetAttr(sTmpFileName) And vbDirectory) <> vbDirectory
Case True: SetAttr sTmpFileName, vbNormal: Kill sTmpFileName
End Select
On Error GoTo 0
'Rename this EXE
MsgBox "Before renaming...", vbInformation
Name sExeFileName As sTmpFileName
'Replace old EXE with new EXE
MsgBox "Before copying...", vbInformation
FileCopy sTmpFileName, sExeFileName
'Tell new EXE to delete old EXE
MsgBox "Before starting new EXE & deleting old EXE...", vbInformation
Shell sExeFileName & DELETE_THIS & """" & sTmpFileName & """", vbNormalFocus
End Sub
Private Function ProcessCmdLineArgs(ByRef sCmdLine As String) As Boolean
Dim nTries As Integer, StartPos As Long, EndPos As Long, sFileName As String
StartPos = InStr(1&, sCmdLine, DELETE_THIS, vbTextCompare)
If StartPos Then
StartPos = InStr(StartPos + Len(DELETE_THIS), sCmdLine, """")
EndPos = InStr(StartPos + 1&, sCmdLine, """")
If EndPos Then
sFileName = Mid$(sCmdLine, StartPos + 1&, EndPos - StartPos - 1&)
If LenB(sFileName) Then
On Error Resume Next
SetAttr sFileName, vbNormal
For nTries = 1 To 10
Err.Clear
Kill sFileName
If Err Then Sleep 500&: DoEvents Else Exit For
Next
ProcessCmdLineArgs = MsgBox("End demo?", vbQuestion Or vbYesNo) = vbYes
End If
End If
End If
End Function
-
Jan 25th, 2018, 11:18 AM
#10
Re: How to install an exe on itself ?
Okay, I'm back.
One thing I've run into is that my executable typically resides on a network. I've found that, when multiple people are running it, under certain circumstances, you can rename it and even delete it. However, when you do so, you crash all the other people who were using it. The one thing you can't do is copy over it with another file of the same name.
Herve_be, I'm not sure those are concerns for you. If not, then ignore that concern.
Now, regarding figuring out if you (your workstation) is running the program, there are a few different approaches, all requiring API calls. If you know the name (actually title) of a form that'll always be loaded, you could search for it. If you're sure of the executable's name, you could search for that in your running processes list.
Maybe that'll help.
Good Luck,
Elroy
@Trick: Yeah, back when I was still doing this, I did use a bit of a Command$ trick to get it all done.
Last edited by Elroy; Jan 25th, 2018 at 11:21 AM.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Jan 26th, 2018, 04:55 AM
#11
Thread Starter
Addicted Member
Re: How to install an exe on itself ?
Hi,
I did like this, it works fine :
- the main program checks for a new version;
- if it find one it starts an Upgrade program;
- main program ends.
Upgrade program
Code:
On Error Resume Next
Do
Kill App.Path & "\RVReefTools.exe"
DoEvents
Loop While Err.Number = 75 ' loops while the main program is still running and cannot be killed
...
URLDownloadToFile(0, URL, App.Path & "\" & FileName, BINDF_GETNEWESTVERSION, 0) ' Download new version
...
Shell(App.Path & "\RVReefTools.exe", vbNormalFocus) ' Starts new version
-
Jan 26th, 2018, 09:10 AM
#12
Re: How to install an exe on itself ?
Herve, I'll just throw in one thing to be careful of here. What if your URLDownloadToFile call fails to download the new .exe? Then the user is left in a state where the main executable is no longer present, because you deleted it in the Do-Loop.
It shouldn't be too much work to shuffle steps around and try to download the upgraded exe first (to a filename like RVReefTools.exe.new), and then only if that download is successful delete the .exe file and then rename the downloaded file.
Code:
On Error Resume Next
URLDownloadToFile(0, URL, App.Path & "\" & FileName & ".new", BINDF_GETNEWESTVERSION, 0) ' Download new version
...
If download worked then
...
Do
Kill App.Path & "\RVReefTools.exe"
DoEvents
Loop While Err.Number = 75 ' loops while the main program is still running and cannot be killed
...
'Add code to rename downloaded file to remove the .new from the end of the filename
...
Shell(App.Path & "\RVReefTools.exe", vbNormalFocus) ' Starts new version
End If
-
Jan 26th, 2018, 09:23 AM
#13
Thread Starter
Addicted Member
Re: How to install an exe on itself ?
For the moment, if a new version is available, you cannot work with the old one anymore : it tells you that you must download the new version then ends.
So keeping the old version is useless.
Before ending it also opens a WEB page explaining "what's new" and also giving a link to download the program manually.
If URLDownloadToFile call fails to download the new .exe you can still download it from the web page, as when you install it for the first time.
-
Jan 26th, 2018, 09:54 AM
#14
Thread Starter
Addicted Member
Re: How to install an exe on itself ?
But you are right, I changed so
Code:
Private Sub Form_Load()
On Error GoTo ErrorHandler
...
Call DeleteUrlCacheEntry(URL)
If URLDownloadToFile(0, URL, App.Path & "\RVReefTools.new", BINDF_GETNEWESTVERSION, 0) = 0 Then
On Error Resume Next
Do
Kill App.Path & "\RVReefTools.exe"
DoEvents
Loop While Err.Number = 75
On Error GoTo ErrorHandler
Name App.Path & "\RVReefTools.new" As App.Path & "\RVReefTools.exe"
ProcessID = Shell(App.Path & "\RVReefTools.exe", vbNormalFocus)
Else
MsgBox ("Le logiciel n'a pas pu être téléchargé."), vbCritical
End If
End
ErrorHandler:
MsgBox ("Erreur " & Err.Number & " (" & Err.Description & ")" & Chr$(10) & " ligne " & Erl), vbCritical
End
End Sub
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|