How To Search Folders with the SetSearchCriteria Method (260322)



The information in this article applies to:

  • Microsoft Extended Messaging Application Programming Interface (MAPI)

This article was previously published under Q260322

SUMMARY

This article demonstrates how to programmatically search for specific messages when you apply restrictions on the message store or generic folder.

MORE INFORMATION

The following are issues to consider 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 demonstrates how to search messages using Messaging Application Programming Interface (MAPI) messaging functions:
#include <mapix.h>
#include <mapiutil.h>
#include "MAPIASST.H"

LONG
STDAPICALLTYPE 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 the
SetSearchCriteria 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();
}


LONG
STDAPICALLTYPE 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.

Modification Type:MinorLast Reviewed:8/25/2005
Keywords:kbhowto kbMsg KB260322