Updating An add-in Through the Internet
Posted by Jan Karel Pieterse on 7th March 2007
Introduction
When you're offering an add-in through your website you usually have no connection to the people who are using your programming work. It is not unusual that you have discovered (or been pointed at) bugs in your code or that you've done some updating to the utility you'd like your users to benefit from. Sometimes it might be useful if your users could be notified automatically of such updates (many software titles have such a mechanism built-in). This little article shows
a way to include that functionality with your add-in.
Assumptions for this article
I've assumed the following:
- You only want to update the add-in itself, not any accompanying files.
- The name of the download file is identical to the add-in's filename.
- Your add-in has a build number.
- There is a html page on your website (or you render one on demand extracting the build number from a database using a query in some php or asp code) which contains nothing else than a build number (no HTML tags surrounding the number).
Updating mechanism
The updating process works as follows:
- The add-in checks when the last update check has been performed.
- If this is more than 7 days ago (or has never been done before), the check is started.
- The add-in fetches the html page from your website and compares build numbers.
- If build on web is higher, permission is asked to download and update.
- The current add-in saves itself, appending "(OldVersion)" to its filename (this enables us to overwrite the old add-in with the new one).
 Note: I've tried whether marking the add-in file as read-only would enable the code to delete the file itself, but this appears not to work when the file is on a local drive. I've heard reports that when the add-in is on a network folder, this does work. I don't know if it works in all cases though and would be pleased to get your feedback on that (enter a comment, or go to my site's contact page to send me a message).
- A message is shown that asks the user to reopen Excel.
- Excel opens the new file. This file also contains code that removes the "(OldVersion)"Â file.
Code
The code that does the actual updating is wrapped in a class module called "clsUpdate", see the entire code below. The code needs a reference to the "Microsoft Internet Controls" library.
' Module   : clsUpdate
' Company  : JKP Application Development Services (c)
' Author   : Jan Karel Pieterse
' Created  : 19-2-2007
' Purpose  : Class to check for program updates
'-------------------------------------------------------------------------
Option Explicit
Private Declare Function URLDownloadToFile Lib "urlmon" _
   Alias "URLDownloadToFileA" (ByVal pCaller As Long, _
   ByVal szURL As String, ByVal szFileName As String, _
   ByVal dwReserved As Long, ByVal lpfnCB As Long) As Long
Private mdtLastUpdate As Date
Private msAppName As String
Private msBuild As String
Private msCheckURL As String
Private msCurrentAddinName As String
Private msDownloadName As String
Private msTempAddInName As String
Private Sub DownloadFile(strWebFilename As String, strSaveFileName As String)
   ' Download the file.
   URLDownloadToFile 0, strWebFilename, strSaveFileName, 0, 0
End Sub
Public Function IsThereAnUpdate() As Boolean
   Dim oIE As InternetExplorer
   Set oIE = New InternetExplorer
   With oIE
       .Navigate2 CheckURL
       Do
       Loop Until .Busy = False
       If Len(.Document.body.innerhtml)> 0 Then
           If CLng(.Document.body.innerhtml)> CLng(Build) Then
               IsThereAnUpdate = True
           End If
       End If
       .Quit
   End With
   Set oIE = Nothing
End Function
Public Property Get Build() As String
   Build = msBuild
End Property
Public Property Let Build(ByVal sBuild As String)
   msBuild = sBuild
End Property
Public Sub RemoveOldCopy()
   CurrentAddinName = ThisWorkbook.FullName
   TempAddInName = CurrentAddinName & "(OldVersion)"
   On Error Resume Next
   Kill TempAddInName
End Sub
Public Function GetUpdate() As Boolean
   On Error Resume Next
   'If workbook has been saved readonly, we can safely delete the file!
   If ThisWorkbook.ReadOnly Then
       Err.Clear
       Kill CurrentAddinName
   End If
   LastUpdate = Now
   If Err.Number = 70 Then
       ThisWorkbook.SaveAs TempAddInName
       DoEvents
       Kill CurrentAddinName
       On Error GoTo 0
       DownloadFile DownloadName, CurrentAddinName
   End If
   If Err = 0 Then GetUpdate = True
End Function
Private Property Get CurrentAddinName() As String
   CurrentAddinName = msCurrentAddinName
End Property
Private Property Let CurrentAddinName(ByVal sCurrentAddinName As String)
   msCurrentAddinName = sCurrentAddinName
End Property
Private Property Get TempAddInName() As String
   TempAddInName = msTempAddInName
End Property
Private Property Let TempAddInName(ByVal sTempAddInName As String)
   msTempAddInName = sTempAddInName
End Property
Public Property Get DownloadName() As String
   DownloadName = msDownloadName
End Property
Public Property Let DownloadName(ByVal sDownloadName As String)
   msDownloadName = sDownloadName
End Property
Public Property Get CheckURL() As String
   CheckURL = msCheckURL
End Property
Public Property Let CheckURL(ByVal sCheckURL As String)
   msCheckURL = sCheckURL
End Property
Public Property Get LastUpdate() As Date
   Dim dtNow As Date
   dtNow = Int(Now)
   mdtLastUpdate = CDate(GetSetting(AppName, "Updates", "LastUpdate", CStr(dtNow)))
   If mdtLastUpdate = dtNow Then
       'Never checked for an update, save today!
       SaveSetting AppName, "Updates", "LastUpdate", CStr(Int(dtNow))
   End If
   LastUpdate = mdtLastUpdate
End Property
Public Property Let LastUpdate(ByVal dtLastUpdate As Date)
   mdtLastUpdate = dtLastUpdate
   SaveSetting AppName, "Updates", "LastUpdate", CStr(Int(mdtLastUpdate))
End Property
Public Property Get AppName() As String
   AppName = msAppName
End Property
Public Property Let AppName(ByVal sAppName As String)
   msAppName = sAppName
End Property
Â
Then in a normal module, we create an instance of this class, set it's initial values and do the updating. The comments in the code describe what is being done:
Public Sub CheckAndUpdate()
   Dim cUpdate As clsUpdate
   Set cUpdate = New clsUpdate
   With cUpdate
       'Set intial values of class
       'Current build
       .Build = "0"
       'Name of this app, probably a global variable, such as GSAPPNAME
       .AppName = "CheckForUpdate"
       'Get rid of possible old backup copy
       .RemoveOldCopy
       'URL which contains build # of new version
       .CheckURL = "<a href="http://www.jkp-ads.com/downloads/UpdateAnAddinBuild.htm">http://www.jkp-ads.com/downloads/UpdateAnAddinBuild.htm</a>"
       'Check once a week
       If Now - .LastUpdate>= 7 Or Int(Now) = .LastUpdate Then
           If .IsThereAnUpdate Then
               If MsgBox("We have an update, do you wish to download?", vbQuestion + vbYesNo) = vbYes Then
                   .DownloadName = "<a href="http://www.jkp-ads.com/downloads/">http://www.jkp-ads.com/downloads/</a>" & ThisWorkbook.Name
                   If .GetUpdate Then
                       MsgBox "Successfully updated the addin, please restart Excel to start using the new version!", vbOKOnly + vbInformation
                   Else
                       MsgBox "Updating has failed.", vbInformation + vbOKOnly
                   End If
               End If
           End If
       End If
   End With
   Set cUpdate = Nothing
End Sub
Basically, that is all there is to it!
Download Demo
Download the demo file here: Update An addin
This article has been published on my website as well. Go check it out there and don't forget to have a look at other articles available on my site too:
Check out this article on JKP Application Development Services' website
Regards,
Jan Karel Pieterse
Posted in Excel, Office (All) | No Comments »


