Home > View Post

Using Windows Search in your applications

I've been working on a WPF app that does lots of stuff with XPS (you don't say Josh! Merging XPS Documents, Cracking an XPS in WPF). One thing I wanted to do was have an integrated search that could whizz through my repository of documents and have the results right there in my application.

Naturally, I was keen to leverage an existing mechanism to do this. My first port of call was to llok at how the Find feature had been implemented in WPF's DocumentViewer control:

Find in WPF's DocumentViewer

Regrettably, the implementation of this search is somewhat, err, encapsulated. You can only get at it using lots of nasty reflection and 'going unsupported'. I really didn't fancy that.

And so my attention was drawn to Windows Search.

Built on the original Windows Desktop Search that you added to Windows XP, Windows Search is part of Vista (and Windows 7 builds on this even more) - fortunately, it has an API that we can all use.

The way in which we query the index should be familiar to most .NET Developers, we just use System.Data's OleDb Providers. Here's some sample code that executes a query and populates a Windows Forms datagrid with the results:

using (OleDbConnection conn = new OleDbConnection(
"Provider=Search.CollatorDSO;Extended Properties='Application=Windows';"))
    OleDbCommand cmd = new OleDbCommand(txtSearch.Text, conn);

    using (OleDbDataReader reader = cmd.ExecuteReader())


        for (int i = 0; i < reader.FieldCount; i++)
            gridResults.Columns.Add(reader.GetName(i), reader.GetName(i));

        while (reader.Read())
            List<object> row = new List<object>();

            for (int i = 0; i < reader.FieldCount; i++)


And here's a snap of the results:

Search Results

The query (txtSearch.Text) I'm using to get these results? Well, for those of you that can't read the tiny image...

SELECT TOP 5 System.ItemPathDisplay, System.ItemUrl FROM SYSTEMINDEX WHERE System.ItemType = '.config'

Oh yeah baby - it's just like SQL! In this case I want to select the display path and the full url for the top 5 files in the system index where the extension is .config.


There is a mindblowing number of columns available when querying Windows Search - most of them are only applicable to certain file types, for example: System.Photo.Aperture, System.Photo.ApertureDenominator, System.Photo.ApertureNumerator, System.Audio.SampleRate.

You can get the full, daunting, list on MSDN: System Shell Properties, All Shell Properties (use the tree on the left to navigate to the categories).

Still, you can put together some amazing queries depending on your application (photo app anyone?).


You can do most of the things you'd expect with the WHERE clause: e.g.

-- items not modified since
WHERE System.DateModified <= '2007-07-07'

-- find all images big enough to be wallpaper (on a small screen :)
WHERE System.Image.VerticalSize >= 768 AND System.Image.HorizontalSize >= 1024

-- items with a due date (includes mails and tasks remember!)

Very cool - but I needed to search documents and dive into the guts of the text. There are two key ways of doing this: CONTAINS and FREETEXT.

Initially, I opted for CONTAINS and started building queries like the example below, passing the value from a textbox the user plonks his search into:


This was fine when the query was "powershell" or "windows" but any non-word character blew it up (including spaces). So "where are you?", "windows vista" and "windows!" were all invalid.

Blindly, I decided to chop these queries up using regular expressions and rebuild them so that they'd become...

WHERE CONTAINS('"where" AND "are" AND "you"')
WHERE CONTAINS('"windows" AND "vista"')
WHERE CONTAINS('"windows"')

...respectively. This worked but it felt wrong. The FREETEXT alternative is really what I was looking for and does exactly what I needed without the need to hack the query to pieces:

WHERE FREETEXT('where are you?')
WHERE FREETEXT('windows vista')
WHERE FREETEXT('windows!')

Much easier.


Truly awesome so far - but I wanted to limit my search to a specific directory with documents that pertain only to this application. No problem!

There are two approaches here:

DIRECTORY - when you want to limit the search to single directory.

SCOPE - when you want to limit your search to specific folder and its sub-folders.

WHERE FREETEXT('your query') AND DIRECTORY = 'c:\users\josh\justhere'

-- or

WHERE FREETEXT('your query') AND SCOPE = 'c:\users\josh\godeep'

UPDATE - read this post 'Windows Search and the file scheme' before copying this code!

And more

There's lots more available in Windows Search SQL - you can ORDER BY and even weight individual columns differently with the RANK BY statement.

Modifying the index

The final obstacle for your application of Windows Search might be getting the files you want into the index. Sadly, there's no support for INSERT, UPDATE or DELETE in Windows Search SQL but there is a different API to allow you to play with the indexes.

As a managed developer, I opted to use the Microsoft.Search.Interop.dll that some helpful folks created as part of the Microsoft Windows Search 3.x SDK.

It's pretty easy to use but the documentation is a little sparse.

Here's some code I used to add a folder path as a user scoped rule (there are default scope rules that include or exclude folders, and user scoped rules that override these where necessary).

CSearchManager manager = new CSearchManager();

// the SystemIndex catalog is the default catalog that windows uses
CSearchCatalogManager catalogManager = manager.GetCatalog("SystemIndex");

CSearchCrawlScopeManager csm = catalogManager.GetCrawlScopeManager();

// Check to see if our path is already a crawl scope
if (!Convert.ToBoolean(csm.IncludedInCrawlScope(ScanPath)))
    // if not, add it at the user level
    csm.AddUserScopeRule(ScanPath, Convert.ToInt32(true), Convert.ToInt32(true), 0);

As you can see, most of the work takes place against the ISearchCrawlScopeManager interface - and as it notes in the documentation Using the Crawl Scope Manager, you'll need the right permissions to modify the index.

A word of caution

I did have some problems with managing query scopes. Specifically, because these files were generated by my application I wanted to keep them tucked away. They're not sensitive or corruptible in any real way, but I didn't want them getting in the users way. Good places for such files are Common Application Data folders (ProgramData) or User Application Data folders (AppData\Local and AppData\Roaming etc).

As you'll see in What is Included in the Index - these folders are specifically excluded. I thought I'd give it a shot at overriding this with a User Scoped Rule for my particular sub-folder. And, although the index made all the right noises (including the UI in Windows 7, below) the contents of these folders simply never showed up in my results.

The FANCI bit

The next thing is to check was the NotContentIndexed attribute of the files - this means the metadata might be indexed, but not the content of your files: b

The FANCI bit

It turns out this is a bugette due to the fact that the exclusion of the ProgramData folder contains a trailing asterisk (c:\ProgramData\*). The solution for me was to put the contents elsewhere, but I believe removing the naughty rule and re-applying it without the trailing asterisk would work equally well.

Josh Post By Josh Twist
12:55 PM
22 Jun 2009

» Next Post: Fun with a Power and Energy Monitor
« Previous Post: A developer's roundabout way of fixing some issues with a wireless router

Comments are closed for this post.

Posted by Armando @ 08 Sep 2009 7:14 PM
Nice info. But, I tried this and the search did not return pdf files that are present. Also, adobe ifilter is installed and pdf type are indexed. Why?

Posted by bl00m @ 10 Nov 2009 10:51 PM
Hello, how i can use Windows Search for files stored in Microsoft SQL server?

Posted by miridfd @ 12 Nov 2009 5:32 AM
Thanks for the valuable information. I'd like to know if this would work on windows server 2003 and XP?

Posted by josh @ 12 Nov 2009 5:40 AM
You'll need to install Windows Desktop Search. I don't think it's as good as Vista's but the details are documented on MSDN somewhere.


WRT Search in SQL, I think you'd need to write an extension - I've never tried that.

Posted by miridfd @ 18 Nov 2009 12:20 PM
Is WS infrastructure part of Windows Server 2003?
I couldn't figure out whether yes or no.

Thanks a lot

Posted by Macke @ 11 Mar 2010 5:16 AM
I have created a test document with some content. If I search after the word "baloon" I get a hit because it's a standalone word in the content.

If I search for example "baloo", I didn't find anything.
How do I build a querystring to act like a sql-query "SELECT * FROM table WHERE text LIKE 'ballo%'" to find a document.

Hope you can help me!

Posted by Vladekk @ 08 Apr 2010 5:30 AM
Thanks, this was useful. I found it strange that find information on this topic on web or in official docs is not so easy.

Posted by Anda @ 02 Nov 2010 3:32 PM
Hi Josh,

Thanks a lot, this is a very useful post!
I do have a question, however, and I was wondering if any of you came across this issue: how to search for those files that are not hidden? I know I have to check the System.FileAttributes property, but I haven't found out just how yet.
Any help would be appreciated, thanks!

Posted by Peter @ 20 Dec 2010 5:55 PM
How do you remove noise from the search, is there is standard rountine or config?

Posted by Josh @ 20 Dec 2010 5:57 PM
I think you'd have to add this yourself, filtering the results before you present them.

Posted by Joshua @ 27 Jan 2011 6:58 PM
Can you give any pointers as to how Windows search could be queried from SQL Server? I currently have an app that queries Indexing Service (Microsoft's old index solution) to get metadata on files that contain my search term, which is then joined with SQL Server data and then presented to the user. I have wanted to replace Indexing Service with Windows Search as my indexer, but have yet to find a way to query from SQL Server. (I want to do this since the size of my Indexing Service Index is now about 10 GB)

Any thoughts would be appreciated.


Posted by Josh @ 27 Jan 2011 7:13 PM
Not other than the SQLCLR? Sounds kind of ugly though.

Posted by Arno @ 07 Jul 2011 4:02 PM

I have built this onto an ASP.Net page. But as soon as I run it from my production server, querying a remote server, I get an "Access Denied" error. Any idea what rights I must grant to gain access.

Posted by Nicole @ 20 Jan 2012 7:09 PM
Thanks for the info Josh.
I'm trying to use Windows Search to return search results from within various websites running on asp.net, IIS7+ on a Windows 2008 server. I've tried many available properties and cannot find one that results in a URL/virtual path to the document. So I can use that in the results for users to click on and go straight to the file. Any thoughts? Thanks!

© 2005 - 2016 Josh Twist - All Rights Reserved.