How To Copy LPSRowSet from MAPI Memory to System Memory (247371)



The information in this article applies to:

  • Microsoft Extended Messaging Application Programming Interface (MAPI)

This article was previously published under Q247371

SUMMARY

Using Extended MAPI, a call to MAPIUninitialize cleans up memory that has been allocated with MAPIAllocateBuffer and MAPIAllocateMore. In order to retain this data to be used after MAPIUninitialize is called, this data needs to be copied out of MAPI memory and over into system memory. This sample illustrates how you can copy a LPSRowSet over to system memory.

MORE INFORMATION

The LPSRowSet in this sample has been created with a call to HrQueryAllRows which uses MAPIAllocateBuffer and MAPIAllocateMore.

For this illustration, you are only copying over the PR_DISPLAY_NAME and PR_ENTRYID properties in the LPSRowSet. There may be additional properties that need to be added depending on the LPSRowSet that is being copied.

After the call to MAPIUninitilize, the new structure (lpHopeRows) is still available and can be used by the rest of the program. Cleanup code should also be included to delete the new structure when finished.
#include <mapix.h>
#include "mapidefs.h"  
#include <mapiutil.h>
#include <mapitags.h>
#include <mapioid.h>
#include <edkmdb.h>

#define	INITGUID
#include <initguid.h>
#include <mapiguid.h>
#include <edkguid.h>
#include <stdio.h>

#pragma comment(lib, "mapi32.lib")

HRESULT QueryEntryID(LPMAPITABLE, ULONG, LPSTR, LPSPropValue*);

int main(int argc, char* argv[])
{
        HRESULT         hr              = NULL;	
        LPMAPISESSION   lpSession       = NULL;
        LPMDB           lpMDB           = NULL;

        LPMAPITABLE     lpContentsTbl   = NULL;
        ULONG           ulCount         = NULL;
        LPSRowSet       lpRows          = NULL;

        //Variables for initiating the Address Book
        ULONG           ulObjType       = NULL;
        LPADRBOOK       lpAdrBook       = NULL;
        LPMAPITABLE     lpTable         = NULL;
        LPSPropValue    lpProp          = NULL;
        LPABCONT        lpABCont        = NULL;
        LPABCONT        lpABOut         = NULL;

        SizedSPropTagArray(2, TypeColumns) = {2, {PR_DISPLAY_NAME, PR_ENTRYID}};

        ULONG           ulSRowCount     = 0;
        ULONG           ulPropCount     = 0;
        ULONG           ulSizeOfSet     = 0;
        ULONG           ulTempSizeofBuffer  = 0;

        LPSPropValue    lpOldTempProp   = NULL;
        LPSPropValue    lpNewTempProp   = NULL;

        LPSRowSet       lpHopeRows      = NULL;
        void *          pv              = NULL;

	
        hr = MAPIInitialize(NULL);

        hr = MAPILogonEx(NULL,
                         NULL,
                         NULL,
                         MAPI_NEW_SESSION | MAPI_LOGON_UI,
                         &lpSession);

        hr = lpSession->OpenAddressBook(NULL,
                                        NULL,
                                        NULL,
                                        &lpAdrBook);
	
        //Code to open up the folders in the address book	
        hr = lpAdrBook->OpenEntry(0,
                                  NULL,
                                  NULL,
                                  MAPI_DEFERRED_ERRORS,
                                  &ulObjType,
                                  (LPUNKNOWN*)&lpABCont);

        hr = lpABCont->GetHierarchyTable(CONVENIENT_DEPTH | MAPI_DEFERRED_ERRORS, &lpTable);

        //Custom function QueryEntryID takes a IMAPITABLE, Column to search on, Value to Equal, 
        // and returns a LPSPropValue with the EntryID as the result.
        hr = QueryEntryID(lpTable,
                          PR_DISPLAY_NAME,
                          "Global Address List",
                          (LPSPropValue*)&lpProp);
	
        hr = lpAdrBook->OpenEntry(lpProp->Value.bin.cb,
                                  (LPENTRYID)lpProp->Value.bin.lpb,
                                  NULL,
                                  MAPI_MODIFY,
                                  &ulObjType,
                                  (LPUNKNOWN*)&lpABOut);

        hr = lpABOut->GetContentsTable(NULL, &lpContentsTbl);
	
        // Position to the beginning of the contents table.
        hr = lpContentsTbl->SeekRow(BOOKMARK_BEGINNING, 0, NULL) ;

        //Find out how many rows are in the table
        hr = lpContentsTbl->GetRowCount(0, &ulCount);

       hr = lpContentsTbl->SetColumns((SPropTagArray*)&TypeColumns, 0);

       //Use QueryRows to gather the first 50 rows in the ContentsTable
        hr = lpContentsTbl->QueryRows(50, TBL_NOADVANCE, &lpRows);

        //Build a new LPSRowSet using malloc to persist after MAPIUninitialize.
    
        ulSizeOfSet = CbSRowSet(lpRows);
        pv = malloc ((size_t)ulSizeOfSet) ;
        lpHopeRows = (LPSRowSet)pv ;
        memcpy (lpHopeRows, lpRows, ulSizeOfSet) ;

        for(ulSRowCount = 0; ulSRowCount < lpRows->cRows; ulSRowCount++)
	{
             lpHopeRows->aRow[ulSRowCount].lpProps = (LPSPropValue)malloc(lpRows->aRow[ulSRowCount].cValues*sizeof(SPropValue));

		for(ulPropCount = 0;
			ulPropCount < lpRows->aRow[ulSRowCount].cValues;
			ulPropCount++)
		{
			lpOldTempProp = lpRows->aRow[ulSRowCount].lpProps;
			lpNewTempProp = lpHopeRows->aRow[ulSRowCount].lpProps;
			
			//Copy over the LPSPropValue structure for this property
			ulSizeOfSet = sizeof(SPropValue);
			memcpy(&lpNewTempProp[ulPropCount], &lpOldTempProp[ulPropCount], ulSizeOfSet);

			switch(lpOldTempProp[ulPropCount].ulPropTag)
			{
				//If the prop tag is a string or a binary, you must copy the string data over 
				//and change the pointer in the 
				//LPSPropValue to point to the new string location.
				case PR_DISPLAY_NAME:
					ulTempSizeofBuffer = lstrlen(lpOldTempProp[ulPropCount].Value.lpszA) + 1;
					pv = malloc(ulTempSizeofBuffer);
					
					if (IsBadWritePtr(pv, ulTempSizeofBuffer))
					{
						OutputDebugString("Bad Write Location in new LPS Structure.");
						break;
					}

					lstrcpy ((LPSTR)pv, lpOldTempProp[ulPropCount].Value.lpszA) ;
					lpNewTempProp[ulPropCount].Value.lpszA = (LPSTR)pv;
					break;

				case PR_ENTRYID:
					pv = malloc((size_t)lpOldTempProp[ulPropCount].Value.bin.cb);

					if (IsBadWritePtr(pv, lpOldTempProp[ulPropCount].Value.bin.cb))
					{
						OutputDebugString("Bad Write Location in new LPS Structure.");
						break;
					}	

					memcpy ((LPBYTE)pv, lpOldTempProp[ulPropCount].Value.bin.lpb, lpOldTempProp[ulPropCount].Value.bin.cb);
					lpNewTempProp[ulPropCount].Value.bin.lpb = (LPBYTE)pv;
					break;

				default:
					break;
			}
		}
		
	}

//Cleanup:
	
	FreeProws(lpRows);

	if(lpABOut) lpABOut->Release();
	if(lpABCont) lpABCont->Release();
	MAPIFreeBuffer(lpProp);
	if(lpTable) lpTable->Release();
	if(lpAdrBook) lpAdrBook->Release();
	
	if(lpContentsTbl) lpContentsTbl->Release();
	if(lpMDB) lpMDB->Release();
	if(lpSession)
	{
		lpSession->Logoff(NULL, NULL, NULL);
		lpSession->Release();
	}

	MAPIUninitialize();

	//The new SRowSet (lpHopeRows) is still available and can be used and cleaned up when you want.

         printf("lpHopeRows cRows: %d\n", lpHopeRows->cRows);
	
	for(ulSRowCount = 0; ulSRowCount < lpHopeRows->cRows; ulSRowCount++)
	{
		for(ulPropCount = 0;
			ulPropCount < lpHopeRows->aRow[ulSRowCount].cValues;
			ulPropCount++)
		{
			switch(lpHopeRows->aRow[ulSRowCount].lpProps[ulPropCount].ulPropTag)
			{
				case PR_DISPLAY_NAME:
					printf("DisplayName: %s\n", lpHopeRows->aRow[ulSRowCount].lpProps[ulPropCount].Value.lpszA);
					break;
				default:
					break;
			}
		}
		
	}

	return hr;
}

//Custom function QueryEntryID takes a IMAPITABLE, Column to search on, Value to Equal, 
// and returns a LPSPropValue with the EntryID as the result.
HRESULT QueryEntryID(LPMAPITABLE lpTable, ULONG lpDesc, LPSTR lpValue, LPSPropValue* lppProp)
{

	SizedSPropTagArray(2, TypeColumns) =	{2, {lpDesc, PR_ENTRYID}};
	SRestriction srName;
	SPropValue spv;
	ULONG ulCount = 0;
	LPSRowSet pRows = NULL;
	LPSPropValue pspvRet = NULL; 

	HRESULT hr;

	// Restrict the table to just it's name and ID
	hr = lpTable->SetColumns((LPSPropTagArray)&TypeColumns, 0);
	if(FAILED(hr))
	{
		OutputDebugString("SetColumns Failed\n");
		goto cleanup;
	}

	// Get the EntryID of the Address folder that you are going to work with
	// Build a restriction to find the EntryID
	srName.rt = RES_PROPERTY;
	srName.res.resProperty.relop = RELOP_EQ;
	srName.res.resProperty.ulPropTag = lpDesc;
	srName.res.resProperty.lpProp = &spv;
	spv.ulPropTag = lpDesc;
	spv.Value.lpszA = lpValue;	// Name of Template ID you want (passed into function)
	
	// Apply the restriction
	hr = lpTable->Restrict(&srName,0);
	if(FAILED(hr))
	{
		OutputDebugString("Restrict Failed\n");
		goto cleanup;
	}

	// Get the total number of rows returned. Typically, this will be 1.
	hr = lpTable->GetRowCount(0,&ulCount);
	if(FAILED(hr))
	{
		OutputDebugString("GetRowCount Failed\n");
		goto cleanup;
	}

	// Get the row props (trying to get the EntryID)
	hr = lpTable->QueryRows(ulCount,0,&pRows);
	if(FAILED(hr))
	{
		OutputDebugString("QueryRows Failed\n");
		goto cleanup;
	}

	hr = MAPIAllocateBuffer(sizeof(SPropValue), (LPVOID*)&pspvRet);
	if(FAILED(hr))
	{
		OutputDebugString("MAPIAllocateBuffer Failed\n");
		MAPIFreeBuffer(pspvRet);
		goto cleanup;
	}

	hr = MAPIAllocateMore(pRows->aRow[0].lpProps[1].Value.bin.cb, pspvRet, (LPVOID*)&pspvRet->Value.bin.lpb);
	if(FAILED(hr))
	{
		OutputDebugString("MAPIAllocateMore Failed\n");
		MAPIFreeBuffer(pspvRet);
		goto cleanup;
	}

	pspvRet->ulPropTag = pRows->aRow[0].lpProps[1].ulPropTag;
	pspvRet->Value.bin.cb = pRows->aRow[0].lpProps[1].Value.bin.cb;

	memcpy(pspvRet->Value.bin.lpb,
		   pRows->aRow[0].lpProps[1].Value.bin.lpb,
		   pRows->aRow[0].lpProps[1].Value.bin.cb);
	
	// Get a pointer to the props.
	*lppProp = pspvRet;

cleanup:
	FreeProws(pRows);

	return hr;
}
				

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