How to search folders by using the SetSearchCriteria method

Summary
This article describes how to programmatically search for specific messages when you apply restrictions on the message store or generic folder.
More information
Consider the following issues before you search for specific messages:
  • The SetSearchCriteria method can only be called on a folder that has a PR_FOLDER_TYPE property that is equal to a FOLDER_SEARCH folder.
  • When you change the PR_FOLDER_TYPE property of the folder from FOLDER_GENERIC to FOLDER_SEARCH, this causes an MAPI_E_COMPUTED error. You must create the folder by calling the MAPI function CreateFolder function with the FOLDER_SEARCH folder flag as the first argument.
  • You must implement an advise sinks object to receive notification from the message store provider that the search is complete. If the SetSearchCriteria methods returns before the search is complete, then your table will be empty.
The following sample code shows how to search messages by using MAPI messaging functions:
#include <mapix.h>#include <mapiutil.h>#include "MAPIASST.H"LONGSTDAPICALLTYPE SearchCompleteCallBack(   LPVOID          lpvContext,   ULONG           cNotif,   LPNOTIFICATION  lpNotif);void main(){	HRESULT	hr = S_OK;	LPMAPISESSION  lpSession = NULL;		LPMDB	       lpMDB	= NULL;	LPMAPITABLE    lptMsgStores = NULL;			// Initiate MAPI.	hr = MAPIInitialize(0);	MAPI_ASSERT_EX(hr);		// Logon to Extended MAPI session.	hr = MAPILogonEx((ULONG)GetActiveWindow(), 				 NULL,				 NULL,				 MAPI_NEW_SESSION|MAPI_LOGON_UI,				 &lpSession);	MAPI_ASSERT_EX(hr);	// Obtain a table of message stores from the session.	hr = lpSession->GetMsgStoresTable(NULL, &lptMsgStores);	MAPI_ASSERT_EX(hr);	// Look for the default store. If you are not online, this is located in the Offline folder.	SizedSPropTagArray(2, tagStores) = 	{		2, PR_DEFAULT_STORE, PR_ENTRYID	};	LPSRowSet pRowSetStores = 0;	SRestriction sRes;	SPropValue propStore;	propStore.ulPropTag = PR_DEFAULT_STORE;	propStore.Value.b = TRUE;	propStore.dwAlignPad = 0;	sRes.rt = RES_PROPERTY;	sRes.res.resProperty.relop = RELOP_EQ;	sRes.res.resProperty.ulPropTag	= PR_DEFAULT_STORE;	sRes.res.resProperty.lpProp = &propStore;	// Use this call with caution because it         // can return a large number of rows.         // You can use it in this case because there is only         // one default message store.	hr = HrQueryAllRows(lptMsgStores,				(LPSPropTagArray)&tagStores,				&sRes,				0,				0,				&pRowSetStores);	MAPI_ASSERT_EX(hr);	if (pRowSetStores->cRows > 0)	{	  LPSPropValue pPropStore = pRowSetStores->aRow[0].lpProps;	  LPMDB pMDBDefault = 0;				// Open the message store.		hr = lpSession->OpenMsgStore(0,			    pPropStore[1].Value.bin.cb,			    (LPENTRYID)pPropStore[1].Value.bin.lpb,			    0,			    MDB_WRITE,			    &lpMDB);				MAPI_ASSERT_EX(hr);                }		// Obtain the EID of the Finder folder.	LPSPropValue	lpspvFinderEID = NULL;	hr = HrGetOneProp(lpMDB, PR_FINDER_ENTRYID, &lpspvFinderEID);	MAPI_ASSERT_EX(hr);	// Open the Finder folder.	LPMAPIFOLDER	lpFinderFolder = NULL;	ULONG		ulType = 0;	hr = lpMDB->OpenEntry(lpspvFinderEID->Value.bin.cb,			(LPENTRYID)lpspvFinderEID->Value.bin.lpb,			NULL,			MAPI_MODIFY,			&ulType,			(LPUNKNOWN*)&lpFinderFolder);	MAPI_ASSERT_EX(hr);	// Create a Search folder from the Finder folder.	LPMAPITABLE lpFinderCont;	LPMAPIFOLDER	lpSearchFolder = NULL;	hr = lpFinderFolder->CreateFolder(FOLDER_SEARCH, "Search Folder",				"Created for Testing", NULL,				OPEN_IF_EXISTS, &lpSearchFolder);	MAPI_ASSERT_EX(hr);	hr = lpFinderFolder->GetHierarchyTable(NULL, &lpFinderCont);	SHOWTABLE(lpFinderCont);  // This is for debugging purposes.	MAPI_ASSERT_EX(hr);	// Create an advise sinks to receive notification from the message store after the search.	//This is required, or you have to wait for theSetSearchCriteria method.	BOOL fSearchCompleted =	FALSE;	LPMAPIADVISESINK lpAdviseSink =	NULL;	char szErrorMsg[50]	= "Entry";	HrAllocAdviseSink(SearchCompleteCallBack,			&fSearchCompleted,			&lpAdviseSink );	if (!lpAdviseSink)	 strcpy(szErrorMsg,"HrAllocAdviseSink no pointer returned");	MAPI_ASSERT_EX(hr);		SizedSPropTagArray(1, lpMsgColumnArray) = {1, PR_ENTRYID}; 	LPSPropValue lpSearchFolderEntryID = NULL;	ULONG cSearchFolderEntryID = NULL;	hr = lpSearchFolder->GetProps( (_SPropTagArray *)&lpMsgColumnArray,					NULL,					&cSearchFolderEntryID,					&lpSearchFolderEntryID );	if (hr)	   strcpy(szErrorMsg,"lpSearchFolder->GetProps");	MAPI_ASSERT_EX(hr);		ULONG ulConnection;	hr = lpMDB->Advise( lpSearchFolderEntryID->Value.bin.cb,		(LPENTRYID)lpSearchFolderEntryID->Value.bin.lpb,		fnevSearchComplete,		lpAdviseSink,	        &ulConnection );	if (hr)	   strcpy(szErrorMsg,"lpMDB->Advise");	MAPI_ASSERT_EX(hr);	//Obtain the EntryID of the IPM SUBTREE.	LPSPropValue	lpspvParentEID = NULL;	hr = HrGetOneProp(l      (pMDB, PR_IPM_SUBTREE_ENTRYID, &lpspvParentEID);	MAPI_ASSERT_EX(hr);		// Set the search criteria for the folder.	propStore.ulPropTag	= PR_SUBJECT;	propStore.Value.lpszA	= "Test";	propStore.dwAlignPad	= 0;	sRes.rt = RES_PROPERTY;	sRes.res.resProperty.relop = RELOP_EQ;	sRes.res.resProperty.ulPropTag	= PR_SUBJECT;	sRes.res.resProperty.lpProp = &propStore;	// Set the LPENTRYLIST for the SetSearchCriteria call.	LPENTRYLIST lpEntryList = NULL;	MAPIAllocateBuffer(sizeof(ENTRYLIST), (void**)&lpEntryList);	lpEntryList->cValues    = 1;	lpEntryList->lpbin = &lpspvParentEID->Value.bin;	// Set the search criteria on the folder.	hr = lpSearchFolder->SetSearchCriteria(&sRes, lpEntryList,                    RESTART_SEARCH | RECURSIVE_SEARCH |FOREGROUND_SEARCH );	MAPI_ASSERT_EX(hr);	printf("\nWaiting for Search to Complete...");				//Process the messages so that the notification is sent, and then begin the search.	MSG msg;		while (GetMessage(&msg, NULL, 0 ,0))			{				TranslateMessage(&msg);				DispatchMessage(&msg);				if (fSearchCompleted)					break;				Sleep(3000);			}					printf("\nDone Waiting!!!\n");	// Obtain the contents table of the Search folder.	LPMAPITABLE lptFoundMsgs = NULL;		hr = lpSearchFolder->GetContentsTable(NULL, &lptFoundMsgs);	MAPI_ASSERT_EX(hr);	// This is for debugging.	SHOWTABLE(lptFoundMsgs);	// Set a restriction on the columns, and then call FindRow.	// Restrict the columns to what you require.	SizedSPropTagArray(3, tagFoundMsgs) = 	{		3, PR_ENTRYID, PR_SUBJECT, PR_SENDER_NAME	};	hr = lptFoundMsgs->SetColumns((LPSPropTagArray)&tagFoundMsgs, NULL);	MAPI_ASSERT_EX(hr);	// Create a restriction, and then call FindRow. 	propStore.ulPropTag	= PR_SUBJECT;	propStore.Value.lpszA	= "Test";	propStore.dwAlignPad	= 0;	sRes.rt = RES_PROPERTY;	sRes.res.resProperty.relop	= RELOP_EQ;	sRes.res.resProperty.ulPropTag	= PR_SUBJECT;	sRes.res.resProperty.lpProp	= &propStore;		hr = lptFoundMsgs->FindRow(&sRes, BOOKMARK_BEGINNING, 0);	MAPI_ASSERT_EX(hr);	SHOWTABLE(lptFoundMsgs);///////////////////////// Search Complete //////////// 		// Release the session.	lpSession->Logoff(0,MAPI_LOGOFF_UI,0);	lpSession->Release();	MAPIUninitialize();}LONGSTDAPICALLTYPE SearchCompleteCallBack(	LPVOID          lpvContext,	ULONG           cNotif,	LPNOTIFICATION  lpNotif){	BOOL	*pfSearchCompleted = (BOOL*)lpvContext;	printf("\nSearch Complete (in callback)\n");	*pfSearchCompleted = TRUE;		return SUCCESS_SUCCESS;}				
This code uses both the MAPI_ASSERT_EX and SHOWTABLE macros. For additional information, click the article number below to view the article in the Microsoft Knowledge Base:
177542 FILE: Mapiasst.exe: MAPI ASSERT Debug Routines
Both the MAPI_ASSERT_EX and SHOWTABLE macros require the Mapi132.lib file.

Note The sample code uses a Sleep() call to make the search run faster. In Outlook 2013, this Sleep() call has no effect. Therefore, Outlook 2013 searches may run slower than searches in earlier versions of Outlook. To work around this problem, keep Outlook open while you run the search.
Atribuudid

Artikli ID: 260322 – viimati läbi vaadatud: 04/28/2015 18:49:00 – redaktsioon: 2.0

Microsoft Office Outlook 2007, Microsoft Messaging Application Programming Interface

  • kbhowto kbmsg KB260322
Tagasiside