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:
http://www.garybeene.com/files/gbsnippets.pbr

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