You can search in Outlook folders and sub folders in 3 different ways: by using the Items.Restrict method, Items.Find in liaison with Items.FindNext and Application.AdvancedSearch. The first two have essential limitations in use – they work only for one Items collection of MAPIFolder, are executed synchronously, and not all fields of Outlook items by a long shot can be used for searching.
The AdvancedSearch method is the most powerful and convenient way of search, it can search in Outlook sub folders as well, and it is this method that we are going to dwell on today.
Well, here goes. The description of the AdvancedSearch method in VB.NET is as follows (C# sample is available for download at the end of the post):
Function AdvancedSearch(ByVal Scope As String,_
Optional ByVal Filter As Object = Nothing,_
Optional ByVal SearchSubFolders As Object = Nothing,_
Optional ByVal Tag As Object = Nothing)_
As Microsoft.Office.Interop.Outlook.Search
Parameters:
- Scope. It is the range of search, usually a path to a folder.
- Filter. This is the most complicated parameter. It determines what we are searching for. Its syntax should correspond to the syntax of SQL Server queries (among others, we can use such a nice operator as LIKE), which is very comfortable indeed. However, it not that easy to specify how column names should look like, but the following MSDN article will definitely be of much help.
- SearchSubFolders. Determines whether to search in folder’s subfolders.
- Tag. This is a search identifier. You will need it when handling the AdvancedSearchComplete event.
In our VB.NET example, we use an instance of an Advanced Outlook Form to give the end-user the ability to start search:
Private Sub Button1_Click(_
ByVal sender As System.Object,_
ByVal e As System.EventArgs) Handles Button1.Click
Dim CurrentFolder As Outlook.MAPIFolder
Dim CurrentOutlookApp As Outlook.Application
Dim sFilter, sScope As String
Me.ListView1.Items.Clear()
If RadioButton1.Checked Then
sFilter = "urn:schemas:httpmail:subject LIKE '%"_
+ TextBox1.Text.Trim + "%'"
Else
sFilter = "urn:schemas:httpmail:textdescription LIKE '%"_
+ TextBox1.Text.Trim + "%'"
End If
If Me.OutlookAppObj IsNot Nothing Then
CurrentOutlookApp = TryCast(Me.OutlookAppObj, Outlook.Application)
If Me.FolderObj IsNot Nothing Then
Try
CurrentFolder = TryCast(Me.FolderObj, Outlook.MAPIFolder)
sScope = "'" + CurrentFolder.FolderPath._
Replace("'", "''") + "'"
oSearch = CurrentOutlookApp.AdvancedSearch(_
sScope, sFilter, True, "Search1")
Catch ex As Exception
System.Windows.Forms.MessageBox.Show(ex.Message)
End Try
End If
End If
End Sub
Handle the AdvancedSearchComplete event and fill in System.Windows.Forms.ListView with search results:
Public Sub adxOutlookEvents_AdvancedSearchComplete(_
ByVal sender As System.Object,_
ByVal hostObj As System.Object)_
Handles adxOutlookEvents.AdvancedSearchComplete
Dim myForm As ADXOlForm1 = Nothing
Dim CurrentResults As Outlook.Results = Nothing
Dim CurrentSearch As Outlook.Search = Nothing
Dim lvListItem As System.Windows.Forms.ListViewItem
Dim OldCursor As System.Windows.Forms.Cursor
Dim objItem As Object
myForm = AdxOlFormsManager1.Items(0)._
GetCurrentForm(AddinExpress.OL.EmbeddedFormStates.Visible)
If myForm IsNot Nothing Then
OldCursor = myForm.Cursor
Try
myForm.Cursor = Windows.Forms.Cursors.WaitCursor
CurrentSearch = CType(hostObj, Outlook.Search)
If CurrentSearch IsNot Nothing Then
If CurrentSearch.Tag = "Search1" Then
CurrentResults = CurrentSearch.Results
If CurrentResults.Count > 0 Then
myForm.ListView1.BeginUpdate()
For i As Integer = 1 To CurrentResults.Count
objItem = CurrentResults.Item(i)
lvListItem =_
New System.Windows.Forms.ListViewItem
With lvListItem
.Text = objItem.SenderName
.SubItems.Add(objItem.Subject)
.SubItems.Add(_
objItem.ReceivedTime.ToString())
.SubItems.Add(objItem.EntryID)
End With
myForm.ListView1.Items.Add(lvListItem)
Next
myForm.ListView1.Items(0).Selected = True
myForm.ListView1.EndUpdate()
Else
System.Windows.Forms.MessageBox.Show(_
"0 items were found.")
End If
End If
End If
Catch ex As Exception
System.Windows.Forms.MessageBox.Show(ex.Message)
Finally
If CurrentResults IsNot Nothing Then
Marshal.ReleaseComObject(CurrentResults)
End If
myForm.Cursor = OldCursor
End Try
End If
End Sub
The search process is VERY fast indeed. It normally takes just a few seconds from executing the AdvancedSearch method to raising the AdvancedSearchComplete event. Retrieving objects from the Results collection is much slower. But even here there is some room for improvement: you can use the SetColumns method of the Results collection to cache certain fields for fast access. That’s all for today.
You may also be interested in:
Special features for Outlook plug-in development
How to write Outlook add-in: toolbars, buttons, ribbons, menus
Available downloads:
C# sample Outlook add-in for VS 2005
VB.NET sample Outlook add-in for VS 2005

del.icio.us
Digg
Stumbleupon
Can this AdvancedSearch also search recursively (i.e. with subfolders) inside Public Folders and folders inside shared mailboxes? Just asking because the Advanced Find dialog in Outlook could not…
It can search recursively in Exchange Mailboxes, but cannot in Public Folders. Also, searching across multiple Stores simultaneously is not possible.
That’s great to hear (about the secondary mailboxes)! We recently had a request where this would definitely come in handy. I’ll have a look at this next week.
Phew looks very complicated. How about a normal search tool which is able to search both your contacts and your addresses and is pretty fast, too? I use lookeen and am pretty happy with it.
Thank you for the idea. We will try to create a how-to sample of such kind.