Introduction
In this article, I will discuss on what you need to know about developing applications for Windows Vista and Windows Server 2008, and the upcoming OS Windows 7, and how to implement these from .NET (C#) applications. The accompanying downloadable application contains all you need to start off immediately. It includes the Vista Bridge runtime, its CHM Help file, and the Windows Search Interop assemblies. But, to keep yourself updated with changes from Microsoft, you should probably get yourself the updated runtimes from the Microsoft site.
The topics that will be covered here are:
- Vista Bridge
- User Access Control (UAC)
- Directory structure
- New controls and dialogs
- Windows Search
Vista Bridge
Vista Bridge is a new API introduced by Microsoft that wraps a lot of the native calls to the Windows Vista OS. This enables the exciting features in Vista like Glass forms, new dialogs, etc. We would keep our discussion to the very basic and general features exposed by this API.
User Access Control
UAC is a feature exclusively introduced from Windows Vista and Windows Server 2008. Although it has its issues, the feature has made Windows Vista and Server 2008 much more safer than their predecessors. Think about a situation where a user gets the Administrator feature and installs a trojan horse and destabilizes the system. The UAC feature has reduced the chances of that. A general user logged in as an Administrator will have to go through the UAC prompt to perform an action that requires an elevated permission. Thus, we infer that an Administrator logged on to the system doesn't get an administrative privilege on Windows Vista.
To provide Administrative privileges, select "Run as Administrator" from the context menu. This section adds the application compatibility flags to the Registry at HCU\Software\Microsoft\Windows NT\Current Version\AppCompatFlags\Layers with the value of RUNASADMIN.
How to get the UAC prompt and run an application at an Elevated permission?
To get an Elevated permission for your application, just follow these steps:
- Add a Manifest file to the application project. The application manifest is named app.manifest, by default.
- Open up the manifest file and edit the
level
attribute of requestedExecutionLevel
in the XML to a value that represents the Execution privilege of the application.
The Execution privilege values are requireAdministrator
, highestAvailable
, and asInvoker
. The value highestAvailable
means that the application gets the privileges the user has-but only after getting the consent from the user. The value of requireAdministrator
requires Administrator privileges. If the user is not logged in as Administrator, a login dialog appears where the user can log in as an Administrator for the application. The value asInvoker
means that the application is running with the security token of the user.
The uiAccess
attribute specifies if the application requires input to a higher privilege level window on the desktop. An example code for app.manifest for Administrator privilege from UACAdminPrompt
is:
<asmv1:assembly xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:asmv2="urn:schemas-microsoft-com:asm.v2"
xmlns:asmv1="urn:schemas-microsoft-com:asm.v1"
xmlns="urn:schemas-microsoft-com:asm.v1" manifestversion="1.0">
<assemblyidentity version="1.0.0.0" name="MyApplication.app">
<trustinfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedprivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedexecutionlevel level="requireAdministrator" uiaccess="false">
</requestedexecutionlevel>
</requestedprivileges>
</security>
</trustinfo>
</assemblyidentity>
Shield icon
When the user clicks on a control with Shield icon, an elevation prompt is used. Elevation prompts would be different depending on the type of application that is elevated:
- Windows needs your permission to continue. This elevation prompt is shown for applications that are delivered with Windows.
- A program needs your permission to continue. This elevation prompt is shown with applications that contain a certificate to provide information about the publisher.
- An unidentified program wants access to your computer. This elevation prompt is shown with applications that don't contain a certificate.
Directory structure
The directory structure has changed a lot from Windows XP to Vista. There's no more a directory of the form c:\Documents and Settings\<username> and had been replaced in Vista by c:\Users\<username>. Windows XP defines a subdirectory My Documents for storing user-specific data, but Windows Vista defines c:\Users\<username>\Documents. To retrieve the folder path, use the SpecialFolder
enumeration as:
string folderName = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
Some of the folders defined by the SpecialFolder
enumeration are described in the following table:
Content | SpecialFolder Enumeration | Windows Vista default Directory |
---|
User specific documents | Personal | c:\Users\<user>\Documents |
User specific data for the roaming profile | ApplicationData | c:\Users\<user>\AppData\Roaming |
User specific data that is local to the system | LocalApplicationData | c:\Users\<user>\AppData\Local |
Program Files | ProgramFiles | c:\Program Files |
Program Files that are shared among different programs | CommonProgramFiles | c:\Program Files\Common |
Application data common to all users | CommonApplicationData | c:\ProgramData |
An example code that retrieves the Vista directories using the above enumerations is highlighted in the application DirStucture project.
Windows Search Provider
Before we begin, let me state that the Windows Search service must be enabled for this to work. Disabling the Windows Search service will cause the query to fail and return an error. Open a C# project, and create a Windows Forms application named, say, VistaSearch. Open the Windows form in designer mode and place these following controls in it:
TextBox
named tbSearch
Button
named btnSearch
, Text
: SQL SearchButton
named btnClassicSearch
, Text
: SearchListView
named lvResult
, Detail mode.
The Windows Search provides a DSO for querying the Windows Search engine with a SQL query. The DSO is named Provider=Search.CollatorDSO.1;EXTENDED PROPERTIES='Application=Windows'. Open this provider using an OLEDB connection and pass the SQL query into it to get the result.
So, we have it. Now, let's see how to use this DSO in our application. Open the source code of the event handler corresponding to the button name btnSearch
, and write:
try
{
lvResult.Clear();
string indexConnectionString = "Provider=Search.CollatorDSO.1;" +
"EXTENDED PROPERTIES='Application=Windows'";
OleDbConnection connection = new OleDbConnection(indexConnectionString);
connection.Open();
OleDbCommand command = connection.CreateCommand();
command.CommandText = tbSearch.Text;
OleDbDataReader reader = command.ExecuteReader();
DataTable schemaTable = reader.GetSchemaTable();
foreach (DataRow row in schemaTable.Rows)
{
lvResult.Columns.Add(row[0].ToString());
}
while (reader.Read())
{
ListViewItem item = new ListViewItem(reader[0].ToString());
for (int i = 1; i < reader.FieldCount; i++)
{
item.SubItems.Add(reader[i].ToString());
}
lvResult.Items.Add(item);
}
connection.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
The application must also include the following line:
using System.Data.OleDb;
The above code the following output:
This should be fairly easy to understand for those who have a knowledge of using using SQL search queries on a database.
Advanced Query Syntax (AQS)
Now, let us focus on the second part of the problem. The above search query included the SQL, but would you like your application user to provide a SQL directly into the Search textbox? I guess the answer is no. So, the workaround is to use the COM based AQS helper built into Vista to do our work. To do so, we must first implement the COM callable wrapper as follows:
tlbimp "c:\Program Files\Microsoft SDKs\Windows\v6.0\Lib\SearchAPI.tlb"
/out:Interop.SearchAPI.dll
If the path does not exist, then an alternate is:
tlbimp "c:\Program Files\Microsoft SDKs\Windows\v6.0A\Lib\SearchAPI.tlb"
/out:Interop.SearchAPI.dll
The output will be a DLL Runtime named Interop.SearchAPI.dll. Add a reference to this COM wrapper DLL from our project and then add the following line in the source code:
using Interop.SearchAPI;
Then, we would write out a function named GetSql
where we would only pass in the search keyword and it would generate the SELECT
SQL call statement which we would pass as SQL statement in the above written code.
private string GetSql(string aqs)
{
CSearchManager searchManager = new CSearchManager();
CSearchCatalogManager catalogManager = searchManager.GetCatalog("SystemIndex");
CSearchQueryHelper queryHelper = catalogManager.GetQueryHelper();
return queryHelper.GenerateSQLFromUserQuery(aqs);
}
Now, we could open and modify the source code of the btnClassicSearch
click event as follows:
private void btnClassicSearch_Click(object sender, EventArgs e)
{
try
{
lvResult.Clear();
string indexConnectionString = "Provider=Search.CollatorDSO.1;" +
"EXTENDED PROPERTIES='Application=Windows'";
OleDbConnection connection = new OleDbConnection(indexConnectionString);
connection.Open();
OleDbCommand command = connection.CreateCommand();
command.CommandText = GetSql(tbSearch.Text);
OleDbDataReader reader = command.ExecuteReader();
DataTable schemaTable = reader.GetSchemaTable();
foreach (DataRow row in schemaTable.Rows)
{
lvResult.Columns.Add(row[0].ToString());
}
while (reader.Read())
{
ListViewItem item = new ListViewItem(reader[0].ToString());
for (int i = 1; i < reader.FieldCount; i++)
{
item.SubItems.Add(reader[i].ToString());
}
lvResult.Items.Add(item);
}
connection.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
For source code, view the VistaSearch project available as download with this article. A demo output is:
Aero Glass Windows Forms
To design an Aero form, just open a C# Windows Forms application, and add reference to VistaBridgeLibrary.dll and VistaBridgeControls.dll to your application. Add the following lines to your source code:
using Microsoft.SDK.Samples.VistaBridge.Dialogs;
Now, derive your Aero Form (to be) class from the GlassForm
super class. Then, modify the Form1_Load
, that is the Load
event, and add the following lines to enable AERO for the form:
this.IsGlassEnabled = true;
A sample AERO form is shown below:
Command Link
Command Link controls are an extension to the Windows Button
control. A Command Link control contains an optional icon and a note text. This control is often used in task dialogs and wizards. To use the Vista controls, add the following line to the Windows Forms source code:
using Microsoft.SDK.Samples.VistaBridge.Controls;
Now, add a private
variable to the Windows Forms class as follows:
private CommandLinkWinForms commandLinkDemo = new CommandLinkWinForms();
Now, modify the Windows Forms constructor to add the Command Link to our Windows Forms as follows:
InitializeComponent();
commandLinkDemo.NoteText = "This is the Note Text on the Windows Vista type Button";
commandLinkDemo.ShieldIcon = true;
commandLinkDemo.Text = "This Command Link control is a part of Vista Library";
commandLinkDemo.UseVisualStyleBackColor = true;
commandLinkDemo.Location = new Point(20, 20);
commandLinkDemo.Size = new Size(300,100);
commandLinkDemo.Click += new EventHandler(this.OnCommandBtnClicked);
this.Controls.Add(commandLinkDemo);
Thus, we see above that a Click
event handler is also added to the project which is handled as:
protected void OnCommandBtnClicked(object src, EventArgs ev)
{
MessageBox.Show("Command Link button clicked.",
"Vista command Link Demo", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
The source code is taken from the VistaCommandLink project, the output of which is:
File Dialogs
Windows Vista has replaced the classic file dialogs with its new dialogs that have an inherent Windows Search built into them to ease file opening and saving. To display the file open dialog, use the following piece of code:
CommonOpenFileDialog dlg = new CommonOpenFileDialog();
dlg.Filters.Add(new CommonFileDialogFilter("All Files.", "*.*"));
CommonFileDialogResult result = dlg.ShowDialog();
The output of the above code is:
The file save dialog is shown using the following piece of code:
CommonSaveFileDialog dlg = new CommonSaveFileDialog();
dlg.Filters.Add(new CommonFileDialogFilter("All Files", "*.*"));
CommonFileDialogResult result = dlg.ShowDialog();
The output of the above code is:
Task Dialog
The task dialog is a next generation dialog that replaces the old message box. The task dialog is a part of the new common controls. It is accessed in Vista using the TaskDialog
class. The following code displays a simple task dialog:
TaskDialog.Show("This is a Simple Task Dialog");
The output of the above code is:
The following code sets the member properties of a task dialog namely, Caption
, Content
, StandardButtons
, and MainIcon
:
TaskDialog dlg = new TaskDialog();
dlg.Caption = "Title";
dlg.Content = "This is some information in the Task Dialog.";
dlg.StandardButtons = TaskDialogStandardButtons.OkCancel;
dlg.MainIcon = TaskDialogStandardIcon.Information;
TaskDialogResult result = dlg.Show();
The output of the above code is:
With the task dialog, you can also set command links. So, let's write another piece of code as follows:
TaskDialog dlg = new TaskDialog();
dlg.Caption = "Title";
dlg.Content = "This is some Content Information in the Task Dialog.";
dlg.StandardButtons = TaskDialogStandardButtons.YesNo;
dlg.MainIcon = TaskDialogStandardIcon.Shield;
dlg.ExpandedText = "This is the Expanded text.";
dlg.ExpandedControlText = "This is the Expanded Control text in the Task Dialog.";
dlg.CollapsedControlText = "This is the content of the collapsed control text.";
dlg.ExpansionMode = TaskDialogExpandedInformationLocation.ExpandFooter;
dlg.FooterText = "This is the footer text.";
dlg.FooterIcon = TaskDialogStandardIcon.Information;
TaskDialogResult result = dlg.Show();
The output results in a single dialog that has two forms:
A task dialog can also contain other controls. In the following code snippet, we would create a task dialog and add two radio buttons, a command link, and a marquee control.
TaskDialog dlg = new TaskDialog();
dlg.Caption = "Title";
dlg.Instruction = "Sample Task Dialog";
TaskDialogRadioButton radio1 = new TaskDialogRadioButton();
radio1.Name = "radio1";
radio1.Text = "One";
dlg.Controls.Add(radio1);
TaskDialogRadioButton radio2 = new TaskDialogRadioButton();
radio2.Name = "radio2";
radio2.Text = "Two";
dlg.Controls.Add(radio2);
TaskDialogCommandLink commandLink = new TaskDialogCommandLink();
commandLink.Name = "link1";
commandLink.ShowElevationIcon = true;
commandLink.Text = "Information";
commandLink.Instruction = "Sample Command Link";
dlg.Controls.Add(commandLink);
TaskDialogMarquee marquee = new TaskDialogMarquee();
marquee.Name = "marquee";
marquee.State = TaskDialogProgressBarState.Normal;
dlg.Controls.Add(marquee);
TaskDialogResult result = dlg.Show();
The output of the above code is:
GUIVistaDialog Project
This project combines all the Vista dialogs shown in this article. It has a main AERO form as:
Note: To use the Vista library and Vista dialogs, you must add the following lines of code:
using Microsoft.SDK.Samples.VistaBridge.Dialogs;
using Microsoft.SDK.Samples.VistaBridge.Library;
So, that is all to know for heading off with a Windows Vista based visually enhanced project. Signing off.