This code was posted last week, but seems to have disappeared, so I'm putting it back online.
The code below is a PowerBASIC remake of the code I've been using in my freeware/shareware
apps for over 10 years. It's what I use in gbSnippets.
It consists of 2 parts - one that goes in your app and a standalone app that you distribute with your application.
The standalone app is call gbOnlineUpdate.exe The standalone app is NOT unique to each program. Once you've
created it you can use it with all your apps.
To make it work, you put two files online:
- myapp.new 'the latest EXE, renamed with a .new extension.
- myapp.ver 'a single line of text with the latest version #
Then, your uses selects "Online Update" from you app. The app compares it's version # with
the one on the server (in myapp.ver). If a new version is available, the user is allowed to
download the new file (myapp.new). The app then downloads the file. It then opens
gbOnlineUpdate, passing it information, and shuts itself down.
gbOnlineUpdate renames the old EXE as myapp.exe.old. It renames the just-downloaded
myapp.new as myapp.exe. It then (optionally) starts up myapp.exe and shuts itself
down - completing the online udpate.
The code for both parts is provided below, and is also available in the
gbSnippets PowerBASIC source code library (snippet# gbs_00150 and
gbs_00151). You can get the entire library by downloading gbSnippets
or you can view individual snippets online.
gbSnippets home page: http://www.garybeene.com/sw/gbsnippets.htm
Online source code listings: http://www.garybeene.com/power/code/
If you've already installed gbSnippets, you can ensure that your local library
is synchronized with the latest snippets on the gbSnippets server by using
the "Actions/Synchronize with gbSnippets Server" menu.
This version does NOT provide status of the downloaded file. I'm working on a revision
that includes that feature and will post it as soon as it is available. But this has worked
so well for me that I thought I'd post it anyway.
Finally, here's a direct link to the gbsnippets.pbr resource file use in this code:
The code below is a PowerBASIC remake of the code I've been using in my freeware/shareware
apps for over 10 years. It's what I use in gbSnippets.
It consists of 2 parts - one that goes in your app and a standalone app that you distribute with your application.
The standalone app is call gbOnlineUpdate.exe The standalone app is NOT unique to each program. Once you've
created it you can use it with all your apps.
To make it work, you put two files online:
- myapp.new 'the latest EXE, renamed with a .new extension.
- myapp.ver 'a single line of text with the latest version #
Then, your uses selects "Online Update" from you app. The app compares it's version # with
the one on the server (in myapp.ver). If a new version is available, the user is allowed to
download the new file (myapp.new). The app then downloads the file. It then opens
gbOnlineUpdate, passing it information, and shuts itself down.
gbOnlineUpdate renames the old EXE as myapp.exe.old. It renames the just-downloaded
myapp.new as myapp.exe. It then (optionally) starts up myapp.exe and shuts itself
down - completing the online udpate.
The code for both parts is provided below, and is also available in the
gbSnippets PowerBASIC source code library (snippet# gbs_00150 and
gbs_00151). You can get the entire library by downloading gbSnippets
or you can view individual snippets online.
gbSnippets home page: http://www.garybeene.com/sw/gbsnippets.htm
Online source code listings: http://www.garybeene.com/power/code/
If you've already installed gbSnippets, you can ensure that your local library
is synchronized with the latest snippets on the gbSnippets server by using
the "Actions/Synchronize with gbSnippets Server" menu.
This version does NOT provide status of the downloaded file. I'm working on a revision
that includes that feature and will post it as soon as it is available. But this has worked
so well for me that I thought I'd post it anyway.
Finally, here's a direct link to the gbsnippets.pbr resource file use in this code:
Code:
Online Update #1 - Check For Updates Allowing a user to download a new version of software is very common. Here's one way to do it. This approach has no security features, so it is best used for downloading freeware applications. Also, this approach only addresses online updating of the application EXE. It does not support downloading updated secondary/support files. The approach is pretty simple, but requiring only the following steps: 1. On your server, place the latest EXE - but with an extension of "app.new". Using .new for an extension bypasses download constraints on downloading files with .EXE extensions and avoids downloading a file with the same name as your application. 2. On your server, place a text file which contains only the version/build number of the latest EXE. name it app.ver. 3. In your app, place a menu item Help\CheckForUpdates which calls the CheckForUpdates procedure shown below 4. Run "Check for Updates" - it will download "app.ver", read the content, and compare the local and server EXE versions. If a newer version is on the servers, and the user agrees, the function will download the latest version of "app" (a file called "app.new"). CheckForUpdates also deletes, if they exist, the files "app.exe.old" and "app.new", to make room for the new downloadable version. CheckForUpdates then starts a second application, gbOnlineUpdate, passing it the name of the application to be updated plus the position/size for displaying gbOnlineUpdate. gbOnlineUpdate source code is included in another snippet in this snippet library. Put the gbOnlineUpdate.exe file in the same folder as your application EXE. One final note: this approach uses the DownLoadURLToFile API to download files. The API does not provide download progress information. 'Primary Code: To initiate an online update, a single procedure is all that must be added to your application. That procedure includes a local variable containing the current version/build# of the application. 'Because of length, the CheckForUpdates procedure is shown only once, in the compilable example below. 'Compilable Example: This code uses a menu item under HELP to call the CheckForUpdates routine. That routine verifies that a new version of itself (named xxx.new) is available from the server, downloads the new version, and starts a second program called gbOnlineUpdate. The second program, gbOnlineUpdate, backs up the original EXE by renaming it as xxx.exe.old, then renames the download file as xxx.exe and optionally restarts the new program. #Compile Exe '#Bloat 1024 #Dim All #Include "Win32API.inc" #Include "CommCtrl.inc" #Include "WinINET.inc" #Resource "gbsnippets.pbr" %ID_MenuHelpCheckForUpdates = 100 : %ID_DownloadTimer = 300 : %ID_Label = 400 Global hDlg As Dword, hMenu As Dword, hMenuHelp As Dword, hWait as Long Global hMenuHelpCheckForUpdate As Dword Function PBMain() As Long Dialog New Pixels, 0, "Test Code",300,300,200,200, %WS_OverlappedWindow To hDlg Control Add Label, hDlg, 500, "I am the original EXE", 20,20,140,20, %WS_Border Or %SS_Center AddMenu Dialog Show Modal hDlg Call DlgProc End Function CallBack Function DlgProc() As Long If CB.Msg = %WM_Command AND CB.Ctl = %ID_MenuHelpCheckForUpdates Then CheckForUpdates End Function Sub AddMenu Menu New Bar To hMenu Menu New Popup To hMenuHelp Menu Add Popup, hMenu, "&Help", hMenuHelp, %MF_Enabled Menu Add String, hMenuHelp, "&Check For Update", %ID_MenuHelpCheckForUpdates, %MF_Enabled Menu Attach hMenu, hDlg End Sub Sub CheckForUpdates Local ServerVer$, Style&, URLPath As Asciiz*%Max_Path, LocalPath As Asciiz*%Max_Path, pid??? Local x As Long, y As Long, h As Long, w As Long, LocalVer$, app$, iResult& app$ = "app" 'the name of your application, without the EXE - use lowercase! URLPath = "http://www.garybeene.com/files/" + app$ + ".ver" 'use your own server information (mine does have app.ver for your use) LocalPath = Exe.Path$ + app$ + ".ver" LocalVer$ = "5.1" 'use a string representing a numerical value 'get the .ver file from the server. if cannot get it tell user there was a problem and then exit sub iResult& = DeleteURLCacheEntry(URLPath) '1 = success clear the cache If URLDownloadToFile (ByVal 0, URLPath, LocalPath, 0, 0) Then MsgBox "Update information not available!", %MB_Ok Or %MB_IconInformation, "Online Update" Exit Sub End If 'check if server version is newer. if not, tell user and then exit sub Open Exe.Path$ + app$ + ".ver" For Input As #1 Line Input #1, ServerVer$ 'get version of app that is on the server Close #1 If Val(ServerVer$) <= Val(LocalVer$) Then 'check to see if the server version is newer than the local version MsgBox "You have the latest update!" Exit Sub End If 'server version is newer than local version 'ask user for permission to proceed with download of "app.new" Style& = %MB_OkCancel Or %MB_IconQuestion Or %MB_TaskModal If MsgBox ("Update available. Download and install?", Style&, "Online Update") = %IDCancel Then Exit Sub 'before downloading, remove the existing .old and .new files, if they exist If IsFile(Exe.Path$ + app$ + ".exe.old") Then Kill Exe.Path$ + app$ + ".exe.old" 'kill .old to clear the way If IsFile(Exe.Path$ + app$ + ".new") Then Kill Exe.Path$ + app$ + ".new" 'kill .new to clear the way 'now download the new version to same folder as the application URLPath = "http://www.garybeene.com/files/" + app$ + ".new" 'get the new app from the server LocalPath = Exe.Path$ + app$ + ".new" 'download as app.new iResult& = DeleteURLCacheEntry(URLPath) '1 = success clear the cache DisplayWaitDialog If URLDownloadToFile (ByVal 0, URLPath, LocalPath, 0, 0) Then Dialog End hWait 'download failed. tell the user then exit sub MsgBox "Download of updated version of App failed!", %MB_Ok Or %MB_IconInformation, "Online Update" Exit Sub Else Dialog End hWait 'the new application was successfully downloaded, so start gbOnlineUpdate.EXE, passing app.exe 'dialog dimensions /top /left /width /height are passed so gbOnlineUpdate can be centered on currently running app.EXE 'then close app.EXE Dialog Get Loc hDlg To x,y : Dialog Get Size hDlg To w,h pid??? = Shell (Exe.Path$ + "gbOnlineUpdate.exe " + app$ + " " + Str$(x) + " " + Str$(y) + " " + Str$(w) + " " + Str$(h)) 'note: use 1 or more spaces to separate gbOnlineUpdate command line arguments Sleep 350 'strictly for effect - gbOnlineUpdate appears briefly on top of app Dialog End hDlg 'quit this application - gbOnlineUpdate is now running End If End Sub Sub DisplayWaitDialog() Local x As Long, y As Long, w As Long, h As Long, wX As Long, wY As Long Dialog Get Client hDlg To w,h wX = 150 : wY = 60 x = (w-wX)/2 'gets left position of WaitDialog to center over app y = (h-wY)/2 'gets top position of WaitDialog to center over app Dialog New Pixels, hDlg, "", x, y, wX, wY, %WS_Popup To hWait Control Add Label, hWait, %ID_Label, "Please wait ... ", 0, 0, wX, wY, %SS_Center Or %SS_CenterImage Or %WS_Border Control Set Color hWait, %ID_Label, %Black, %White Dialog Show Modeless hWait End Sub 'gbs_00050
Code:
Online Update #2 - gbOnlineUpdate.exe This is code for the standalone application, which I call gbOnlineUpdate, which you distribute with your app, In general, your original app downloads a new version of itself from a server. It calls gbUpdate and then closes itself. gbUpdate removes the old EXE and installs the new EXE, then starts the new EXE. When calling gbUpdate, your application passes command line data consisting of the application's name, size, and position. gbUpdate locates/resizes itself relative to your application. 'Primary Code: This code confirms that the command line used to call gbUpdate has valid data - a valid file called myapp.new, the original file called myapp.exe, and legal dialog dimensions. Function VerifyCommandLineAndFiles(x as long, y as long, w as long, h as long) As Long 'get the five parameters from command line used to start gbUpdate AppName$ = Command$(1) : x = Val(Command$(2)) : y = Val(Command$(3)) : w = Val(Command$(4)) : h = Val(Command$(5)) 'verify that needed files .new/.exe are present, check validity of passed size/location arguments If IsFile(Exe.Path$ + AppName$ + ".exe") = %False Then MsgBox "Invalid application specified! gbUpdate closing. ", %MB_Ok + %MB_IconExclamation, AppName$ + " Online Update" ElseIf IsFile(Exe.Path$ + AppName$ + ".new") = %False Then MsgBox "Application update file missing! gbUpdate closing. ", %MB_Ok + %MB_IconExclamation, AppName$ + " Online Update" ElseIf x<=10 Or y<=10 Or w<=10 Or h<=10 Then MsgBox "Invalid application data specified! gbUpdate closing. ", %MB_Ok + %MB_IconExclamation, AppName$ + " Online Update" Else Function = 1 End If End Function 'This additional code is used in the gbUpdate Callback function to install/run the new app Case %WM_Command Select Case CB.Ctl Case %IdOk 'renames the old EXE as .old, then renames the downloaded file from .NEW to .EXE If IsFile(Exe.Path$ + AppName$ + ".exe.old") Then Kill Exe.Path$ + AppName$ + ".exe.old" Name Exe.Path$ + AppName$ + ".exe" As Exe.Path$ + AppName$ + ".exe.old" Name Exe.Path$ + AppName$ + ".new" As Exe.Path$ + AppName$ + ".exe" Dialog End hDlg End Select Case %WM_Destroy Control Get Check hDlg, %IDCheckBox To iResult If iResult = 1 Then pid??? = Shell (Exe.Path$ + AppName$ + ".exe") 'runs 'Compilable Example: #Compile Exe #Dim All #Include "Win32API.inc" #Resource "gbsnippets.pbr" %IDLabel = 500 : %IDCheckBox = 501 : %IDImage = 502 Global hDlg As Dword, AppName$ Function PBMain() As Long Local x As Long, y As Long, h As Long, w As Long If VerifyCommandLineAndFiles(x,y,w,h) = 0 Then Exit Function Dialog New Pixels, 0, AppName$ + " Online Update",x+w/2-150,y+h/2-75,300,150, %WS_OverlappedWindow To hDlg Dialog Set Icon hDlg, "logo" Control Add Image, hDlg, %IDImage, "gbupdate", 20, 10, 265, 70, %WS_Border Control Add Label, hDlg, %IDLabel, "Ready to install " + AppName$ + ". Continue?", 20,90,270,20, %SS_Center Control Add Button, hDlg, %IdOk,"Ok", 30,115,30,25 Control Add Button, hDlg, %IdCancel,"Cancel", 70,115,50,25 Control Add Checkbox, hDlg, %IDCheckBox,"Start on exit", 150,115,150,20 Control Set Check hDlg, %IDCheckBox, 1 'optional (start on exit) Dialog Show Modal hDlg Call DlgProc End Function CallBack Function DlgProc() As Long Dim pid???, iResult As Long Select Case CB.Msg Case %WM_Command Select Case CB.Ctl Case %IdOk If IsFile(Exe.Path$ + AppName$ + ".exe.old") Then Kill Exe.Path$ + AppName$ + ".exe.old" Name Exe.Path$ + AppName$ + ".exe" As Exe.Path$ + AppName$ + ".exe.old" Name Exe.Path$ + AppName$ + ".new" As Exe.Path$ + AppName$ + ".exe" Dialog End hDlg Case %IdCancel Dialog End hDlg End Select Case %WM_Destroy Control Get Check hDlg, %IDCheckBox To iResult If iResult = 1 Then pid??? = Shell (Exe.Path$ + AppName$ + ".exe") End Select End Function Function VerifyCommandLineAndFiles(x as long, y as long, w as long, h as long) As Long 'get the five parameters from command line used to start gbUpdate AppName$ = Command$(1) : x = Val(Command$(2)) : y = Val(Command$(3)) : w = Val(Command$(4)) : h = Val(Command$(5)) If IsFile(Exe.Path$ + AppName$ + ".exe") = %False Then MsgBox "Invalid application specified! gbUpdate closing. ", %MB_Ok + %MB_IconExclamation, AppName$ + " Online Update" ElseIf IsFile(Exe.Path$ + AppName$ + ".new") = %False Then MsgBox "Application update file missing! gbUpdate closing. ", %MB_Ok + %MB_IconExclamation, AppName$ + " Online Update" ElseIf x<=0 Or y<=0 Or w<=0 Or h<=0 Then MsgBox "Invalid application data specified! gbUpdate closing. ", %MB_Ok + %MB_IconExclamation, AppName$ + " Online Update" Else Function = 1 End If End Function 'gbs_00051