Extending the Updater Application Block
| Retired Content |
|---|
This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. |
Extending the Updater Application Block
Updater Application Block - Version 2.0
Microsoft CorporationMarch 2005
Summary: Updater Application Block is designed to be flexible enough to let you customize the application update solution. This chapter describes custom downloaders and custom activation processors.
You can use the Updater Application Block as-is to implement an automatic application update solution. However, it is designed to be flexible enough to let you customize the application update solution. Specifically, you can create the following kinds of custom components for the application block to suit the particular needs of a solution:
- Custom downloaders. A downloader is a .NET class that derives from the IDownloader interface defined in the application block. It encapsulates the logic that is required to copy files from a central server to a client computer.
The application block includes the BITSDownloader implementation, which uses the Windows Background Intelligent Transfer Service (BITS) to copy files. This will meet the needs of most application update scenarios. However, sometimes you might want to develop an alternative downloader. For example, you might want to create a custom downloader to copy files from a File Transfer Protocol (FTP) server or a Universal Naming Convention (UNC) file share.
- Custom activation processors. An activation processor is a .NET class that derives from the IActivationProcessor interface defined in the application block. It encapsulates the logic that you need to perform actions on downloaded files.
The application block includes a suite of implementations that provide the functionality such as copying and deleting files and folders and running Windows installer packages. For more information about the included implementations, see IActivationProcessor Implementations. These implementations will meet the needs of most post-download processing scenarios. However, sometimes you might want to develop an alternative activation processor. For example, you might want to create a custom activation processor to write data to the Windows registry.
The Updater Application Block is designed to support the scenarios described in the Scenarios and Design Goals topic. These include the most frequently required functionality for self-updating applications. However, the application block download includes the source code for all the subsystems within the application block. Therefore, you can customize the functionality of the application block itself if you need to.
The following topics provide detailed information about extending and modifying the Updater Application Block:
Adding an Activation Processor
Adding a Downloader Provider
Downloaders are used to copy application files from the server to the client computer. To create a custom downloader, you must create a class that derives from the IDownloader interface defined in the Updater Application Block and configure your application to use the custom downloader class.
The following topics describe how to create a custom downloader:
Configuring a Custom Downloader
Creating a Custom Downloader
The Updater Application Block provides the IDownloader interface you can derive custom downloader classes from. You should consider creating a custom downloader class when the Background Intelligent Transfer Service (BITS) downloader provided with the application block does not meet your needs or is not suited for your particular environment. For example, you should consider creating a custom downloader in the following situations:
- You have to download files from a non-HTTP location (such as a UNC network share, a mapped network drive, or an FTP server).
- You want to use the Updater Application Block on an operating system that does not support BITS (such as Windows 98).
There are two classes that you must use to create a custom downloader:
- IDownloader. You must create a class that implements this interface, adding code to initialize the class and to download specified files to the client computer.
You can use the Initialize method to store configuration data passed in the ConfigurationView argument into private members to use during the download process.
You can implement the Download and BeginDownload methods to perform the synchronous or asynchronous downloading of files respectively. You can also implement the CancelDownload method to cancel a download.
- DownloadProviderData. You must create a class that extends this class to store downloader configuration information from the application configuration file. The IDownloader implementation can then access this information to perform its work.
For example, if access to your server location requires user credentials, you can configure those credentials in the configuration file, store them in class members during theInitialize method, and use that information from the IDownloader methods.
If your custom downloader does not require any configuration, you must still implement the TypeName property of this class to return the fully qualified name of your downloader type.
Note IDownloader implementations are based on the provider model from the Enterprise Library. The IConfigurationProvider interface is supplied by the Enterprise Library for implementing this model. For more information about IConfigurationProvider, see the Enterprise Library documentation.
To create a custom downloader class
- Add references to the following assembly:
- Microsoft.ApplicationBlocks.Updater.dll
- Create a new class.
- Import the Microsoft.ApplicationBlocks.Updater, Microsoft.ApplicationBlocks.Updater.Configuration and Microsoft.Practices.EnterpriseLibrary.Configuration namespaces into the class.
- Derive the class from the IDownloader interface in the Microsoft.ApplicationBlocks.Updater namespace.
- Implement the following methods defined in the IDownloader interface:
- Download. Add code to this method to perform a synchronous download of updates, accessing the task information from the task argument passed to the method. Use the maxWaitTime argument to implement a timeout if the download exceeds the configured maximum time limit.
- BeginDownload. Add code to this method to perform an asynchronous download of updates, accessing the task information from the task argument passed to the method.
- CancelDownload. Add code to this method to enable the cancellation of an asynchronous download.
- Implement the following members defined in the IConfigurationProvider interface:
- ConfigurationName. Add code to return the string "downloader." The application block uses this to identify the name of the configuration section for this class.
- Initialize. Add code to this method to initialize class members with any downloader configuration information passed to the method in the ConfigurationView argument.
- Add handlers for the following events defined in the IDownloader interface and raise the event up to the calling code:
- DownloadTaskStartedEventHandler
- DownloadTaskProgressEventHandler
- DownloadTaskErrorEventHandler
- DownloadTaskCompletedEventHandler
To create a custom DownloadProviderData class
- Create a new class that inherits from DownloadProviderData.
- Import the System.Xml.Serialization namespace into the class.
- Modify the class to serialize the information in the downloader element in the ApplicationUpdaterSettings.ConfigurationNamespace namespace.
- Override the TypeName method of this class to return the fully qualified name of your downloader type.
- Add public properties and private member variables to store and access any configuration settings your downloader requires.
Code Sample
The following example shows a custom downloader that can be used to copy files from a UNC network share.
[C#]
using System;
using System.IO;
using System.Threading;
using System.Xml.Serialization;
using Microsoft.ApplicationBlocks.Updater;
using Microsoft.ApplicationBlocks.Updater.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Configuration;
namespace MyApp.Downloaders
{
// This is the downloader class
public class UNCDownloader : IDownloader
{
public UNCDownloader()
{
}
private UpdaterConfigurationView updaterConfigurationView;
bool isCompleted = false;
bool isSuccessful = false;
Thread asyncDownloadThread;
// Method to perform a synchronous download
public void Download(UpdaterTask task, TimeSpan maxWaitTime)
{
try
{
OnDownloadStarted(new TaskEventArgs(task));
AsyncDownloader aDownload = new AsyncDownloader(task,
new DownloadCompleted(OnDownloadCompleted));
Thread downloadThread = new Thread(new
ThreadStart(aDownload.DownloadFiles));
downloadThread.Start();
double endTime = Environment.TickCount + maxWaitTime.TotalMilliseconds;
do
{
if (isCompleted == true)
{
break;
}
}
while(Environment.TickCount < endTime);
// If the file is still not ready, throw a timeout error
if(isSuccessful == false)
{
downloadThread.Abort();
throw new Exception("Time out error");
}
}
catch (Exception ex)
{
OnDownloadError(new DownloadTaskErrorEventArgs(task, ex));
}
}
public void BeginDownload(UpdaterTask task)
{
try
{
OnDownloadStarted(new TaskEventArgs(task));
AsyncDownloader aDownload = new AsyncDownloader(task, new
DownloadCompleted(OnDownloadCompleted));
asyncDownloadThread = new Thread(new
ThreadStart(aDownload.DownloadFiles));
asyncDownloadThread.Start();
}
catch (Exception ex)
{
OnDownloadError(new DownloadTaskErrorEventArgs(task, ex));
}
}
public bool CancelDownload(UpdaterTask task)
{
asyncDownloadThread.Abort();
return true;
}
public event DownloadTaskStartedEventHandler DownloadStarted;
public event DownloadTaskProgressEventHandler DownloadProgress;
public event DownloadTaskErrorEventHandler DownloadError;
public event DownloadTaskCompletedEventHandler DownloadCompleted;
private void OnDownloadStarted( TaskEventArgs e )
{
if ( DownloadStarted != null )
{
DownloadStarted( this, e );
}
}
private void OnDownloadProgress( DownloadTaskProgressEventArgs e )
{
if ( DownloadProgress != null )
{
DownloadProgress( this, e );
}
}
private void OnDownloadError( DownloadTaskErrorEventArgs e )
{
if ( DownloadError != null )
{
DownloadError( this, e );
isSuccessful = false;
}
}
private void OnDownloadCompleted(TaskEventArgs e)
{
if (DownloadCompleted != null)
{
DownloadCompleted(this, e);
isCompleted = true;
isSuccessful = true;
}
}
public string ConfigurationName
{
get
{
return "downloader";
}
set
{
}
}
public void Initialize(ConfigurationView configurationView)
{
updaterConfigurationView = (UpdaterConfigurationView)configurationView;
// No downloader specific configuration required for UNCDownloader, so the
// updaterConfigurationView object is not used.
// If it is required, use the
// updaterConfigurationView.GetDownloadProviderData method.
// to access the data.
}
}
[XmlRoot("downloader",
Namespace=ApplicationUpdaterSettings.ConfigurationNamespace )]
public sealed class UNCDownloaderProviderData : DownloadProviderData
{
public UNCDownloaderProviderData()
{
}
public override string TypeName
{
get { return typeof( UNCDownloader ).AssemblyQualifiedName; }
set {}
}
}
// Delegate for "download completed" event
internal delegate void DownloadCompleted(TaskEventArgs e);
class AsyncDownloader
{
internal AsyncDownloader(UpdaterTask task, DownloadCompleted callbackFunction)
{
_task = task;
_callbackFunction = callbackFunction;
}
private UpdaterTask _task;
private DownloadCompleted _callbackFunction;
public event DownloadTaskProgressEventHandler DownloadProgress;
private void OnDownloadProgress( DownloadTaskProgressEventArgs e )
{
if ( DownloadProgress != null )
{
DownloadProgress( this, e );
}
}
internal void DownloadFiles()
{
for(int i = 0; i<_task.Manifest.Files.Count; i++)
{
string srcFile = _task.Manifest.Files.Base +
_task.Manifest.Files[i].Source;
string destFile = Path.Combine(_task.DownloadFilesBase,
_task.Manifest.Files[i].Source);
if ( !Directory.Exists( Path.GetDirectoryName( destFile ) ) )
{
Directory.CreateDirectory( Path.GetDirectoryName( destFile ) );
}
FileInfo src = new FileInfo(srcFile);
src.CopyTo(destFile, true);
Thread.Sleep(TimeSpan.FromMinutes(1));
OnDownloadProgress(new DownloadTaskProgressEventArgs(
0,0,_task.Manifest.Files.Count,i+1,_task));
}
_callbackFunction(new TaskEventArgs(_task));
}
}
}
[Visual Basic]
Imports System
Imports System.IO
Imports System.Threading
Imports System.Xml.Serialization
Imports Microsoft.ApplicationBlocks.Updater
Imports Microsoft.ApplicationBlocks.Updater.Configuration
Imports Microsoft.Practices.EnterpriseLibrary.Configuation
Namespace Downloaders
Public Class UNCDownloader
Implements Microsoft.ApplicationBlocks.Updater.IDownloader
Dim UpdaterConfigView as UpdaterConfigurationView
Dim isCompleted As Boolean = False
Dim isSuccessful As Boolean = False
Dim asyncDownloadThread As Thread
Public Sub BeginDownload(ByVal task As Microsoft.ApplicationBlocks.Updater.UpdaterTask) Implements Microsoft.ApplicationBlocks.Updater.IDownloader.BeginDownload
Try
OnDownloadStarted(New TaskEventArgs(task))
Dim aDownload As New AsyncDownloader(task, New DownloadCompleted(AddressOf OnDownloadCompleted))
asyncDownloadThread = New Thread(New ThreadStart(AddressOf aDownload.DownloadFiles))
asyncDownloadThread.Start()
Catch ex As Exception
OnDownloadError(New DownloadTaskErrorEventArgs(task, ex))
End Try
End Sub
Public Function CancelDownload(ByVal task As Microsoft.ApplicationBlocks.Updater.UpdaterTask) As Boolean Implements Microsoft.ApplicationBlocks.Updater.IDownloader.CancelDownload
asyncDownloadThread.Abort()
Return True
End Function
Public Sub Download(ByVal task As Microsoft.ApplicationBlocks.Updater.UpdaterTask, ByVal maxWaitTime As System.TimeSpan) Implements Microsoft.ApplicationBlocks.Updater.IDownloader.Download
Try
OnDownloadStarted(New TaskEventArgs(task))
Dim aDownload As New AsyncDownloader(task, New DownloadCompleted(AddressOf OnDownloadCompleted))
Dim downloadThread As New Thread(New ThreadStart(AddressOf aDownload.DownloadFiles))
downloadThread.Start()
Dim endTime As Double = Environment.TickCount + maxWaitTime.TotalMilliseconds
Do
If isCompleted = True Then
Exit Do
End If
Loop While Environment.TickCount < endTime
' if the file is still not ready, throw a timeout error
If isSuccessful = False Then
downloadThread.Abort()
Throw New Exception("Time out error")
End If
Catch ex As Exception
OnDownloadError(New DownloadTaskErrorEventArgs(task, ex))
End Try
End Sub
Public Event DownloadCompleted(ByVal sender As Object, ByVal e As Microsoft.ApplicationBlocks.Updater.TaskEventArgs) Implements Microsoft.ApplicationBlocks.Updater.IDownloader.DownloadCompleted
Public Event DownloadError(ByVal sender As Object, ByVal e As Microsoft.ApplicationBlocks.Updater.DownloadTaskErrorEventArgs) Implements Microsoft.ApplicationBlocks.Updater.IDownloader.DownloadError
Public Event DownloadProgress(ByVal sender As Object, ByVal e As Microsoft.ApplicationBlocks.Updater.DownloadTaskProgressEventArgs) Implements Microsoft.ApplicationBlocks.Updater.IDownloader.DownloadProgress
Public Event DownloadStarted(ByVal sender As Object, ByVal e As Microsoft.ApplicationBlocks.Updater.TaskEventArgs) Implements Microsoft.ApplicationBlocks.Updater.IDownloader.DownloadStarted
Private Sub OnDownloadStarted(ByVal e As TaskEventArgs)
RaiseEvent DownloadStarted(Me, e)
End Sub
Private Sub OnDownloadProgress(ByVal e As DownloadTaskProgressEventArgs)
RaiseEvent DownloadProgress(Me, e)
End Sub
Private Sub OnDownloadError(ByVal e As DownloadTaskErrorEventArgs)
RaiseEvent DownloadError(Me, e)
End Sub
Private Sub OnDownloadCompleted(ByVal e As TaskEventArgs)
RaiseEvent DownloadCompleted(Me, e)
isCompleted = True
isSuccessful = True
End Sub
Public Property ConfigurationName() As String Implements Microsoft.Practices.EnterpriseLibrary.Configuration.IConfigurationProvider.ConfigurationName
Get
End Get
Set(ByVal Value As String)
End Set
End Property
Public Sub Initialize(ByVal configurationView As Microsoft.Practices.EnterpriseLibrary.Configuration.ConfigurationView) Implements Microsoft.Practices.EnterpriseLibrary.Configuration.IConfigurationProvider.Initialize
updaterConfigView = CType(configurationView, UpdaterConfigurationView)
' No downloader specific configuration required for UNCDownloader, so the
' updaterConfigView object is not used. If it is required, use the
' updaterConfigView.GetDownloadProviderData method.
End Sub
End Class
<XmlRoot("downloader", Namespace:=ApplicationUpdaterSettings.ConfigurationNamespace)> _
Public NotInheritable Class UNCDownloaderProviderData
Inherits Microsoft.ApplicationBlocks.Updater.Configuration.DownloadProviderData
Public Overrides Property TypeName() As String
Get
Dim objType As Type = GetType(UNCDownloader)
Return objType.AssemblyQualifiedName
End Get
Set(ByVal Value As String)
End Set
End Property
End Class
' Delegate for "download complete" event
Friend Delegate Sub DownloadCompleted(ByVal e As TaskEventArgs)
Class AsyncDownloader
Friend Sub New(ByVal task As UpdaterTask, ByVal callbackFunction As DownloadCompleted)
_task = task
_callbackFunction = callbackFunction
End Sub
Private _task As UpdaterTask
Private _callbackFunction As DownloadCompleted
Public Event DownloadProgress As DownloadTaskProgressEventHandler
Private Sub OnDownloadProgress(ByVal e As DownloadTaskProgressEventArgs)
RaiseEvent DownloadProgress(Me, e)
End Sub
Friend Sub DownloadFiles()
Dim i As Integer
For i = 0 To _task.Manifest.Files.Count - 1
Dim srcFile As String = _task.Manifest.Files.Base + _task.Manifest.Files(i).Source
Dim destFile As String = Path.Combine(_task.DownloadFilesBase, _task.Manifest.Files(i).Source)
If Not Directory.Exists(Path.GetDirectoryName(destFile)) Then
Directory.CreateDirectory(Path.GetDirectoryName(destFile))
End If
Dim src As New FileInfo(srcFile)
src.CopyTo(destFile, True)
Thread.Sleep(TimeSpan.FromMinutes(1))
OnDownloadProgress(New DownloadTaskProgressEventArgs(0, 0, _task.Manifest.Files.Count, i + 1, _task))
Next i
_callbackFunction(New TaskEventArgs(_task))
End Sub
End Class
End Namespace
The code shows a downloader class named UNCDownloader that uses an internal class that is named AsyncDownloader to copy files. The UNCDownloader class provides methods for synchronous and asynchronous downloading of files.
More Information
Note the following about custom downloader classes:
- You must reference the Microsoft.ApplicationBlocks.Updater.dll and Microsoft.Practices.EnterpriseLibrary.Configuration.dll assemblies.
- Even if your downloader does not require any configuration information, you must still create the DownloadProviderData class and override the TypeName method.
- The DownloadManager calls the Download method synchronously to copy updates for an application from the server to the client. You must use the maxWaitTime parameter to implement a timeout mechanism for this method.
- The BeginDownload method is called to initiate an asynchronous download of application files. In this method, you should start an asynchronous process to download the files.
Configuring a Custom Downloader
You can configure a client application to use a custom downloader by modifying elements in the application configuration and the manifest.
Application Configuration
The application configuration contains information that identifies the downloader and data provider for the client application.
Downloader Configuration
You must specify the downloader that you want to use in a downloader element of the application configuration file, Updaterconfiguration.config. You must specify the download provider data type and the name of the downloader as attributes of this element and any additional configuration settings that the downloader required as child elements.
The following code shows an appropriate downloaders element in the Updaterconfiguration.config file for the custom downloader described Creating a Custom Downloader.
<downloaders> <downloader xsi:type="UNCDownloaderProviderData" name="UNCDownloader"> </downloader> </downloaders>
The information in this element is used to initialize the downloader. Therefore, you can add any custom configuration information that your downloader requires as child elements of this element. Those settings will then be available during the downloader initialization process.
Downloader Provider Data Configuration
You must also specify the downloader provider data type in the application configuration file, App.config. You must specify the type name of the class that inherits the DownloaderProviderData class.
The following code shows an appropriate includeTypes element in the UpdaterConfiguration section of the App.config file for the custom downloader described Creating a Custom Downloader.
<includeTypes> <includeType name="UNCDownloader" type="MyApp.Downloaders.UNCDownloaderProviderData, MyApp" /> </includeTypes>
Manifest Configuration
The application manifest includes information that defines which downloader to use and where to access the update files.
Downloader Configuration
You must specify the downloader name in the manifest.
The following code shows an appropriate downloader element in the manifest file for the custom downloader described in Creating a Custom Downloader.
<downloader name="UNCDownloader"/>
Base Configuration
You must also make sure that the base attribute of the files element correctly identifies the base location of the files in the correct format for the downloader. For example, if you are writing a UNC downloader, the base attribute should be a UNC path.
The following code shows an appropriate files element for the custom UNC downloader described in Creating a Custom Downloader. Because this downloader uses a UNC share, the base attribute must be the UNC path to that location.
<files base="\\server1\MyApp">
<file source="Manifest.xml" />
<file source="MyTextFile.txt" />
</files>
Adding an Activation Processor
Activation processors perform post-download tasks, such as writing data to the registry, creating message queues, or other configuration functions. To create an activation processor, you must create a class that derives from the IActivationProcessor interface defined in the Updater Application Block. You must also specify your activation processor in the manifest file so that the application updater will load and run it.
The following topics describe how to create a custom activation processor:
Creating a Custom Activation Processor
Configuring a Custom Activation Processor
Creating a Custom Activation Processor
The Updater Application Block provides the IActivationProcessor interface you can derive custom activation processors from. You should consider creating a custom activation processor class if you require post-download functionality that is not included in the application block.
To create an activation processor class
- Add references to the following assemblies:
- Microsoft.ApplicationBlocks.Updater.dll
- Microsoft.Practices.EnterpriseLibrary.Configuration.dll
- Create a new class.
- Import the Microsoft.ApplicationBlocks.Updater namespace into the class.
- Derive the class from the IActivationProcessor interface in the Microsoft.ApplicationBlocks.Updater namespace.
- Implement the following methods defined in the IActivationProcessor interface:
- Init. Add any initialization code to this method, accessing configuration information from the ActivationProcessorProviderData argument passed to the method.
- PrepareExecution. Add code to this method to verify that any prerequisites for the execution are met. For example, if a folder is required to exist for the execution to succeed, add code to this method to check for the folder and to create it if necessary. If the prerequisites are not met, you should raise an exception to the calling code.
- Execute. Add code to this method to run the activation process.
- OnError. Add code to this method that should run if a later processor in the chain fails.
Code Sample
The following example shows a custom activation processor that writes data to the Windows registry.
[C#]
using System;
using System.Xml;
using Microsoft.Win32;
using Microsoft.ApplicationBlocks.Updater;
namespace MyApp
{
public class RegistryProcessor : IActivationProcessor
{
private UpdaterTask task;
string key;
string newKey;
string keyName;
string keyValue;
public RegistryProcessor()
{
}
public void Execute()
{
RegistryKey regKey = Registry.LocalMachine.OpenSubKey(key,true);
RegistryKey regNewKey = regKey.CreateSubKey(newKey);
regNewKey.SetValue(keyName,keyValue);
regKey.Close();
}
public void Init(ActivationProcessorProviderData data, UpdaterTask task)
{
this.task = task;
foreach( XmlAttribute attr in data.AnyAttributes )
{
if ( attr.Name == "key" )
{
key = attr.Value;
}
if ( attr.Name == "newKey" )
{
newKey = attr.Value;
}
if ( attr.Name == "keyName" )
{
keyName = attr.Value;
}
if ( attr.Name == "keyValue" )
{
keyValue = attr.Value;
}
}
if ( key == String.Empty )
{
throw new ArgumentException( "Expecting the 'key' value." );
}
if ( newKey == String.Empty )
{
throw new ArgumentException( "Expecting the 'newKey' value." );
}
if ( keyName == String.Empty )
{
throw new ArgumentException( "Expecting the 'keyName' value." );
}
if ( keyValue == String.Empty )
{
throw new ArgumentException( "Expecting the 'keyValue' value." );
}
}
public void OnError()
{
RegistryKey regKey = Registry.LocalMachine.OpenSubKey( key, true );
regKey.DeleteSubKey( newKey, false );
regKey.Close();
}
public void PrepareExecution()
{
}
}
}
[Visual Basic]
Imports System
Imports System.Xml
Imports Microsoft.Win32
Imports Microsoft.ApplicationBlocks.Updater
Public Class RegistryProcessor
Implements IActivationProcessor
Dim task As UpdaterTask
Dim key As String
Dim newKey As String
Dim keyName As String
Dim keyValue As String
Public Sub Execute() Implements Microsoft.ApplicationBlocks.Updater.IActivationProcessor.Execute
Dim regKey As RegistryKey = Registry.LocalMachine.OpenSubKey(key, True)
Dim regNewKey As RegistryKey = regKey.CreateSubKey(newKey)
regNewKey.SetValue(keyName, keyValue)
regKey.Close()
End Sub
Public Sub Init(ByVal data As Microsoft.ApplicationBlocks.Updater.ActivationProcessorProviderData, ByVal task As Microsoft.ApplicationBlocks.Updater.UpdaterTask) Implements Microsoft.ApplicationBlocks.Updater.IActivationProcessor.Init
Me.task = task
Dim attr As XmlAttribute
For Each attr In data.AnyAttributes
If attr.Name = "key" Then
key = attr.Value
End If
If attr.Name = "newKey" Then
newKey = attr.Value
End If
If attr.Name = "keyName" Then
keyName = attr.Value
End If
If attr.Name = "keyValue" Then
keyValue = attr.Value
End If
Next
If key = String.Empty Then
Throw New ArgumentException("Expecting the 'key' value.")
End If
If newKey = String.Empty Then
Throw New ArgumentException("Expecting the 'newKey' value.")
End If
If keyName = String.Empty Then
Throw New ArgumentException("Expecting the 'keyName' value.")
End If
If keyValue = String.Empty Then
Throw New ArgumentException("Expecting the 'keyValue' value.")
End If
End Sub
Public Sub OnError() Implements Microsoft.ApplicationBlocks.Updater.IActivationProcessor.OnError
Dim regKey As RegistryKey = Registry.LocalMachine.OpenSubKey(key, True)
regKey.DeleteSubKey(newKey, False)
regKey.Close()
End Sub
Public Sub PrepareExecution() Implements Microsoft.ApplicationBlocks.Updater.IActivationProcessor.PrepareExecution
End Sub
End Class
More Information
Note the following about post-processor classes:
- You must reference the Microsoft.ApplicationBlocks.Updater.dll and Microsoft.Practices.EnterpriseLibrary.Configuration.dll assemblies.
- You should use the PrepareExecute method to confirm that any requirements for your activation processor are met. For example, if your activation processor relies on a specific folder being present, you can check for this folder and if necessary, create it in the PrepareExecute method.
If processing has to be paused at this point, you can raise the ActivationPausedException exception to the ActivationProcessing system. This will pause processing for later resumption. This exception will raise the ActivationInitializationAborted event for the client application to handle.
- The Execute method accepts no parameters. If your activation processor requires initialization values, you should design it so that it stores configuration information during the Init method.
Configuring a Custom Activation Processor
You can configure a client application to use a custom activation processor by modifying the activation element in the manifest file.
Manifest Configuration
The activation element contains one or more task elements that define the activation processors that should be executed. You must create one task element for each task that should be processed. For example, if two Windows Installer packages should be executed, you must create one task element for each package defining the configuration for that package. Activation processors are executed in the order that they are defined in the manifest file.
You must specify the type and the name of the activation processor. If your activation processor requires additional configuration information, this can be included as an attribute or child element of the task element. For example, a folder path may be included as a folderPath attribute.
The following code shows an appropriate activation element for the custom activation processor described in Creating a Custom Activation Processor.
<activation>
<tasks>
<task name="RegistryProcessor" type="MyApp.RegistryProcessor, MyApp"
key="Software" newKey="MyApp" keyName="MyValue" keyValue="1"/>
</tasks>
</activation>
| Retired Content |
|---|
This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. |
