/* * MAPI 1.0 property handling routines * * * MAPIUTIL.C - * * Useful routines for manipulating and comparing property values continued * The difference between this file and proputil.c is that this file doesn't require * any c-runtimes. */ #include <_apipch.h> #ifndef MB_SETFOREGROUND #define MB_SETFOREGROUND 0 #endif STDAPI_(BOOL) FEqualNames(LPMAPINAMEID lpName1, LPMAPINAMEID lpName2) { AssertSz(lpName1 && !IsBadReadPtr(lpName1, sizeof(MAPINAMEID)), TEXT("lpName1 fails address check")); AssertSz(lpName2 && !IsBadReadPtr(lpName2, sizeof(MAPINAMEID)), TEXT("lpName2 fails address check")); // // Same ptr case - optimization if (lpName1 == lpName2) return TRUE; if (memcmp(lpName1->lpguid, lpName2->lpguid, sizeof(GUID))) return FALSE; if (lpName1->ulKind == lpName2->ulKind) { if (lpName1->ulKind == MNID_STRING) { if (!lstrcmpW(lpName1->Kind.lpwstrName, lpName2->Kind.lpwstrName)) { return TRUE; } } else { if (lpName1->Kind.lID == lpName2->Kind.lID) { return TRUE; } } } return FALSE; } /* * IsBadBoundedStringPtr * * Like IsBadStringPtr, but guarantees in addition that there is a * valid string which will fit in a buffer of cchMax characters. */ BOOL WINAPI EXPORT_16 IsBadBoundedStringPtr(const void FAR *lpsz, UINT cchMax) { if (IsBadStringPtr(lpsz, (UINT) -1) || ((UINT) lstrlenA(lpsz) >= cchMax)) return TRUE; return FALSE; } /* * For now, internal to HrQueryAllRows. * * Merges prows with *pprowsDst, reallocating *pprowsDst if * necessary. Destroys the container portion of prows (but not the * individual rows it contains). */ HRESULT // STDAPI HrMergeRowSets(LPSRowSet prows, LPSRowSet FAR *pprowsDst) { SCODE sc = S_OK; LPSRowSet prowsT; UINT crowsSrc; UINT crowsDst; Assert(!IsBadWritePtr(pprowsDst, sizeof(LPSRowSet))); Assert(prows); if (!*pprowsDst || (*pprowsDst)->cRows == 0) { // This is easy. But check this case first, because if the // table is completely empty we want to return this. FreeBufferAndNull(pprowsDst); // correct, no '&' *pprowsDst = prows; prows = NULL; // don't free it! goto ret; } if (prows->cRows == 0) { // This is easy too goto ret; } // OK, now we know there are rows in both rowsets. // We have to do a real merge. SideAssert(crowsSrc = (UINT) prows->cRows); crowsDst = (UINT) (*pprowsDst)->cRows; // handle 0 if (FAILED(sc = MAPIAllocateBuffer(CbNewSRowSet(crowsSrc + crowsDst), &prowsT))) goto ret; if (crowsDst) CopyMemory(prowsT->aRow, (*pprowsDst)->aRow, crowsDst*sizeof(SRow)); CopyMemory(&prowsT->aRow[crowsDst], prows->aRow, crowsSrc*sizeof(SRow)); prowsT->cRows = crowsSrc + crowsDst; FreeBufferAndNull(pprowsDst); // correct, no '&' *pprowsDst = prowsT; ret: FreeBufferAndNull(&prows); DebugTraceSc(HrMergeRowSets, sc); return ResultFromScode(sc); } /* - HrQueryAllRows - * Purpose: * Retrieves all rows from an IMAPITable interface up to a set * maximum. It will optionally set the column set, sort order, * and restriction on the table before querying. * * If the table is empty, an SRowSet with zero rows is * returned (just like QueryRows). * * The seek position of the table is undefined both before and * after this call. * * If the function fails with an error other than * MAPI_E_NOT_ENOUGH_MEMORY, extended error information is * available through the table interface. * * Arguments: * ptable in the table interface to query * ptaga in if not NULL, column set for the table * pres in if not NULL, restriction to be applied * psos in if not NULL, sort order to be applied * crowsMax in if nonzero, limits the number of rows * to be returned. * pprows out all rows of the table * * Returns: * HRESULT. Extended error information normally is in the * table. * * Side effects: * Seek position of table is undefined. * * Errors: * MAPI_E_TABLE_TOO_BIG if the table contains more than * cRowsMax rows. */ STDAPI HrQueryAllRows(LPMAPITABLE ptable, LPSPropTagArray ptaga, LPSRestriction pres, LPSSortOrderSet psos, LONG crowsMax, LPSRowSet FAR *pprows) { HRESULT hr; LPSRowSet prows = NULL; UINT crows = 0; LPSRowSet prowsT; UINT crowsT; #if !defined(DOS) // Why have we commented out the check for PARAMETER_VALIDATION? --gfb //#ifdef PARAMETER_VALIDATION if (FBadUnknown(ptable)) { DebugTraceArg(HrQueryAllRows, TEXT("ptable fails address check")); goto badArg; } if (ptaga && FBadColumnSet(ptaga)) { DebugTraceArg(HrQueryAllRows, TEXT("ptaga fails address check")); goto badArg; } if (pres && FBadRestriction(pres)) { DebugTraceArg(HrQueryAllRows, TEXT("pres fails address check")); goto badArg; } if (psos && FBadSortOrderSet(psos)) { DebugTraceArg(HrQueryAllRows, TEXT("psos fails address check")); goto badArg; } if (IsBadWritePtr(pprows, sizeof(LPSRowSet))) { DebugTraceArg(HrQueryAllRows, TEXT("pprows fails address check")); goto badArg; } //#endif #endif *pprows = NULL; // Set up the table, if the corresponding setup parameter // is present. if (ptaga && HR_FAILED(hr = ptable->lpVtbl->SetColumns(ptable, ptaga, TBL_BATCH))) goto ret; if (pres && HR_FAILED(hr = ptable->lpVtbl->Restrict(ptable, pres, TBL_BATCH))) goto ret; if (psos && HR_FAILED(hr = ptable->lpVtbl->SortTable(ptable, psos, TBL_BATCH))) goto ret; // Set position to beginning of the table. if (HR_FAILED(hr = ptable->lpVtbl->SeekRow(ptable, BOOKMARK_BEGINNING, 0, NULL))) goto ret; if (crowsMax == 0) crowsMax = LONG_MAX; for (;;) { prowsT = NULL; // Retrieve some rows. Ask for the limit. hr = ptable->lpVtbl->QueryRows(ptable, crowsMax, 0, &prowsT); if (HR_FAILED(hr)) { // Note: the failure may actually have happened during // one of the setup calls, since we set TBL_BATCH. goto ret; } Assert(prowsT->cRows <= UINT_MAX); crowsT = (UINT) prowsT->cRows; // Did we get more rows than caller can handle? if ((LONG) (crowsT + (prows ? prows->cRows : 0)) > crowsMax) { hr = ResultFromScode(MAPI_E_TABLE_TOO_BIG); FreeProws(prowsT); goto ret; } // Add the rows just retrieved into the set we're building. // Note: this handles boundary conditions including either // row set is empty. if (HR_FAILED(hr = HrMergeRowSets(prowsT, &prows))) goto ret; // NOTE: the merge destroys prowsT. // Did we hit the end of the table? // Unfortunately, we have to ask twice before we know. if (crowsT == 0) break; } *pprows = prows; ret: if (HR_FAILED(hr)) FreeProws(prows); DebugTraceResult(HrGetAllRows, hr); return hr; #if !defined(DOS) badArg: #endif return ResultFromScode(MAPI_E_INVALID_PARAMETER); } #ifdef WIN16 // Imported inline function /* * IListedPropID * * Purpose * If a tag with ID == PROP_ID(ulPropTag) is listed in lptaga then * the index of tag is returned. If the tag is not in lptaga then * -1 is returned. * * Arguments * ulPropTag Property tag to locate. * lptaga Property tag array to search. * * Returns TRUE or FALSE */ LONG IListedPropID( ULONG ulPropTag, LPSPropTagArray lptaga) { ULONG FAR *lpulPTag; /* No tag is contained in a NULL list of tags. */ if (!lptaga) { return -1; } /* Mutate ulPropTag to just a PROP_ID. */ ulPropTag = PROP_ID(ulPropTag); for ( lpulPTag = lptaga->aulPropTag + lptaga->cValues ; --lpulPTag >= lptaga->aulPropTag ; ) { /* Compare PROP_ID's. */ if (PROP_ID(*lpulPTag) == ulPropTag) { return (lpulPTag - lptaga->aulPropTag); } } return -1; } /* * FListedPropID * * Purpose * Determine if a tag with ID == PROP_ID(ulPropTag) is listed in lptaga. * * Arguments * ulPropTag Property tag to locate. * lptaga Property tag array to search. * * Returns TRUE or FALSE */ BOOL FListedPropID( ULONG ulPropTag, LPSPropTagArray lptaga) { ULONG FAR *lpulPTag; /* No tag is contained in a NULL list of tags. */ if (!lptaga) { return FALSE; } /* Mutate ulPropTag to just a PROP_ID. */ ulPropTag = PROP_ID(ulPropTag); for ( lpulPTag = lptaga->aulPropTag + lptaga->cValues ; --lpulPTag >= lptaga->aulPropTag ; ) { /* Compare PROP_ID's. */ if (PROP_ID(*lpulPTag) == ulPropTag) { return TRUE; } } return FALSE; } /* * FListedPropTAG * * Purpose * Determine if a the given ulPropTag is listed in lptaga. * * Arguments * ulPropTag Property tag to locate. * lptaga Property tag array to search. * * Returns TRUE or FALSE */ BOOL FListedPropTAG( ULONG ulPropTag, LPSPropTagArray lptaga) { ULONG FAR *lpulPTag; /* No tag is contained in a NULL list of tags. */ if (!lptaga) { return FALSE; } /* Compare the entire prop tag to be sure both ID and TYPE match */ for ( lpulPTag = lptaga->aulPropTag + lptaga->cValues ; --lpulPTag >= lptaga->aulPropTag ; ) { /* Compare PROP_ID's. */ if (PROP_ID(*lpulPTag) == ulPropTag) { return TRUE; } } return FALSE; } /* * AddProblem * * Purpose * Adds a problem to the next available entry of a pre-allocated problem * array. * The pre-allocated problem array must be big enough to have another * problem added. The caller is responsible for making sure this is * true. * * Arguments * lpProblems Pointer to pre-allocated probelem array. * ulIndex Index into prop tag/value array of the problem property. * ulPropTag Prop tag of property which had the problem. * scode Error code to list for the property. * * Returns TRUE or FALSE */ VOID AddProblem( LPSPropProblemArray lpProblems, ULONG ulIndex, ULONG ulPropTag, SCODE scode) { if (lpProblems) { Assert( !IsBadWritePtr( lpProblems->aProblem + lpProblems->cProblem , sizeof(SPropProblem))); lpProblems->aProblem[lpProblems->cProblem].ulIndex = ulIndex; lpProblems->aProblem[lpProblems->cProblem].ulPropTag = ulPropTag; lpProblems->aProblem[lpProblems->cProblem].scode = scode; lpProblems->cProblem++; } } BOOL FIsExcludedIID( LPCIID lpiidToCheck, LPCIID rgiidExclude, ULONG ciidExclude) { /* Check the obvious (no exclusions). */ if (!ciidExclude || !rgiidExclude) { return FALSE; } /* Check each iid in the list of exclusions. */ for (; ciidExclude; rgiidExclude++, ciidExclude--) { // if (IsEqualGUID( lpiidToCheck, rgiidExclude)) if (!memcmp( lpiidToCheck, rgiidExclude, sizeof(MAPIUID))) { return TRUE; } } return FALSE; } /* * Error/Warning Alert Message Boxes */ int AlertIdsCtx( HWND hwnd, HINSTANCE hinst, UINT idsMsg, LPSTR szComponent, ULONG ulContext, ULONG ulLow, UINT fuStyle); int AlertIds(HWND hwnd, HINSTANCE hinst, UINT idsMsg, UINT fuStyle) { return AlertIdsCtx(hwnd, hinst, idsMsg, NULL, 0, 0, fuStyle); } int AlertSzCtx( HWND hwnd, LPSTR szMsg, LPSTR szComponent, ULONG ulContext, ULONG ulLow, UINT fuStyle); int AlertSz(HWND hwnd, LPSTR szMsg, UINT fuStyle) { return AlertSzCtx(hwnd, szMsg, NULL, 0, 0, fuStyle); } #endif // WIN16