Tuesday, August 07, 2007

How to use Windows Vista Search API from WPF application?

Another great service, provided by Windows Vista is it's integrated search. Can we use it from our WPF application? Sure we can. This how you'll do it.

First of all you'll need to find Windows Search API library inside Windows SDK. Locate SearchAPI.tlb and process it with tlbimp tool to create managed assembly to reference to. You'll get file, named SeachAPILib.dll. This one, you need. In order to use it, refer to MSDN documentation of Windows Search API 3.0. Actually, using of search API is not much different then using database queries. However, this is not so trivial in core. Actually, the syntax of Windows Search (AQS - Advanced Query Syntax) is very different. But search team create brilliant work to make our life easier. CSearchManager and ISeachQueryHelper - those translate AQS to SQL and, even provide us with proper connection string.

Let's start. First of all, we'll have to create CSeachManager

 

CSearchManager cManager = new CSearchManagerClass();


</PRE< P> 

 






Then, while you are in query, you'll create new ISearchQueryHelper to help you with translations and query strings





 

ISearchQueryHelper cHelper = cManager.GetCatalog("SYSTEMINDEX").GetQueryHelper();

cHelper.QuerySelectColumns =
"\"System.ItemNameDisplay\"";</PRE< P>

 






Well done, now. Ask Vista with old good OleDB provider





 

using (cConnection = new OleDbConnection(

cHelper.ConnectionString))


{


cConnection.Open();


using (OleDbCommand cmd = new OleDbCommand(

cHelper.GenerateSQLFromUserQuery(


SearchString


),


cConnection))


{


if (cConnection.State == ConnectionState.Open)

{


using (OleDbDataReader reader = cmd.ExecuteReader())

{


m_results.Clear();




while (!reader.IsClosed && reader.Read())

{


m_results.Add(reader[0].ToString());


}

reader.Close();





}

}





}


cConnection.Close();


}</PRE< P>

 






Brilliant. Let's move it into WPF by creating DependencyObject, that provide us with all we need for search - search string and array of results





 

public static readonly DependencyProperty SearchTextProperty = DependencyProperty.Register("SearchText", typeof(string), typeof(VistaSearchProviderHelper), new UIPropertyMetadata(default(string),

new PropertyChangedCallback(OnSearchTextChanged)));




static void OnSearchTextChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)

{


//change

ToAbortFlag = IsWorkingFlag;




if (workerCallback == null)

workerCallback =
new WaitCallback(doSearch);




searchObjState.SearchString = e.NewValue.ToString();


//if (searchObjState.SearchString.Length > 2)

{

workerCallback.BeginInvoke(searchObjState,
null, null);

}





}</PRE< P>

 








 

public string SearchText

{


get { return GetValue(SearchTextProperty).ToString(); }

set { SetValue(SearchTextProperty, value); }

}





static ThreadSafeObservableCollection<string> m_results;

public ReadOnlyObservableCollection<string> Results

{


get { return new ReadOnlyObservableCollection<string>(m_results); }

}</PRE< P>

 






I think you know where to get thread safe observable collection :)



The only thing we should do now is to bind input and output to XAML presentation





 

<StackPanel FocusManager.FocusedElement="{Binding ElementName=searchStr}">

<
StackPanel.DataContext>

<
ObjectDataProvider ObjectType="l:VistaSearchProviderHelper"/>

</
StackPanel.DataContext>

<
TextBox Name="searchStr" Text="{Binding Path=SearchText, UpdateSourceTrigger=PropertyChanged }" FontSize="30"/>

<
ListBox ItemsSource="{Binding Path=Results}" />

</
StackPanel></PRE< P>

 






We done. Now we can search our Windows Vista from custom WPF application. This is not final application for sure, there is a long way to go to make it work perfectly, but this is the beginning of how to do it.



Source code for this article

1 comment:

kevz said...

Hi ,
I am trying to have a search field and a drop down box and a search button , based on the values in search field and drop down box i press the search button to make an api call to get the results . Now I have a listview where i want to be able to display the results using the Observable Collection. Can you help me with a possible solution.