After a Compact Framework application has been packaged into a .cab file, it must be deployed and installed on the device. There are several techniques for doing so, including using ActiveSync, a Web site, a storage card, a file share, and even creating an auto-updating application.
Perhaps the most obvious option for deploying a Compact Framework application is to allow the application to be installed when the device is cradled using the ActiveSync software typically used to synchronize files and e-mail, as discussed in Chapter 6.
To do so, the application must be registered with the ActiveSync Application Manager installed on the desktop machine. This process is relatively simple; it requires creating a custom setup executable that invokes the Application Manager on the workstation with ActiveSync installed and passing it an .ini file that contains information about the application to install. For example, to install a simple application called MyApp.exe on the device, the bare-bones .ini file would look as follows[7] :
[7] The .ini file can also include entries to specify the icon that ActiveSync uses when displaying information about the application.
[CEAppManager] Version = 1.0 Component = MyApp [MyApp] Description = My Application Uninstall = MyApp CabFiles = MyApp_PPC.arm.cab
You'll notice that each application to be installed is configured in its own section within the .ini file. In this case, MyApp includes a short description used by the Application Manager when displaying the application in its UI, a pointer to the registry key name used by the Application Manager[8] to uninstall the application if need be, and a comma-delimited list of .cab files to deploy to the device and to install. In this case only the ARM .cab is shown, but others could be added and installed by the Application Manager as necessary.
[8] This key defaults to HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall.
The custom setup application then needs to invoke the Application Manager and pass it the path to the .ini file. To do so, a developer could write a simple desktop VB .NET application like the one shown in Listing 10-1.
Imports System.Diagnostics Imports System.Reflection Imports System.IO Imports Microsoft.Win32 Public Class SetupApp Private Const INI_FILE As String = "\setup.ini" Public Shared Sub Main() Dim ceApp As String = GetCeAppMgr() Dim args As String = GetIniArgs() ' Start the Application Manager process Dim p As Process = Process.Start(ceApp, args) End Sub Public Shared Function GetCeAppMgr() As String ' Get the key from the registry Dim ceApp As String = KeyExists() If ceApp = String.Empty Then MessageBox.Show( _ "The Application Manager is not installed on this machine.", _ "Setup", MessageBoxButtons.OK, MessageBoxIcon.Error) Application.Exit() Else Return ceApp End If End Function Public Shared Function GetIniArgs() As String Return """" & Application.StartupPath & INI_FILE & """" End Function Private Shared Function KeyExists() As String Dim key As RegistryKey = Registry.LocalMachine.OpenSubKey( _ "SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\CEAPPMGR.EXE") If key Is Nothing Then Return String.Empty Else Return key.GetValue("", String.Empty) End If End Function End Class
You'll notice in Listing 10-1 that the program's execution begins in Sub Main and first calls GetCeAppMgr to retrieve the path to the Application Manager. This path is stored in the registry, and so, if it does not exist, the application throws up a message box and quits. Once the path is found, the Setup.ini file (hard-coded using a constant in this case) is formatted with double quotes and returned through the GetIniArgs method. Finally, both the path to the Application Manager and its argument are passed to the shared Start method of the Process class to start the Application Manager.
The custom setup application can then be packaged (along with the .ini and .cab files) using the Windows Installer in VS .NET 2003 and deployed on the machine that the device connects to. When the user double-clicks the setup application, the application will be deployed to the device.
Although this deployment and installation option is intuitive and provides a familiar mechanism to the user, it does require that the custom setup application be installed on the workstation used for synchronizing with the device.
The second option for deploying and installing a Compact Framework application is to use a Web site. Using this option, an organization could create a Internet or intranet site that contains links to the various .cab files created by SDP. This option has the benefit of not requiring the device to be cradled in order to install software.
When a user navigates to the Web page using Pocket Internet Explorer, he or she can tap on the required .cab file. The resulting dialog allows the file to be downloaded and opened. Opening the file after download is equivalent to executing the .cab file on the device and will cause the application to be installed.
NOTE
Regardless of how the .cab file reaches the device, the installation software on the device automatically deletes the .cab file once the installation is complete. To prevent this from happening, the .cab file can be marked as read-only.
To protect the .cab files, especially on a site accessible over the Internet, it is recommend that the virtual directory in which the download page resides be protected by standard HTTP encryption and authentication schemes. For example, the site could use basic authentication to authenticate the user and protect the virtual directory using SSL in order to encrypt both the credentials and the data. Alternatively, a VPN could be used as discussed in Chapter 9.
For scenarios where mobile applications need to be deployed dynamically and are location dependent (an application should be installed on the device when the device enters the WLAN available on a manufacturing floor, for example), third-party provisioning servers can be used. For example, the Appear Provisioning Server (APS) from Appear Network allows automatic delivery, single-click download, and automatic discard of location-specific applications targeted for health care, hospitality, transportation, and workforce coordination.
In many cases, the application needs to be deployed along with a SQLCE database or other software. As a result it can be both time-consuming and bulky to deploy such an application over the Internet or through a cradled connection. |
For those reasons, the application can alternatively be deployed on a memory storage card, such as a Compact Flash card; however, rather than requiring the user to execute the .cab file once the storage card is inserted into the device, Pocket PC devices include an Autorun feature.
With this feature, when a storage card is inserted into the device, the Pocket PC looks for an executable called Autorun.exe in a folder mapping to the processor type of the device. For example, if the processor type is ARM, it will then look for the file \Storage Card\ARM\Autorun.exe on the storage card. When found, the executable is copied to the \Windows folder and executed with the install parameter. Likewise, when the card is removed from the device, the same executable is launched with the uninstall parameter.
As a result, the Autorun executable needs to perform the following steps:
Determine which mode to run in. Because the application is passed either the install or uninstall command-line parameter, the Autorun application must first determine which of the two modes to run in. The rest of the steps discussed here assume the install mode.[9]
[9] In uninstall mode, the application will perhaps not be uninstalled, but the Autorun executable could check to see if the application is currently executing and if so display a warning message or shut down gracefully.
Verify that the application is not already installed on the device. This can be done by searching for the application's installation directory.
Find the storage card name. Because storage card names can differ on localized devices (they won't always be called "storage card") and devices can support more than one storage card, techniques such as using the Windows CE FindFirstFile API function can be used.[10]
[10] See the article "Pocket PC Programming Tips" by John Kennedy at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnroad/html/road03132002.asp
Find the processor-specific .cab file. This can be done by first detecting the processor on the device and then mapping that to the appropriate directory on the storage card. The Windows CE GetSystemInfo returns the processor architecture in its SYSTEM_INFO structure.
Execute the .cab file. This can be done using a Windows CE API, such as ShellExecuteEx.
Because the Compact Framework might not have been previously installed on the device, the Autorun.exe application is typically written using eMbedded Visual C. Further discussion is beyond the scope of this book.
As with deploying through a Web site, the .cab files can be placed on a network (LAN) share and accessed from the File Explorer on the device, either wirelessly using 802.11 or when cradled using ActiveSync 3.5 and higher.
And, as with deployment through the Web, the share can be protected, and users will be forced to enter valid credentials to gain access to the files. Once again, this option frees the user from having to cradle the device in order to install software.
Although they differ slightly from the previous deployment options covered in this chapter, Compact Framework applications, like those written with the desktop Framework, can be written to be auto-updating. By auto-updating we mean that the application checks file shares or Web sites either periodically or with each invocation for newer versions of its assemblies and dynamically downloads them. This technique is especially effective for applications that use private assemblies because the application can be partitioned into various functionalities, each housed in a separate assembly and, therefore, updated independently. |
The obvious benefit to creating an auto-updating application is that it takes the burden of keeping the application up to date off the user.
To understand how such an application would work, consider the simple Loader class shown in Listing 10-2.
Public Class Loader Protected _assemblies As New ArrayList Protected _net As String Protected _localPath As String Public Event Downloading(ByVal f As String) Public Sub New(ByVal networkPath As String, _ ByVal assemblies As ArrayList) ' Grab the defaults _net = networkPath _localPath = (Path.GetDirectoryName( _ [Assembly].GetExecutingAssembly.GetName.CodeBase) & _ "\").Substring(6) ' Load the FileInfo objects Dim f As String For Each f In assemblies If File.Exists(_localPath & f) Then Dim fi As New FileInfo(f) _assemblies.Add(fi) End If Next End Sub Public Sub CheckForNewAssemblies() Try Dim fi As FileInfo For Each fi In _assemblies Dim serverTime As DateTime = _ Me.GetServerTime(_net & fi.Name) If serverTime > fi.LastWriteTime Then ' Get the file RaiseEvent Downloading(fi.Name) Me.GetServerFile( _ _net & fi.Name, _localPath & fi.Name) End If Next Catch e As IOException ' Exception occurred Throw New Exception("Could not retrieve updates") End Try End Sub Protected Overridable Function GetServerTime( _ ByVal f As String) As DateTime ' This method could be rewritten or overridden ' to check using HttpWebRequest Return File.GetLastWriteTime(f) End Function Protected Overridable Sub GetServerFile( _ ByVal serverFile As String, ByVal localFile As String) ' This method could be rewritten or overridden ' to download using HttpWebRequest File.Copy(serverFile, localFile, True) End Sub End Class
As Listing 10-2 shows, the Loader class exposes a public constructor that accepts the network path of files on the server, along with an ArrayList that holds the names of private assemblies to update if new versions are available on the server. The constructor creates an internal ArrayList that holds a series of System.IO.FileInfo objects to represent each of the private assemblies to inspect.
When the CheckForNewAssemblies method is called, it enumerates the assembly list and determines each assembly's date and timestamp on the server, using the GetServerTime method. If the server has a newer file, the file is downloaded using the GetServerFile method, and it replaces the existing file.
You'll notice that both the GetServerTime and GetServerFile methods are marked as protected and overridable (virtual in C#). This allows a class derived from Loader to override these methods and to use a different means of determining the date and timestamp of the server file and of downloading the file. This could be used to create an LoaderHttp class that uses the HttpWebRequest class to download new assemblies placed on an intranet.
A bootstrap application or a method in an executable could then use the loader as follows:
Dim net As String = "\\myserver\updates\" Dim s As String = "mydll.dll" Dim a As New ArrayList a.Add(s) Dim l As New Loader(net, a) l.CheckForNewAssemblies()