Search


Search is an important feature that you can find at many places with Windows Vista. The Windows Start menu offers a search capability. Here, you can search for programs to start. After using this search for some time I wouldn’t want to miss it. With Windows XP it was hard to find programs from the Start button if a many applications were installed. Now it’s really easy with the search function.

By selecting the Search menu, you can find documents such as e-mails, documents, pictures, music, and more. With the simple search, you just enter a search phrase in the search box to find items in indexed locations. The advanced search (see Figure 44-15) allows you to enter a name, tags, or an author, and to define the locations where to search. Figure 44-16 shows the details view of the search page where you can select all the properties of items that can be shown with the searched items.

image from book
Figure 44-15

image from book
Figure 44-16

The Windows Vista File Open and File Save dialogs have the search capability integrated as well. The search function can be integrated into your applications, and your applications can take full advantage of the Windows search functionality. To understand the architecture of the Windows search capability, examine Figure 44-17. The heart of the search functionality is the indexer, which examines content and writes it to the content index. For each store (file system, MAPI), a protocol handler is responsible for getting data to the indexer. Protocol handlers implement the interface Ifilter, which is used by the indexer to analyze content for indexing. The property system describes the properties that can be searched. Properties are described by property schemas. If an application has a custom file format, it can implement a property handler for the file format. If an application has custom properties that can be searched, it can add properties to the property system. Properties are defined for the generic files, Office documents, pictures, and videos. Property handlers are invoked when content is indexed to analyze the properties of the content.

image from book
Figure 44-17

Let’s make use of the query system by building search functionality into an application.

OLE DB Provider

You can integrate search functionality into your application by using an OLE DB provider to search for items in the index. Create a simple Windows Forms application with a TextBox to allow the user to input a query, a Button control to start the query, and a ListView control to display the result, as shown in Figure 44-18. Change the View property of the ListView control to Details to display all the information the user enters with the query.

image from book
Figure 44-18

Import the namespace System.Data.OleDb and add the following code to the Click event of the Search button.

  private void buttonSearch_Click(object sender, EventArgs e) {    try    {       listViewResult.Clear();       string indexerConnectionString = "provider=Search.CollatorDSO.1;" +             "EXTENDED PROPERTIES='Application=Windows'";       OleDbConnection connection = new OleDbConnection(             indexerConnectionString);       connection.Open();       OleDbCommand command = connection.CreateCommand();       command.CommandText = textBoxQuery.Text;       OleDbDataReader reader = command.ExecuteReader();       DataTable schemaTable = reader.GetSchemaTable();       foreach (DataRow row in schemaTable.Rows)       {          listViewResult.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());          }          listViewResult.Items.Add(item);       }       connection.Close();    }    catch (Exception ex)    {       MessageBox.Show(ex.Message);    } } 

Let’s get into the code details. The indexer offers the OLE DB provider Search.CollatorDSO. With the OLE DB connection string, you can pass this provider information and open the connection to the indexer.

 string indexerConnectionString = "provider=Search.CollatorDSO.1;" +       "EXTENDED PROPERTIES='Application=Windows'"; OleDbConnection connection = new OleDbConnection(       indexerConnectionString); connection.Open();

The query that is used with the indexer is read from the TextBox control textBoxQuery. Because during compile time it is not known which properties will be selected by the user, the columns in the ListView control must be added dynamically. The method GetSchemaTable() of the OldDbDataReader returns the dynamically created schema information that relates to the query. Every row describes an item in the SELECT statement, and the first column inside this item gives the name of the item. By iterating through every row of the returned schema, a new column is added to the ListView control, and the heading of this column is set to the item name.

 OleDbCommand command = connection.CreateCommand(); command.CommandText = textBoxQuery.Text; OleDbDataReader reader = command.ExecuteReader(); DataTable schemaTable = reader.GetSchemaTable(); foreach (DataRow row in schemaTable.Rows) {    listViewResult.Columns.Add(row[0].ToString()); }

Next, every row from the OleDbDataReader is read. The first column creates a new ListViewItem, and every further column in the result set adds a subitem that is shown with the detail information of the list view.

 while (reader.Read()) {    ListViewItem item = new ListViewItem(reader[0].ToString());    for (int i = 1; i < reader.FieldCount; i++)    {       item.SubItems.Add(reader[i].ToString());    }    listViewResult.Items.Add(item); }

Now, you can start the application, enter a query and get the result, as shown in Figure 44-19.

image from book
Figure 44-19

 SELECT System.ItemName, System.ItemTitle, System.Size FROM SYSTEMINDEX       WHERE System.Size > 1024

In the SELECT statement of the query, you specify the properties that should be returned. System .ItemName, System.ItemTitle, and System.Size are predefined properties. You can find other predefined properties in the MSDN and TechNet documentation for the Windows Desktop Search 3.0 properties. Some of the generic file properties are System.Author, System.Category, System.Company, System.DateCreated, System.DateModified, System.FileName, System.ItemName, System.ItemUrl, and System.Keywords. For audio files, digital photos, graphics files, media files, Office documents, music files and Outlook calendar items additional properties are defined, for example, System.Photo .Orientation, System.Photo.DateTaken, System.Music.Artist, System.Music.BeatsPerMinute, System.Music.Mood, System.Calendar.Location, System.Calendar.Duration, System .Calendar.Location.

With the WHERE clause you can define predicates such as literal value comparisons <, >, =, and LIKE; full-text searches such as CONTAINS and FREETEXT; and also the search depth predicates SCOPE and DIRECTORY.

Advanced Query Syntax

You wouldn’t want to let a user search by specifying a SELECT statement such as the ones used in the previous example. You can create a user interface to ask for specific items and build the SELECT statement programmatically. Another way to let users do their own searching is by using Advanced Query Syntax (AQS).

The Advanced Query Syntax lets you specify search terms and restrict a search based on properties. For example, the query Wrox date:past week searches all the items that contain the string Wrox that changed the last week. Wrox date:past week kind:documents restricts the search further by only accepting documents.

A few samples showing how you can restrict a search are described next:

  • You can restrict the search by defining the store. For example, store:outlook gets items just from the Outlook. store:file gets items from the file system.

  • With the search functionality, you can specify what kind of items should be in the result, for example, kind:text, kind:tasks, kind:contacts, kind:emails, and kind:folders.

  • Boolean operators can be used to restrict the search. For example the OR operator used in Wrox OR Wiley. date:>11/05/07 gets items after the date 11/05/07. For items between two dates, you can use 11/05/06..11/07/07.

  • You can use some item properties to search for items, for example, webpage:www.wrox.com, birthday:2/14/65, firstname:Christian.

You don’t have to manually translate the AQS to the SELECT query, there’s a COM object that does it for you. In the Windows SDK Lib directory you can find the file SearchAPI.tlb. This is a type library that describes the COM object used to do the AQS translation. By using COM Interop, you can use a COM object from .NET.

Create a .NET callable wrapper by using the tblimp utility to import the type library SearchAPI.tlb:

 tlbimp c:\Program Files\Microsoft SDKs\Windows\v6.0\Lib\SearchAPI.tlb       /out:Interop.SearchAPI.dll

Tip 

COM Interop is described in Chapter 23, “COM Interoperability.”

Referencing the generated interop assembly from the Windows Forms project created previously allows you to use the SearchAPI from the .NET application. Because of the generated assembly, import the namespace Interop.SearchAPI from the application and add the GetSql() method to the Windows Forms class.

The classes CSearchManager, CsearchCatalogManager, and CSearchQueryHelper are generated from the tlbimp utility to invoke the COM objects. The GetCatalog() method defines the catalog that is queried and returns the catalogManager. With the catalogManager instance, the query helper object is returned from the method GetQueryHelper(). Passing an AQS string to the method GenerateSQLFromUserQuery() returns a SELECT query that then can be used with the OLE DB provider to perform the query.

        private string GetSql(string aqs)       {          CSearchManager searchManager = new CSearchManager();          CSearchCatalogManager catalogManager = searchManager.GetCatalog("SystemIndex");          CSearchQueryHelper queryHelper = catalogManager.GetQueryHelper();          return queryHelper.GenerateSQLFromUserQuery(aqs);       } 

Now, you just have to change the implementation from the Click handler of the Button control to convert to invoke the GetSql() method for converting the AQS to the SELECT query that is used with the application.

 private void buttonSearch_Click(object sender, EventArgs e)    {          try          {             listViewResult.Clear();             string indexerConnectionString = "provider=Search.CollatorDSO.1;" +                   "EXTENDED PROPERTIES='Application=Windows'";             OleDbConnection connection = new OleDbConnection(indexerConnectionString);             connection.Open();             OleDbCommand command = connection.CreateCommand();             command.CommandText = GetSql(textBoxQuery.Text);             OleDbDataReader reader = command.ExecuteReader();             //...

Now, you can start the application and pass an AQS query, as shown in Figure 44-20.

image from book
Figure 44-20




Professional C# 2005 with .NET 3.0
Professional C# 2005 with .NET 3.0
ISBN: 470124725
EAN: N/A
Year: 2007
Pages: 427

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net