How to: Use Automation in Trusted Applications
Microsoft Silverlight will reach end of support after October 2021. Learn more.
Trusted applications can integrate with some native functionality of the host operating system. Starting in Silverlight 4, this native integration includes the ability to access Automation APIs on Windows operating systems.
Automation is a technology that applications use to expose functionality to scripting tools and other applications. For example, you can use Automation to add Office features to your Silverlight-based applications.
An application or component that exposes Automation APIs is called an Automation server, while an application that accesses these APIs is called an Automation client. The following topic describes how to enable your Silverlight-based applications to work as Automation clients.
Note: |
---|
Only trusted applications running on Windows can access Automation APIs, and only those exposed by components or applications that are already installed. In Silverlight 4 and earlier, trusted applications must also run outside the browser. Starting in Silverlight 5, system administrators can enable trusted applications to run inside the browser. For more information, see Trusted Applications and AutomationFactory. Silverlight for Windows Phone and Silverlight 3 do not support trusted applications. |
To determine whether Automation is available
Use the AutomationFactory.IsAvailable property as demonstrated in the following code example. The IsAvailable property indicates whether the application is trusted and is running outside the browser on a Windows operating system.
Public Sub New() InitializeComponent() If AutomationFactory.IsAvailable Then ' Use Outlook on a background thread to keep the UI responsive. Dim worker As New BackgroundWorker() AddHandler worker.DoWork, Sub(sender, e) If InitializeOutlook() Then SearchEmail() Else : Dispatcher.BeginInvoke( Sub() MessageBox.Show("Outlook is not available.") End Sub) End If End Sub worker.RunWorkerAsync() Else : MessageBox.Show("Automation is not available.") End If End Sub
public MainPage() { InitializeComponent(); if (AutomationFactory.IsAvailable) { // Use Outlook on a background thread to keep the UI responsive. BackgroundWorker worker = new BackgroundWorker(); worker.DoWork += (sender, e) => { if (InitializeOutlook()) SearchEmail(); else Dispatcher.BeginInvoke(() => { MessageBox.Show("Outlook is not available."); }); }; worker.RunWorkerAsync(); } else { MessageBox.Show("Automation is not available."); } }
To create or retrieve an Automation object
Call the AutomationFactory.CreateObject or AutomationFactory.GetObject method with a programmatic identifier (progID) that indicates the Automation server to use. These methods throw a NotSupportedException if Automation is not available, and throw an Exception if the specified Automation server is not available.
In general, CreateObject will start a new instance of the Automation server and GetObject will retrieve the most recently started instance. However, the exact behavior of CreateObject and GetObject differs for different components, so be sure to check the component documentation and test your usage thoroughly.
The example for this topic searches the user's Outlook inbox. This requires Outlook to be open, so the following code first attempts to retrieve a running instance by calling GetObject. If an exception is thrown, the code attempts to open Outlook by calling CreateObject and displaying the user's inbox. If a second exception is thrown, then Outlook is probably not installed.
The reference to the Automation server is stored in a variable of type Object in Visual Basic and type dynamic in C#. This is necessary because the type information is not available until run time. However, the lack of type information also prevents the use of IntelliSense and compile-time debugging, making the component documentation even more important.
Private outlook As Object Private Function InitializeOutlook() As Boolean Try ' If GetObject throws an exception, then Outlook is ' either not running or is not available. outlook = AutomationFactory.GetObject("Outlook.Application") Return True Catch Try ' Start Outlook and display the Inbox, but minimize ' it to avoid hiding the Silverlight application. outlook = AutomationFactory.CreateObject("Outlook.Application") outlook.Session.GetDefaultFolder(6).Display() ' 6 = Inbox outlook.ActiveWindow.WindowState = 1 ' minimized Return True Catch ' Outlook is unavailable. Return False End Try End Try End Function
private dynamic outlook; private bool InitializeOutlook() { try { // If GetObject throws an exception, then Outlook is // either not running or is not available. outlook = AutomationFactory.GetObject("Outlook.Application"); return true; } catch (Exception) { try { // Start Outlook and display the Inbox, but minimize // it to avoid hiding the Silverlight application. outlook = AutomationFactory.CreateObject("Outlook.Application"); outlook.Session.GetDefaultFolder(6 /* Inbox */).Display(); outlook.ActiveWindow.WindowState = 1; // minimized return true; } catch (Exception) { // Outlook is unavailable. return false; } } }
To handle Automation events
Use one of the techniques demonstrated in the following code example. For more information, see the AutomationEvent class.
Note: Events with return values are not supported.
Private Sub SearchEmail() UpdateStatusMessage("Searching Inbox for 'Silverlight'...") ' The following code demonstrates three ways to handle Automation ' events. In Visual Basic, all three ways use the AutomationEvent class. searchEvent = AutomationFactory.GetEvent(outlook, "AdvancedSearchComplete") ' The first way is demonstrated by the Handles clause of the ' SearchEvent_EventRaised method, which requires the WithEvents modifier ' on the searchEvent variable declaration. ' The second way uses the AddHandler syntax with the EventRaised event, ' and does not require the WithEvents modifier. ' AddHandler searchEvent.EventRaised, AddressOf SearchEvent_EventRaised ' The third way uses the AutomationEvent.AddEventHandler method, and ' requires the use of a delegate with an API signature that matches the ' Automation event. ' searchEvent.AddEventHandler( ' New AdvancedSearchCompleteDelegate(AddressOf SearchComplete)) ' Begin the search. outlook.AdvancedSearch("Inbox", "urn:schemas:mailheader:subject ci_phrasematch 'Silverlight'", True, "SubjectSearch") End Sub Private WithEvents searchEvent As AutomationEvent Sub SearchEvent_EventRaised(ByVal sender As Object, ByVal e As AutomationEventArgs) Handles searchEvent.EventRaised SearchComplete(e.Arguments(0)) End Sub ' Required only with the second two ways of handling Automation events. ' Private Delegate Sub AdvancedSearchCompleteDelegate(ByRef search As Object) ' Note: Visual Basic does not support the use of custom delegates for ' events with optional parameters. Private Sub SearchComplete(ByRef search As Object) Dim searchResults As New List(Of String) For Each result As Object In search.Results searchResults.Add(result.Subject) Next SetResultsList(searchResults) End Sub
private void SearchEmail() { UpdateStatusMessage("Searching Inbox for 'Silverlight'..."); // The following code demonstrates three ways to handle Automation // events. The first two ways use the AutomationEvent class. // The last two ways require the use of a delegate with // an API signature that matches the Automation event. AutomationEvent searchEvent = AutomationFactory .GetEvent(outlook, "AdvancedSearchComplete"); // The first way: searchEvent.EventRaised += (sender, e) => { SearchComplete(e.Arguments[0]); }; // The second way: // searchEvent.AddEventHandler( // new AdvancedSearchCompleteDelegate(SearchComplete)); // The third way: // outlook.AdvancedSearchComplete += // new AdvancedSearchCompleteDelegate(SearchComplete); // Begin the search. outlook.AdvancedSearch("Inbox", "urn:schemas:mailheader:subject ci_phrasematch 'Silverlight'", true, "SubjectSearch"); } // Required only with the second two ways of handling Automation events. private delegate void AdvancedSearchCompleteDelegate(dynamic search); // To use custom delegates for events with optional parameters, you // must specify default values in the delegate signature as shown here: // private delegate void MyEventHandlerDelegate(int i, float f=77); private void SearchComplete(dynamic search) { List<String> searchResults = new List<String>(); foreach (dynamic result in search.Results) { searchResults.Add(result.Subject); } SetResultsList(searchResults); }
Example
The following code provides the helper methods and user-interface XAML used by the preceding code. To run the code in this topic, create a new Silverlight application project and then add all the code to the MainPage class.
<Grid x:Name="LayoutRoot" Background="White">
<TextBlock x:Name="message"/>
<ListBox x:Name="items" Visibility="Collapsed"/>
</Grid>
Private Sub UpdateStatusMessage(ByVal text As String)
UpdateUserInterface(Sub() message.Text = text)
End Sub
Private Sub SetResultsList(ByVal results As IEnumerable(Of String))
UpdateUserInterface(
Sub()
message.Visibility = System.Windows.Visibility.Collapsed
items.Visibility = System.Windows.Visibility.Visible
items.ItemsSource = results
End Sub)
End Sub
Private Sub UpdateUserInterface(ByVal performUpdate As Action)
' Marshal to the UI thread, if necessary.
If Dispatcher.CheckAccess Then
performUpdate()
Else
Dispatcher.BeginInvoke(performUpdate)
End If
End Sub
private void UpdateStatusMessage(string text)
{
// Update the message on the UI thread.
UpdateUserInterface(() => { message.Text = text; });
}
private void SetResultsList(IEnumerable<String> results)
{
// Hide the message and populate the results list on the UI thread.
UpdateUserInterface(() =>
{
message.Visibility = System.Windows.Visibility.Collapsed;
items.Visibility = System.Windows.Visibility.Visible;
items.ItemsSource = results;
});
}
private void UpdateUserInterface(Action performUpdate)
{
// Marshall to the UI thread, if necessary.
if (Dispatcher.CheckAccess()) performUpdate();
else Dispatcher.BeginInvoke(performUpdate);
}
Compiling the Code
To use the C# dynamic keyword, your project must include a reference to Microsoft.CSharp.dll.
See Also