You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
517 lines
11 KiB
517 lines
11 KiB
/*
|
|
* 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
|
|
|