(Print this page)

The Vista Bridge
Published date: Wednesday, December 10, 2008
On: Moer and Éric Moreau's web site

Is your development computer running on Vista? I really hope you answer yes no matter what you may hear from people around you because Vista is really a great OS. Are your users running on Vista? If you work for large companies chances are that you will answer no, companies normally don’t upgrade every time a new version hits the market. If you answer yes to both questions, you definitely need to be introduced to the Vista Bridge.

BTW, I was told that all this code will also runs perfectly on the upcoming Windows 7.

What is the Vista Bridge?

I was introduced to the Vista Bridge late last summer when I was asked to do a presentation on that topic for the Microsoft TechDays event in Montréal.

Apart from being a real bridge in Portland, Oregon (see Wikipedia) it is a library that you can use from VB.Net and/or C# that gives you access to features provided by the Vista OS that are not directly available from .Net (for all kinds of good reasons – good or bad).

I consider this component much like the VB Power Packs I have already covered in March 2008 in the way that it is a temporary stage before being part of the official Visual Studio package. Instead of waiting for the next big release or service pack, you can start using this component a lot faster. For the team that develops it, it is also a good way of getting feedbacks.

The whole purpose of the VistaBridge is to offer features that are built into the Windows Vista platform but which are not available directly through the .Net Framework. It is provided much as a “sample” library which means that it doesn’t get the same level of support.

How can I get it?

The answer is easy but wait before navigating go to Microsoft downloads or MSDN because you won’t find it there.

Instead you will find it on MSDN Code Gallery which is yet another official Microsoft from where you can download sample applications and code snippets. The good news is that you don’t get only the component itself, you also get all the source code.

The other good news is that because it is distributed aside the official roadmap, chances are that we will get versions (or fixes) much faster.

The first time that component was made available to developers, it was through the Windows Vista SDK. This component was so deeply hidden into a ZIP file that most developers never found it. If you installed the SDK, have a look in C:\Program Files\Microsoft SDKs\Windows\v1.0\samples\CrossTechnologySamples.zip – you will find VistaBridge.zip in there. That was version 1.0. Then the same version (1.0) was available on MSDN.

After many months of waiting (due to the legal side of distributing source code and not to the content of the component), a new version has finally been made available in November of 2008. We now have access to the version 1.3.1 of the Vista Bridge and this article will target this specific version.

What’s in it?

There are a couple of interesting features that you can hardly get otherwise. In this article, I will explore only 3 of those features here:

  • The Command Link
  • The Task Dialog
  • The Application Restart and Recovery

What’s in the downloadable demo?

At the root of the ZIP file, you will find the 2 VistaBridge DLLs (VistaBridgeLibrary.DLL and VistaBridgeControls.DLL). Those DLLs were compiled with the version 1.3.1 as found on MSDN Code Gallery.

You will also find 2 sub-folders, each containing a different solution. Those solutions demonstrate the 3 features covered here.

I strongly encourage you to download the version that is on MSDN Code Gallery as it contains some more demos (and some are even WPF demos).

Detecting Windows version

You should always check which version of Windows you are running before trying to use one of the features of this article. The best way to do it is to query the My.Computer.Info.OSVersion and/or the My.Computer.Info.OSFullName properties (see the bottom of the form shown in figure 1) and branch to a different form if required.

The only feature presented in this article that can scale down is the Command Link. Instead of showing a nicely formatted button, it will display a big ugly one. All other topics of this article will trigger and exception.

The Command Link

The first feature I want to explore, is call the CommandLink. It is a control. That means that you need to add the VistaBridgeControls DLL to your toolbox and then you will be able to drag a CommandlinWinForms control to your Windows Forms. The very same control also exists for WPF application (in the same DLL).

Once you created an instance on a form, you will be able to find that you already know how to use this control because it is nothing else then a button! But this new button has 3 characteristics:

  • It is big.
  • It has 2 sections of text.
  • It has a nice effect when you hover the mouse pointer over it.

About the 2 sections of text, the first line can be considered has the title of the button and is set using the Text property. The second section has a smaller font and is set using the NoteText property. This NoteText section will only have effect if the FlatStyle property is set to System. Otherwise it displays a big regular button.

You will also notice that there is an icon right next to the button’s title. This icon is either a green arrow icon or a shield icon. It can be set using the Boolean ShieldIcon property (which is set to False by default). You should set this property to true (if you want to be a good Windows Vista citizen) when you know that the action that will be performed by clicking this button will require elevated privileges.

Figure 1: The CommandLInk button in action.

To react to this button, you have to use the click event just like for a regular button.

If you try to run an application displaying one of those controls on an older version of Windows, you will get a big ugly button (no icon and no additional text zone) but the application will work just as well.

I admit, this control is not very exciting but I promise that the best is yet to come.

The Task Dialog

Are all the questions an application has to ask a user can always be answered by Yes/No, OK/Cancel? The exact purpose of this TaskDialog class is to be able to offer users a good dialog to which he/she doesn’t have to say Yes or No. It is re-using the Command Links we just covered but it is much more then this as we will see here. The figure 2 gives you an example of one dialog which is much more complete then the plain old MessageBox.

Figure 2: The Task Dialog

If you have downloaded the code of this article, this dialog is still in the “UI Demo” solution but don’t look for a form that contains this dialog because it is all done by code and it is not as bad as it first appear.

So let’s break the code required to build this dialog. The first thing you need to do is to declare an instance of this dialog. I first thought that the constructor would have exposed many overloads to initialize some of the dialog properties but you cannot pass any values to the constructor. This is the dialog declaration:

Dim td As New TaskDialog
Then we can start setting the first properties. I will try to do it in a top-to-bottom way (as seen in figure 2).

The first thing we see at the top of this form is the icon that is set using the MainIcon property which exposes an enumeration of 4 values (Error, Information, Shield, and Warning). The same icon is displayed in the title bar of the dialog.

Then comes the title of the dialog that you can set using the Caption property.

At the top-right of the dialog, you currently see a red-X letting you close this dialog. You can hide it and force the user to select one of the options by setting the Cancelable property to False.

The first 2 blocks of text inside the dialogs are set using the Instruction and the Content properties.

So far, the required code is:

td.MainIcon = TaskDialogStandardIcon.Information
td.Cancelable = True
td.Caption = "This is a sample Task Dialog"
td.Instruction = "Follow these instructions to complete the task"
td.Content = "This is the place where more detailed explanation goes. There is room" + _
             " for plenty of text so you can cover a lot of ground for users who can't decide" + _
             " which option to select."
There are still no options selectable by the users. To expose buttons to the users, we have to create as many TaskDialogCommandLink as required. These controls are almost the same we saw in the previous section. You need at least 3 lines of codes to get a link button to appear:
Dim clStartOver As New TaskDialogCommandLink( _
    "clStartOver", _
    "Start Over", _
    "Start again from the beginning")
AddHandler clStartOver.Click, AddressOf clStartOver_Click
td.Controls.Add(clStartOver)
The first line declares the link giving it a Name, a Text and the Instruction. Be careful to this constructor if you see other examples because the order of the Text and Instruction arguments changed between version 1.0 and version 1.3. Then you need to assign an event handler using the AddHandler statement which basically says: “if the user Click this command link, execute the clStartOver_Click event”. Finally, you need to add this new object to the task dialog object. The command links will appear in the sequence you add them. The signature of the method called by the Click event has to be the same as the Click event of a button:
Private Sub clStartOver_Click(ByVal sender As Object, ByVal e As System.EventArgs)
    MessageBox.Show("You chose to start over")
End Sub
Your TaskDialog can provide one (and only one) checkbox for the cases where you want to give a kind of “yes to all” option to your users. The required code is:
td.CheckBoxText = "You can provide an option like Always Use Saved File here."
I will show you later how to retrieve the value from it.

You might also want to provide a footer text to your dialog. To achieve this, you have to set the FooterText property. This is the code required:

td.HyperlinksEnabled = True
td.FooterText = "This footer text can explain even more of what is going on " + _
                "(<A href=""http:=www.emoreau.com"">www.emoreau.com</A>)."
AddHandler td.HyperlinkClick, AddressOf TaskDialogHyperlinkClick
Of those 3 lines, only the middle one is required to show the footer. I have also used this sample to show you that you can provide hyperlinks in any of the text section. You first need to set the HyperlinksEnabled property to True. Then you need to provide an hyperlink using the HTML syntax in your text. Finally, you must provide the handler of the click event. Normally, we just want to open the default browser to the page of the link. You can use this code:
Private Sub TaskDialogHyperlinkClick(ByVal sender As Object, _
    ByVal e As Microsoft.SDK.Samples.VistaBridge.Library.TaskDialogHyperlinkClickedEventArgs)
    Process.Start(e.LinkText)
End Sub
The last section of the TaskDialog control I want to show you is the expanded text. This zone lets you add additional information that the users will be able to see only if they want. Consider this code:
        td.ExpansionMode = TaskDialogExpandedInformationLocation.ExpandContent
        td.CollapsedControlText = "Click here to expand"

        Dim strExpandedControlText As String
        strExpandedControlText = "This is where you would start writing you biography!" + _
                                 Environment.NewLine + _
                                 "This is a true story..."
        td.ExpandedControlText = strExpandedControlText

        td.ExpandedText = <S>This text will appear just under the Instruction section and before the first Command Link

    This is a true story...
    Line 1
    Line 2
    Line 3
    Line 4
    Line 5
    Line 6
    Line 7
    Line 8
    Line 9
    Line 10
    Line 11
    Line 12
    Line 13
    Line 14
    Line 15
    Line 16
    Line 17
    Line 18
    Line 19
    Line 20
</S>.Value
By setting those properties, you will get a little section at the bottom with an arrow beside it. When you click the arrow, another section of text opens and provides much more information. The ExpandedText property is set using the new VB 2008 feature called XML literals. Instead of concatenating strings all together, you can encapsulate it into a XML value.

We are now ready to show the dialog. We simply have to call the Show method like this (retrieving the results is optional but I need it):

Dim tdr As TaskDialogResult = td.Show()
If you remember, we have created a checkbox on our dialog. The only way to retrieve its value is by checking the result of the Show method like this:
If tdr.CheckBoxChecked Then
    MessageBox.Show("the Checkbox is CHECKED")
Else
    MessageBox.Show("the Checkbox is NOT CHECKED")
End If
The good thing with this dialog is that if you create a dialog that is higher than the screen height, it will automatically add scroll bars to some of the sections.

The bad thing with this dialog is that outside the long list of properties covered here (and there are even some more) it is not very customizable. Say for example that you would like to display 2 checkboxes, you would be required to create a dialog yourself.

I found a little “issue” when playing with this control. If you set the ExpandedControlText to a long string value, an empty spot to fit that string value will appear at the bottom of your dialog even if your text is not in the expanded mode. I have added a comment to the MSDN Code Gallery and we will see how fast (or slow) the team will react!

When you download the package from the MSDN Code Gallery, you have other examples of this dialog with progress bar and other nice features that I haven’t explained here.

The Application Restart and Recovery

Since a long time, some applications like Microsoft Word and even Visual Studio automatically save your current document every X minutes so that the application can recover from it if anything bad happens. But this action consumes resources (disk space and CPU) just in case something goes bad (and I really hope your computer does not have to recover from those files every day!). It is a rudimentary mechanism but it works to some extent. What if Word automatically saves every 10 minutes and the application crashes after 9 minutes? You just lost 9 minutes of works.

Windows Vista offers a brand new mechanism that uses a lot less resources for the “just in case something bad ever happens”. This new mechanism is named “Application Restart and Recovery”. Instead of automatically saving data every X minutes, this new mechanism detect that the application has problems and let Vista sends an event to the crashing application letting it persist any information required and can also restart the application automatically. Isn’t it nice?

This mechanism is really a 2 step thing. In the first step, Vista tells you that you are going to die really soon and that is the right time to write your last wills. In the second step, which is fully optional, Vista resurrects you. These 2 steps are really independent from each other.

Before going on with the example, I must warn you of something. When I first start playing with this feature, I had the surprise that it wasn’t working “as advertized”. My application was always dying silently until I found a setting in the Windows Vista Control Panel which was short-circuiting this mechanism. As shown in figure 3, users have the choice of an automatic check or to be asked for how to deal with the problem. This dialog is available by opening the “Problem Reports and Solutions” applet from the Control Panel and selecting “Change Settings”.

Figure 3: Problem Reports and Solutions settings

I strongly suggest that you open the RestartDemo solution found in the downloadable file, that you build it and that you run the demo application by double clicking the RestartDemoVB.exe file that you will find in your debug folder after the build process. If you try to run the application from within Visual Studio IDE, the debugger tries to do is best not to have your application killed but this time that’s exactly what you want.

When you start the application, you see a very simple form. Write something into the textbox and wait at least one minute (the timer label background will turn green after one minute as shown in figure 4) before pushing one of the buttons. The minute that you have to wait is a protection. You can imagine in some weird circumstances an application crashing when it tries to start, would trigger the process of killing itself and recover to crash again. This is not very helpful!

Figure 4: This application will crash soon!

Now click the “Fatal Error” button (which will trigger a fatal exception in the application). If your “Problem Reports and Solutions” settings are not set to the automatic mode, you will see the dialog shown in figure 5. The exact wording of the first question (which is a Command Link in case you haven’t seen it) may differ depending on your Internet connection state (I was commuting to work with no Internet connection when I took this snapshot).

Figure 5: Restart?

There is absolutely no added value in having users selecting the first option (connected or not) because you cannot set the location to check for online solution to your own web server. It will always go to Microsoft servers and will never find a solution because your application is not registered there. If you click the “Restart the program” link, the dialog shown in figure 6 will then appear.

Figure 6: The application is now writing its last wills

While the figure 6 dialog is displayed on the screen, code of your application is currently running (and we will talk of the required code later). For this demo, this dialog will appear for quite a long time because fake loops are made to spend time so that you have the chance to see that dialog (and for me to capture it). In your real life application, the time it is displayed varies according to the work your application has to do before being killed.

If you have selected to restart the application, it will then restart. The first line of the textbox (this is a limitation of the demo application and not the mechanism) will be reinserted into the textbox just like it was before dying.

Now add something else to the textbox and when the label will turn green again (after a minute), click the second button titled Hang. Notice that the timer is not updated anymore. You will see a tight loop in the code later to simulate this situation. After about 5 seconds, try to move the application and Windows will tell you that the application is not responding (see figure 7).

Figure 7: Application is not responding

If you kill the non-responding application (the simplest way is by clicking the red X at top-right), you will get a dialog a bit different than the previous one as shown in figure 8. You will now have of the choice of restarting, closing or waiting.

Figure 8: The application died again

If you select the restart button, your application will restart and restore its current state.

I just demonstrate how this feature is working but said nothing about the required code yet. The persisting of the current state and the recovery is not done automatically, you have to write some code!

This simple application starts with the Main method in the Module1.vb file. It detects if a command line arguments was passed to it and call the form’s constructor using this argument which in this case will be the path of the file containing the data to restore after a crash. This is the important code of the Main method:

Dim recoverypath As String = ""
Dim args() As String = Environment.GetCommandLineArgs()
If (args.Length > 1) Then
    recoverypath = args(1)
End If

Application.Run(New Form1(recoverypath))
The form’s constructor checks if the parameter is a file that really exist, opens it and restore the value from it. This is the required code:
Public Sub New(ByVal pRecoveryPath As String)
    Me.New()
    If Not String.IsNullOrEmpty(pRecoveryPath) _
        AndAlso File.Exists(pRecoveryPath) _
    Then
        Me.lblRecoveryPath.Text = pRecoveryPath
        Dim r As StreamReader = File.OpenText(pRecoveryPath)
        textBox1.Text = r.ReadLine()
        _TextboxText = textBox1.Text
        r.Close()
        r.Dispose()
        r = Nothing

        '//should clean away the file - I am leaving it so it can be 
        '//examined while debugging/understanding the process, or so 
        '//restarts can be repeated under the debugger
    End If
End Sub
In that method, it would be a good idea to delete the file after recovering from it but to keep the file for debugging purpose, I am not doing it here. Also notice that the code required here heavily depends on the method you used to save your data and the complexity of your interface.

The following section of code that we will explore is contained into the Form_Load event. The code there is responsible of registering to the notifications sent by Windows Vista.

There are 2 notifications to which you can register as shown in this example:

'Register the recovery notification
Dim recoverySettings = New RecoverySettings( _
    New RecoveryCallback(AddressOf SaveForRecover), Nothing, 5000)
ArrManager.RegisterForApplicationRecovery(recoverySettings)

'Register the Restart Notification
Dim restartSettings = New RestartSettings( _
    Convert.ToChar(34) + _RecoveryPath + Convert.ToChar(34), RestartRestrictions.None)
ArrManager.RegisterForApplicationRestart(restartSettings)
The first notification is the one sent when Windows Vista detects that the application is dying. The SaveForRecover keyword is the name of the method that will be called when this event will be handled. ArrManager is the name of a class contained into the VistaBridge library. The first parameter of the RestartSettings constructor should always be enclosed between double quotes in case you have spaces into your path (that problem was found by my friend Christian Beauclair). The second parameter of the RestartSettings constructor can be set to values other than None. For example, you can tell not to recover after a reboot.

We now need to provide the method that will save the data from your dying application to a data store. Remember that it is not the time of being fancy as your application is currently dying. You better write the data you want into the simplest form you can.

Private Function SaveForRecover(ByVal Parameter As RecoveryData) As Integer
    Dim w As StreamWriter = File.CreateText(_RecoveryPath)
    w.WriteLine(_TextboxText)
    w.Close()
    '//simulated delay
    For i As Integer = 1 To 10
        Dim b As Boolean = Me.Ping()
        If (b) Then Return 0
        System.Threading.Thread.Sleep(2000)
    Next
    ArrManager.ApplicationRecoveryFinished(True)
    Return 0
End Function
This code creates a text file and save the content of the textbox to it. It then simulates a delay so that you can see the dialog and finally warn Windows Vista that the operation has completed by calling the ApplicationRecoveryFinished method.

The _RecoveryPath is a class level variable. You may write your file anywhere but keep in mind that your user might not have enough privileges to write anywhere. A good idea is to use the GetFolderPath and the ApplicationData special folder. This is how I declared my variable:

Private ReadOnly _RecoveryPath As String = _
    Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), _
                 "App Recov.txt")
The other thing you might notice in the SaveForRecover method is that a variable named _TextboxText is used instead of the real control. The reason is that this method will be called by Windows Vista from another thread and that new thread won’t have access to controls on the form. That’s why you need a mechanism of keeping your controls’ value into an intermediate storage. In my very simple application, I have used the TextChanged event:
_TextboxText = textBox1.Text
The last thing I want to point you to in the SaveForRecover method is the call to the Ping method. The code of this Ping method is the following:
Private Function Ping() As Boolean
    'ApplicationRecoveryInProgress returns TRUE if I hit the Cancel button
    Dim blnEsc As Boolean = ArrManager.ApplicationRecoveryInProgress()
    If blnEsc Then
        MessageBox.Show("Cancelled")
    End If
    Return blnEsc
End Function
If you return to figure 6, you will see a Cancel button. If the user press the Cancel button, the ApplicationRecoveryInProgress (that name is really not intuitive for what it is used for!) will be set to True. This cancellation mechanism is really required if your SaveForRecover method really takes more than 1 seconds. If I wouldn’t have the loop in place, I wouldn’t be required to use it because the user would never have a chance to click the button. Finally, if that button is clicked, you should not call the ApplicationRecoveryFinished method to stop the application from restarting.

Just in case you wander how I made the application crashed or not responding, here is the code behind the 2 buttons:

Private Sub Hang_Click() Handles Hang.Click
    Do While True
        'nothing to ensure that we loop tight!
    Loop
End Sub

Private Sub FatalError_Click() Handles FatalError.Click
    timer1.Enabled = False
    Dim zero As Integer = 0
    Dim i As Integer = Convert.ToInt32(3 / zero)
End Sub
And what if you have to debug that process?

Testing the recovery is really simple. You just need to provide the same parameters that would be provided by the code in the “Command line arguments” textbox of your project properties (as shown in figure 9), set a breakpoint into the constructor that accepts the argument (the one that fills the textbox) and you are done.

Figure 9: Setting the Command line arguments

If you have to trace the method that persist the data to a file, it is a bit more complicated but it can be done. This is the recipe you need to follow in this particular order (otherwise it is likely to fail):

  • Run the application by double-clicking the .exe file from the bin folder (not from within VS IDE)
  • In the source code, place a break point into the SaveForRecover method
  • Open the Attach to Process dialog from the Debug menu (from within VS IDE)
  • Find your application in the list of available processes as shown in figure 10 (my demo application is called RestartDemoVB.exe)
  • When the label turns green, click one of the buttons
  • When the dialog from Windows appear (asking if you want to restart the application), go back to the Attach to Process dialog and click the Attach button
  • Now go back to the Windows dialog and click the Restart command link
  • Your debugger should now be activated
  • Quickly do what you have to do because Windows Vista will kill your application if you are not done debugging after some time

Figure 10: Attaching the debugger to the process

Alternatives

You won’t find easy alternatives to all those features.

If you (or your users) are not running Windows Vista yet and still want to use something similar to the Command Links and/or the Task dialog, I found a Vista-like TaskDialog control that is compatible with Windows XP on CodeProject.

Conclusion

I am a bit disappointed of the support (or lack of support I should say) we get from the VistaBrdige team on MSDN Code Gallery. I posted a bug a long time ago about the ExpandedText property and had no comments since then.

If you as a developer and your users are using Windows Vista, you definitely need to download it and start using it today.

Start with the new Task Dialog. Your users will thank you for sure.


(Print this page)