The PODA Blog

News, views and articles from our membership

Archive for March 7th, 2007

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.

Visual Basic:
'-------------------------------------------------------------------------
' 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:

Visual Basic:
Option Explicit

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 »