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.
1762 lines
48 KiB
1762 lines
48 KiB
/*
|
|
* VALCOPY.C
|
|
*
|
|
* Utility functions for validating, copying, and (yeech) relocating
|
|
* complex MAPI structures.
|
|
*
|
|
* For each data type there are three functions:
|
|
* ScCountXXX address-checks and calculates the size
|
|
* ScCopyXXX copies to a contiguous block of memory, which
|
|
* must be pre-allocated
|
|
* ScRelocXXX adjusts pointers, assuming that a structure in a
|
|
* contiguous block of memory has been moved
|
|
*
|
|
* Data types supported:
|
|
* NOTIFICATION (and array of), in ScCountNotifications etc.
|
|
* SPropValue (and array of), in ScCountProps etc.
|
|
*
|
|
* //$ SIZE Returning the byte count from ScRelocXXX may not be necessary.
|
|
*/
|
|
|
|
#include <_apipch.h>
|
|
|
|
|
|
|
|
#if defined (_AMD64_) || defined (_IA64_)
|
|
#define AlignProp(_cb) Align8(_cb)
|
|
#else
|
|
#define AlignProp(_cb) (_cb)
|
|
#endif
|
|
|
|
#define ALIGN_RISC 8
|
|
#define ALIGN_X86 1
|
|
|
|
|
|
// Pointer manipulation macros for use in the Reloc functions
|
|
#ifdef WIN16
|
|
#define SEG(_fp) HIWORD((DWORD)_fp)
|
|
#define OFF(_fp) LOWORD((DWORD)_fp)
|
|
|
|
#define PvRelocPv(_p,_baseOld,_baseNew) \
|
|
((LPVOID)MAKELONG(OFF(_p) - OFF(_baseOld) + OFF(_baseNew), SEG(_baseNew)))
|
|
#else
|
|
#define PvRelocPv(_p,_baseOld,_baseNew) \
|
|
((LPVOID)((LPBYTE)(_p) - (LPBYTE)(_baseOld) + (LPBYTE)(_baseNew)))
|
|
#endif
|
|
|
|
|
|
#ifdef NOTIFICATIONS // save this for notifications
|
|
STDAPI_(SCODE)
|
|
ScCountNotifications(int cntf, LPNOTIFICATION rgntf, ULONG FAR *pcb)
|
|
{
|
|
ULONG cb;
|
|
ULONG cbT;
|
|
LPNOTIFICATION pntf;
|
|
SCODE sc = S_OK;
|
|
|
|
// validate parameters
|
|
|
|
AssertSz(!cntf || !IsBadReadPtr(rgntf, sizeof(NOTIFICATION) * cntf),
|
|
TEXT("rgntf fails address check"));
|
|
|
|
AssertSz(!pcb || !IsBadWritePtr(pcb, sizeof(ULONG)),
|
|
TEXT("pcb fails address check"));
|
|
|
|
for (cb = 0, pntf = rgntf; cntf--; ++pntf)
|
|
{
|
|
if (IsBadReadPtr(pntf, sizeof(NOTIFICATION)))
|
|
{
|
|
DebugTraceArg(ScCountNotification, TEXT("pntf fails address check"));
|
|
goto badNotif;
|
|
}
|
|
cb += sizeof(NOTIFICATION);
|
|
|
|
switch (HIWORD(pntf->ulEventType))
|
|
{
|
|
case (fnevExtended >> 16):
|
|
// case (fnevSpooler >> 16):
|
|
// fnevSpooler and fnevExtended both use the EXTENDED_NOTIFICATION
|
|
// structure for their parameters
|
|
if (pntf->info.ext.cb &&
|
|
IsBadReadPtr(pntf->info.ext.pbEventParameters, (UINT)pntf->info.ext.cb))
|
|
{
|
|
DebugTraceArg(ScCountNotification, TEXT("ext.pbEventParameters fails address check"));
|
|
goto badNotif;
|
|
}
|
|
cb += AlignProp(pntf->info.ext.cb);
|
|
break;
|
|
|
|
case 0:
|
|
{
|
|
switch (LOWORD(pntf->ulEventType))
|
|
{
|
|
case (USHORT)fnevCriticalError:
|
|
{
|
|
ERROR_NOTIFICATION FAR *perr = &pntf->info.err;
|
|
|
|
if ( IsBadReadPtr( perr->lpEntryID, (UINT)perr->cbEntryID ) )
|
|
{
|
|
DebugTraceArg( ScCountNotification, TEXT("lpEntryID fails address check") );
|
|
goto badNotif;
|
|
}
|
|
|
|
cb += AlignProp(((UINT)perr->cbEntryID));
|
|
|
|
if (perr->lpMAPIError)
|
|
{
|
|
cb += AlignProp(sizeof( MAPIERROR ));
|
|
|
|
#if defined(_WINNT) && !defined(MAC)
|
|
if (perr->ulFlags & MAPI_UNICODE)
|
|
{
|
|
//$ No error check in WIN16
|
|
if (IsBadStringPtrW((LPWSTR)perr->lpMAPIError->lpszError, INFINITE))
|
|
{
|
|
DebugTraceArg(ScCountNotification, TEXT("err.MapiError.lpszError (UNICODE) fails address check"));
|
|
goto badNotif;
|
|
}
|
|
|
|
cb += AlignProp(((lstrlenW((LPWSTR)perr->lpMAPIError->lpszError) + 1)
|
|
* sizeof(WCHAR)));
|
|
|
|
if ( perr->lpMAPIError->lpszComponent )
|
|
{
|
|
if (IsBadStringPtrW((LPWSTR)perr->lpMAPIError->lpszComponent, INFINITE))
|
|
{
|
|
DebugTraceArg(ScCountNotification, TEXT("err.MapiError.lpszComponent (UNICODE) fails address check"));
|
|
goto badNotif;
|
|
}
|
|
|
|
cb += AlignProp(((lstrlenW((LPWSTR)perr->lpMAPIError->lpszComponent) + 1)
|
|
* sizeof(WCHAR)));
|
|
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
if (IsBadStringPtrA((LPSTR)perr->lpMAPIError->lpszError, INFINITE))
|
|
{
|
|
DebugTraceArg(ScCountNotification, TEXT("err.MapiError.lpszError (ASCII) fails address check"));
|
|
goto badNotif;
|
|
}
|
|
|
|
cb += AlignProp((lstrlenA((LPSTR)perr->lpMAPIError->lpszError) + 1));
|
|
|
|
if ( perr->lpMAPIError->lpszComponent )
|
|
{
|
|
if (IsBadStringPtrA((LPSTR)perr->lpMAPIError->lpszComponent, INFINITE))
|
|
{
|
|
DebugTraceArg(ScCountNotification, TEXT("err.MapiError.lpszError (ASCII) fails address check"));
|
|
goto badNotif;
|
|
}
|
|
|
|
cb += AlignProp((lstrlenA((LPSTR)perr->lpMAPIError->lpszComponent) + 1));
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case (USHORT)fnevNewMail:
|
|
{
|
|
NEWMAIL_NOTIFICATION FAR *pnew = &pntf->info.newmail;
|
|
|
|
if (IsBadReadPtr(pnew->lpEntryID, (UINT)pnew->cbEntryID))
|
|
{
|
|
DebugTraceArg(ScCountNotification, TEXT("lpEntryID fails address check"));
|
|
goto badNotif;
|
|
}
|
|
cb += AlignProp(((UINT)pnew->cbEntryID));
|
|
if (IsBadReadPtr(pnew->lpParentID, (UINT)pnew->cbParentID))
|
|
{
|
|
DebugTraceArg(ScCountNotification, TEXT("lpParentID fails address check"));
|
|
goto badNotif;
|
|
}
|
|
cb += AlignProp(((UINT)pnew->cbParentID));
|
|
if (pnew->lpszMessageClass)
|
|
{
|
|
if (pnew->ulFlags & MAPI_UNICODE)
|
|
{
|
|
#if defined(_WINNT) && !defined(MAC)
|
|
//$ No error check in WIN16
|
|
if (IsBadStringPtrW((LPWSTR)pnew->lpszMessageClass, INFINITE))
|
|
{
|
|
DebugTraceArg(ScCountNotification, TEXT("newmail.lpszMessageClass (UNICODE) fails address check"));
|
|
goto badNotif;
|
|
}
|
|
#endif
|
|
cb += AlignProp(((lstrlenW((LPWSTR)pnew->lpszMessageClass) + 1)
|
|
* sizeof(WCHAR)));
|
|
}
|
|
else
|
|
{
|
|
if (IsBadStringPtrA((LPSTR)pnew->lpszMessageClass, INFINITE))
|
|
{
|
|
DebugTraceArg(ScCountNotification, TEXT("newmail.lpszMessageClass (ASCII) fails address check"));
|
|
goto badNotif;
|
|
}
|
|
cb += AlignProp((lstrlenA((LPSTR)pnew->lpszMessageClass) + 1));
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case (USHORT)fnevObjectCreated:
|
|
case (USHORT)fnevObjectDeleted:
|
|
case (USHORT)fnevObjectModified:
|
|
case (USHORT)fnevObjectMoved:
|
|
case (USHORT)fnevObjectCopied:
|
|
case (USHORT)fnevSearchComplete:
|
|
{
|
|
OBJECT_NOTIFICATION FAR *pobj = &pntf->info.obj;
|
|
|
|
if (pobj->cbEntryID)
|
|
{
|
|
if (IsBadReadPtr(pobj->lpEntryID, (UINT)pobj->cbEntryID))
|
|
{
|
|
DebugTraceArg(ScCountNotifications, TEXT("obj.lpEntryID fails address check"));
|
|
goto badNotif;
|
|
}
|
|
cb += AlignProp(pobj->cbEntryID);
|
|
}
|
|
if (pobj->cbParentID)
|
|
{
|
|
if (IsBadReadPtr(pobj->lpParentID, (UINT)pobj->cbParentID))
|
|
{
|
|
DebugTraceArg(ScCountNotifications, TEXT("obj.lpParentID fails address check"));
|
|
goto badNotif;
|
|
}
|
|
cb += AlignProp(pobj->cbParentID);
|
|
}
|
|
if (pobj->cbOldID)
|
|
{
|
|
if (IsBadReadPtr(pobj->lpOldID, (UINT)pobj->cbOldID))
|
|
{
|
|
DebugTraceArg(ScCountNotifications, TEXT("obj.lpOldID fails address check"));
|
|
goto badNotif;
|
|
}
|
|
cb += AlignProp(pobj->cbOldID);
|
|
}
|
|
if (pobj->cbOldParentID)
|
|
{
|
|
if (IsBadReadPtr(pobj->lpOldParentID, (UINT)pobj->cbOldParentID))
|
|
{
|
|
DebugTraceArg(ScCountNotifications, TEXT("obj.lpOldParentID fails address check"));
|
|
goto badNotif;
|
|
}
|
|
cb += AlignProp(pobj->cbOldParentID);
|
|
}
|
|
if (pobj->lpPropTagArray)
|
|
{
|
|
if (IsBadReadPtr(pobj->lpPropTagArray, sizeof(ULONG)) ||
|
|
IsBadReadPtr(pobj->lpPropTagArray,
|
|
offsetof(SPropTagArray, aulPropTag) +
|
|
(UINT)pobj->lpPropTagArray->cValues * sizeof(ULONG)))
|
|
{
|
|
DebugTraceArg(ScCountNotifications, TEXT("obj.lpPropTagArray fails address check"));
|
|
goto badNotif;
|
|
}
|
|
cb += AlignProp(offsetof(SPropTagArray, aulPropTag) +
|
|
pobj->lpPropTagArray->cValues * sizeof(ULONG));
|
|
}
|
|
break;
|
|
}
|
|
|
|
case (USHORT)fnevTableModified:
|
|
{
|
|
TABLE_NOTIFICATION FAR *ptn = &pntf->info.tab;
|
|
UINT n = (UINT) ptn->ulTableEvent;
|
|
|
|
if (n != TABLE_CHANGED &&
|
|
n != TABLE_RELOAD &&
|
|
n != TABLE_ERROR &&
|
|
n != TABLE_ROW_ADDED &&
|
|
n != TABLE_ROW_DELETED &&
|
|
n != TABLE_ROW_MODIFIED &&
|
|
n != TABLE_SORT_DONE &&
|
|
n != TABLE_RESTRICT_DONE &&
|
|
n != TABLE_SETCOL_DONE)
|
|
{
|
|
DebugTraceArg(ScCountNotifications, TEXT("invalid tab.ulTableEvent"));
|
|
goto badNotif;
|
|
}
|
|
|
|
if (ptn->propIndex.ulPropTag)
|
|
{
|
|
if (sc = ScCountProps(1, &ptn->propIndex, &cbT))
|
|
goto ret;
|
|
cb += cbT;
|
|
}
|
|
if (ptn->propPrior.ulPropTag)
|
|
{
|
|
if (sc = ScCountProps(1, &ptn->propPrior, &cbT))
|
|
goto ret;
|
|
cb += cbT;
|
|
}
|
|
if (ptn->row.cValues)
|
|
{
|
|
if (sc = ScCountProps((int)ptn->row.cValues, ptn->row.lpProps,
|
|
&cbT))
|
|
goto ret;
|
|
cb += cbT;
|
|
}
|
|
else if (ptn->row.lpProps)
|
|
{
|
|
DebugTraceArg(ScCountNotifications, TEXT("non-NULL row.lpProps with zero row.cValues in table notification"));
|
|
goto badNotif;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case (USHORT)fnevStatusObjectModified:
|
|
{
|
|
STATUS_OBJECT_NOTIFICATION FAR *pstat = &pntf->info.statobj;
|
|
|
|
if (pstat->cbEntryID)
|
|
{
|
|
if (IsBadReadPtr(pstat->lpEntryID, (UINT)pstat->cbEntryID))
|
|
{
|
|
DebugTraceArg(ScCountNotifications, TEXT("statobj.lpEntryID fails address check"));
|
|
goto badNotif;
|
|
}
|
|
cb += AlignProp(pstat->cbEntryID);
|
|
}
|
|
if (pstat->cValues)
|
|
{
|
|
if (sc = ScCountProps((int)pstat->cValues,
|
|
pstat->lpPropVals, &cbT))
|
|
goto ret;
|
|
cb += cbT;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
DebugTraceArg(ScCountNotification, TEXT("invalid ulEventType"));
|
|
goto badNotif;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
DebugTraceArg(ScCountNotification, TEXT("invalid ulEventType"));
|
|
goto badNotif;
|
|
}
|
|
}
|
|
|
|
if (pcb)
|
|
*pcb = cb;
|
|
|
|
ret:
|
|
DebugTraceSc(ScCountNotifications, sc);
|
|
return sc;
|
|
|
|
badNotif:
|
|
// trace already issued
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
STDAPI_(SCODE)
|
|
ScCopyNotifications(int cntf, LPNOTIFICATION rgntf, LPVOID pvDst,
|
|
ULONG FAR *pcb)
|
|
{
|
|
LPBYTE pb = pvDst;
|
|
ULONG cb = 0;
|
|
ULONG cbT;
|
|
LPNOTIFICATION pntf;
|
|
LPNOTIFICATION pntfDst;
|
|
SCODE sc = S_OK;
|
|
|
|
// validate parameters
|
|
|
|
AssertSz(!cntf || !IsBadReadPtr(rgntf, sizeof(NOTIFICATION) * cntf),
|
|
TEXT("rgntf fails address check"));
|
|
|
|
AssertSz(!cntf || !IsBadWritePtr(pvDst, sizeof(NOTIFICATION) * cntf),
|
|
TEXT("pvDst fails address check"));
|
|
|
|
AssertSz(!pcb || !IsBadWritePtr(pcb, sizeof(ULONG)),
|
|
TEXT("pcb fails address check"));
|
|
|
|
cb = cntf * sizeof(NOTIFICATION);
|
|
MemCopy(pvDst, rgntf, (UINT)cb);
|
|
pb = (LPBYTE)pvDst + cb;
|
|
|
|
for (pntf = rgntf, pntfDst = (LPNOTIFICATION)pvDst;
|
|
cntf--;
|
|
++pntf, ++pntfDst)
|
|
{
|
|
switch (HIWORD(pntf->ulEventType))
|
|
{
|
|
case (fnevExtended >> 16):
|
|
// case (fnevSpooler >> 16):
|
|
if (pntf->info.ext.cb)
|
|
{
|
|
pntfDst->info.ext.pbEventParameters = pb;
|
|
cbT = pntf->info.ext.cb;
|
|
MemCopy(pb, pntf->info.ext.pbEventParameters, (UINT)cbT);
|
|
pb += AlignProp(cbT);
|
|
cb += AlignProp(cbT);
|
|
}
|
|
break;
|
|
|
|
case 0:
|
|
{
|
|
switch (LOWORD(pntf->ulEventType))
|
|
{
|
|
case (USHORT)fnevCriticalError:
|
|
{
|
|
ERROR_NOTIFICATION FAR *perr = &pntf->info.err;
|
|
|
|
if ( perr->cbEntryID )
|
|
{
|
|
pntfDst->info.err.lpEntryID = (LPENTRYID)pb;
|
|
cbT = perr->cbEntryID;
|
|
MemCopy(pb, perr->lpEntryID, (UINT)cbT);
|
|
pb += AlignProp(cbT);
|
|
cb += AlignProp(cbT);
|
|
}
|
|
|
|
|
|
if ( perr->lpMAPIError )
|
|
{
|
|
pntfDst->info.err.lpMAPIError = (LPMAPIERROR)pb;
|
|
cbT = sizeof(MAPIERROR);
|
|
MemCopy( pb, perr->lpMAPIError, sizeof( MAPIERROR ) );
|
|
pb += AlignProp(cbT);
|
|
cb += AlignProp(cbT);
|
|
|
|
if (perr->lpMAPIError->lpszError)
|
|
{
|
|
#ifdef _WINNT
|
|
if (perr->ulFlags & MAPI_UNICODE)
|
|
{
|
|
cbT = (lstrlenW((LPWSTR)perr->lpMAPIError->lpszError)
|
|
+ 1) * sizeof(WCHAR);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
cbT = lstrlenA((LPSTR)perr->lpMAPIError->lpszError) + 1;
|
|
|
|
}
|
|
|
|
pntfDst->info.err.lpMAPIError->lpszError = (LPSTR)pb;
|
|
MemCopy(pb, perr->lpMAPIError->lpszError, (UINT)cbT);
|
|
pb += AlignProp(cbT);
|
|
cb += AlignProp(cbT);
|
|
}
|
|
|
|
if (perr->lpMAPIError->lpszComponent)
|
|
{
|
|
#ifdef _WINNT
|
|
if (perr->ulFlags & MAPI_UNICODE)
|
|
{
|
|
cbT = (lstrlenW((LPWSTR)perr->lpMAPIError->lpszComponent)
|
|
+ 1) * sizeof(WCHAR);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
cbT = lstrlenA((LPSTR)perr->lpMAPIError->lpszComponent) + 1;
|
|
|
|
}
|
|
|
|
pntfDst->info.err.lpMAPIError->lpszComponent = pb;
|
|
MemCopy(pb, perr->lpMAPIError->lpszComponent, (UINT)cbT);
|
|
pb += AlignProp(cbT);
|
|
cb += AlignProp(cbT);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case (USHORT)fnevNewMail:
|
|
{
|
|
NEWMAIL_NOTIFICATION FAR *pnew = &pntf->info.newmail;
|
|
|
|
if (pnew->cbEntryID)
|
|
{
|
|
pntfDst->info.newmail.lpEntryID = (LPENTRYID)pb;
|
|
cbT = pnew->cbEntryID;
|
|
MemCopy(pb, pnew->lpEntryID, (UINT)cbT);
|
|
pb += AlignProp(cbT);
|
|
cb += AlignProp(cbT);
|
|
}
|
|
|
|
if (pnew->cbParentID)
|
|
{
|
|
pntfDst->info.newmail.lpParentID = (LPENTRYID)pb;
|
|
cbT = pnew->cbParentID;
|
|
MemCopy(pb, pnew->lpParentID, (UINT)cbT);
|
|
pb += AlignProp(cbT);
|
|
cb += AlignProp(cbT);
|
|
}
|
|
|
|
if (pnew->lpszMessageClass)
|
|
{
|
|
if (pnew->ulFlags & MAPI_UNICODE)
|
|
cbT = (lstrlenW((LPWSTR)pnew->lpszMessageClass) + 1)
|
|
* sizeof(WCHAR);
|
|
else
|
|
cbT = lstrlenA((LPSTR)pnew->lpszMessageClass) + 1;
|
|
pntfDst->info.newmail.lpszMessageClass = (LPTSTR)pb;
|
|
MemCopy(pb, pnew->lpszMessageClass, (UINT)cbT);
|
|
pb += AlignProp(cbT);
|
|
cb += AlignProp(cbT);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case (USHORT)fnevObjectCreated:
|
|
case (USHORT)fnevObjectDeleted:
|
|
case (USHORT)fnevObjectModified:
|
|
case (USHORT)fnevObjectMoved:
|
|
case (USHORT)fnevObjectCopied:
|
|
case (USHORT)fnevSearchComplete:
|
|
{
|
|
OBJECT_NOTIFICATION FAR *pobj = &pntf->info.obj;
|
|
|
|
if (pobj->cbEntryID)
|
|
{
|
|
pntfDst->info.obj.lpEntryID = (LPENTRYID)pb;
|
|
cbT = pobj->cbEntryID;
|
|
MemCopy(pb, pobj->lpEntryID, (UINT)cbT);
|
|
pb += AlignProp(cbT);
|
|
cb += AlignProp(cbT);
|
|
}
|
|
if (pobj->cbParentID)
|
|
{
|
|
pntfDst->info.obj.lpParentID = (LPENTRYID)pb;
|
|
cbT = pobj->cbParentID;
|
|
MemCopy(pb, pobj->lpParentID, (UINT)cbT);
|
|
pb += AlignProp(cbT);
|
|
cb += AlignProp(cbT);
|
|
}
|
|
if (pobj->cbOldID)
|
|
{
|
|
pntfDst->info.obj.lpOldID = (LPENTRYID)pb;
|
|
cbT = pobj->cbOldID;
|
|
MemCopy(pb, pobj->lpOldID, (UINT)cbT);
|
|
pb += AlignProp(cbT);
|
|
cb += AlignProp(cbT);
|
|
}
|
|
if (pobj->cbOldParentID)
|
|
{
|
|
pntfDst->info.obj.lpOldParentID = (LPENTRYID)pb;
|
|
cbT = pobj->cbOldParentID;
|
|
MemCopy(pb, pobj->lpOldParentID, (UINT)cbT);
|
|
pb += AlignProp(cbT);
|
|
cb += AlignProp(cbT);
|
|
}
|
|
if (pobj->lpPropTagArray)
|
|
{
|
|
cbT = offsetof(SPropTagArray, aulPropTag) +
|
|
pobj->lpPropTagArray->cValues * sizeof(ULONG);
|
|
pntfDst->info.obj.lpPropTagArray = (LPSPropTagArray)pb;
|
|
MemCopy(pb, pobj->lpPropTagArray, (UINT)cbT);
|
|
pb += AlignProp(cbT);
|
|
cb += AlignProp(cbT);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case (USHORT)fnevTableModified:
|
|
{
|
|
TABLE_NOTIFICATION FAR *ptn = &pntf->info.tab;
|
|
|
|
if (ptn->propIndex.ulPropTag)
|
|
{
|
|
// Wastes 16 bytes when the property doesn't have a tail
|
|
if (sc = ScCopyProps(1, &ptn->propIndex, pb, &cbT))
|
|
goto ret;
|
|
//
|
|
// This was once a straight structure assignment. However, on RISC platforms
|
|
// if pntfDst is not on an 8-byte boundary, this raises a Datatype
|
|
// Misalignment Exception. Changed this to a memcpy in order to not worry
|
|
// about alignment and not cause any extra exception handling.
|
|
//
|
|
memcpy(&(pntfDst->info.tab.propIndex), (LPSPropValue)pb, sizeof(SPropValue));
|
|
pb += AlignProp(cbT);
|
|
cb += AlignProp(cbT);
|
|
}
|
|
|
|
if (ptn->propPrior.ulPropTag)
|
|
{
|
|
// Wastes 16 bytes when the property doesn't have a tail
|
|
if (sc = ScCopyProps(1, &ptn->propPrior, pb, &cbT))
|
|
goto ret;
|
|
//
|
|
// This was once a straight structure assignment. However, on RISC platforms
|
|
// if pntfDst is not on an 8-byte boundary, this raises a Datatype
|
|
// Misalignment Exception. Changed this to a memcpy in order to not worry
|
|
// about alignment and not cause any extra exception handling.
|
|
//
|
|
memcpy(&(pntfDst->info.tab.propPrior), (LPSPropValue)pb, sizeof(SPropValue));
|
|
pb += AlignProp(cbT);
|
|
cb += AlignProp(cbT);
|
|
}
|
|
|
|
if (ptn->row.cValues)
|
|
{
|
|
pntfDst->info.tab.row.lpProps = (LPSPropValue)pb;
|
|
if (sc = ScCopyProps((int)ptn->row.cValues, ptn->row.lpProps, pb, &cbT))
|
|
goto ret;
|
|
pb += AlignProp(cbT);
|
|
cb += AlignProp(cbT);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case (USHORT)fnevStatusObjectModified:
|
|
{
|
|
STATUS_OBJECT_NOTIFICATION FAR *pstat = &pntf->info.statobj;
|
|
|
|
if (pstat->cbEntryID)
|
|
{
|
|
pntfDst->info.statobj.lpEntryID = (LPENTRYID)pb;
|
|
cbT = pstat->cbEntryID;
|
|
MemCopy(pb, pstat->lpEntryID, (UINT)cbT);
|
|
pb += AlignProp(cbT);
|
|
cb += AlignProp(cbT);
|
|
}
|
|
if (pstat->cValues)
|
|
{
|
|
pntfDst->info.statobj.lpPropVals = (LPSPropValue)pb;
|
|
if (sc = ScCopyProps((int)pstat->cValues,
|
|
pstat->lpPropVals, pb, &cbT))
|
|
goto ret;
|
|
pb += cbT;
|
|
cb += cbT;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
DebugTraceArg(ScCopyNotification, TEXT("invalid ulEventType"));
|
|
goto badNotif;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
DebugTraceArg(ScCopyNotification, TEXT("invalid ulEventType"));
|
|
goto badNotif;
|
|
}
|
|
}
|
|
|
|
if (pcb)
|
|
*pcb = (ULONG)cb;
|
|
|
|
ret:
|
|
DebugTraceSc(ScCopyNotifications, sc);
|
|
return sc;
|
|
|
|
badNotif:
|
|
// trace already issued
|
|
return E_INVALIDARG;
|
|
|
|
#undef COPY
|
|
}
|
|
|
|
STDAPI_(SCODE)
|
|
ScRelocNotifications(int cntf, LPNOTIFICATION rgntf, LPVOID pvBaseOld,
|
|
LPVOID pvBaseNew, ULONG FAR *pcb)
|
|
{
|
|
ULONG cb;
|
|
ULONG cbT;
|
|
LPNOTIFICATION pntf;
|
|
SCODE sc = S_OK;
|
|
|
|
AssertSz(!cntf || !IsBadReadPtr(rgntf, sizeof(NOTIFICATION) * cntf),
|
|
TEXT("rgntf fails address check"));
|
|
|
|
AssertSz(pvBaseOld, TEXT("pvBaseOld fails address check"));
|
|
|
|
AssertSz(!IsBadWritePtr(pvBaseNew, sizeof(LPVOID)),
|
|
TEXT("pvBaseNew fails address check"));
|
|
|
|
AssertSz(!pcb || !IsBadWritePtr(pcb, sizeof(ULONG)),
|
|
TEXT("pcb fails address check"));
|
|
|
|
cb = cntf * sizeof(NOTIFICATION);
|
|
for (pntf = rgntf; cntf--; ++pntf)
|
|
{
|
|
switch (HIWORD(pntf->ulEventType))
|
|
{
|
|
case (fnevExtended >> 16):
|
|
// case (fnevSpooler >> 16):
|
|
if (pntf->info.ext.cb)
|
|
{
|
|
pntf->info.ext.pbEventParameters =
|
|
PvRelocPv(pntf->info.ext.pbEventParameters, pvBaseOld,
|
|
pvBaseNew);
|
|
cb += AlignProp(pntf->info.ext.cb);
|
|
}
|
|
break;
|
|
|
|
case 0:
|
|
{
|
|
switch (LOWORD(pntf->ulEventType))
|
|
{
|
|
case (USHORT)fnevCriticalError:
|
|
{
|
|
ERROR_NOTIFICATION FAR *perr = &pntf->info.err;
|
|
|
|
if ( perr->lpEntryID )
|
|
{
|
|
perr->lpEntryID = PvRelocPv( perr->lpEntryID, pvBaseOld,
|
|
pvBaseNew );
|
|
cb += AlignProp( (UINT)perr->cbEntryID );
|
|
}
|
|
|
|
if ( perr->lpMAPIError )
|
|
{
|
|
perr->lpMAPIError = PvRelocPv( perr->lpMAPIError, pvBaseOld,
|
|
pvBaseNew );
|
|
|
|
if (perr->lpMAPIError->lpszError)
|
|
{
|
|
perr->lpMAPIError->lpszError = PvRelocPv(
|
|
perr->lpMAPIError->lpszError, pvBaseOld,
|
|
pvBaseNew );
|
|
|
|
#ifdef _WINNT
|
|
if (perr->ulFlags & MAPI_UNICODE)
|
|
cb += AlignProp((lstrlenW((LPWSTR)perr->lpMAPIError->lpszError)
|
|
+ 1) * sizeof(WCHAR));
|
|
else
|
|
#endif
|
|
cb += AlignProp(lstrlenA((LPSTR)perr->lpMAPIError->lpszError) + 1);
|
|
}
|
|
|
|
if (perr->lpMAPIError->lpszComponent)
|
|
{
|
|
perr->lpMAPIError->lpszComponent = PvRelocPv(
|
|
perr->lpMAPIError->lpszComponent, pvBaseOld,
|
|
pvBaseNew );
|
|
#ifdef _WINNT
|
|
if (perr->ulFlags & MAPI_UNICODE)
|
|
cb += AlignProp((lstrlenW((LPWSTR)perr->lpMAPIError->lpszComponent) + 1)
|
|
* sizeof(WCHAR));
|
|
else
|
|
#endif
|
|
cb += AlignProp(lstrlenA((LPSTR)perr->lpMAPIError->lpszComponent) + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
case (USHORT)fnevNewMail:
|
|
{
|
|
NEWMAIL_NOTIFICATION FAR *pnew = &pntf->info.newmail;
|
|
|
|
if (pnew->lpEntryID)
|
|
{
|
|
pnew->lpEntryID = PvRelocPv(pnew->lpEntryID, pvBaseOld,
|
|
pvBaseNew);
|
|
cb += AlignProp((UINT)pnew->cbEntryID);
|
|
}
|
|
|
|
if (pnew->lpParentID)
|
|
{
|
|
pnew->lpParentID = PvRelocPv(pnew->lpParentID, pvBaseOld,
|
|
pvBaseNew);
|
|
cb += AlignProp((UINT)pnew->cbParentID);
|
|
}
|
|
|
|
if (pnew->lpszMessageClass)
|
|
{
|
|
pnew->lpszMessageClass = PvRelocPv(pnew->lpszMessageClass,
|
|
pvBaseOld, pvBaseNew);
|
|
if (pnew->ulFlags & MAPI_UNICODE)
|
|
cbT = (lstrlenW((LPWSTR)pnew->lpszMessageClass) + 1)
|
|
* sizeof(WCHAR);
|
|
else
|
|
cbT = lstrlenA((LPSTR)pnew->lpszMessageClass) + 1;
|
|
cb += AlignProp(cbT);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case (USHORT)fnevObjectCreated:
|
|
case (USHORT)fnevObjectDeleted:
|
|
case (USHORT)fnevObjectModified:
|
|
case (USHORT)fnevObjectMoved:
|
|
case (USHORT)fnevObjectCopied:
|
|
case (USHORT)fnevSearchComplete:
|
|
{
|
|
OBJECT_NOTIFICATION FAR *pobj = &pntf->info.obj;
|
|
|
|
if (pobj->lpEntryID)
|
|
{
|
|
pobj->lpEntryID = PvRelocPv(pobj->lpEntryID, pvBaseOld,
|
|
pvBaseNew);
|
|
cb += AlignProp(pobj->cbEntryID);
|
|
}
|
|
if (pobj->lpParentID)
|
|
{
|
|
pobj->lpParentID = PvRelocPv(pobj->lpParentID, pvBaseOld,
|
|
pvBaseNew);
|
|
cb += AlignProp(pobj->cbParentID);
|
|
}
|
|
if (pobj->lpOldID)
|
|
{
|
|
pobj->lpOldID = PvRelocPv(pobj->lpOldID, pvBaseOld,
|
|
pvBaseNew);
|
|
cb += AlignProp(pobj->cbOldID);
|
|
}
|
|
if (pobj->lpOldParentID)
|
|
{
|
|
pobj->lpOldParentID = PvRelocPv(pobj->lpOldParentID, pvBaseOld,
|
|
pvBaseNew);
|
|
cb += AlignProp(pobj->cbOldParentID);
|
|
}
|
|
if (pobj->lpPropTagArray)
|
|
{
|
|
pobj->lpPropTagArray = PvRelocPv(pobj->lpPropTagArray,
|
|
pvBaseOld, pvBaseNew);
|
|
cb += offsetof(SPropTagArray, aulPropTag) +
|
|
pobj->lpPropTagArray->cValues * sizeof(ULONG);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case (USHORT)fnevTableModified:
|
|
{
|
|
TABLE_NOTIFICATION FAR *ptn = &pntf->info.tab;
|
|
|
|
Assert (FIsAligned (&ptn->propIndex));
|
|
if (ptn->propIndex.ulPropTag)
|
|
{
|
|
if (sc = ScRelocProps(1, &ptn->propIndex, pvBaseOld,
|
|
pvBaseNew, &cbT))
|
|
goto ret;
|
|
cb += cbT;
|
|
}
|
|
Assert (FIsAligned (&ptn->propPrior));
|
|
if (ptn->propPrior.ulPropTag)
|
|
{
|
|
if (sc = ScRelocProps(1, &ptn->propPrior, pvBaseOld,
|
|
pvBaseNew, &cbT))
|
|
goto ret;
|
|
cb += cbT;
|
|
}
|
|
if (ptn->row.cValues)
|
|
{
|
|
Assert (FIsAligned (ptn->row.lpProps));
|
|
ptn->row.lpProps = PvRelocPv(ptn->row.lpProps,
|
|
pvBaseOld, pvBaseNew);
|
|
if (sc = ScRelocProps((int)ptn->row.cValues, ptn->row.lpProps,
|
|
pvBaseOld, pvBaseNew, &cbT))
|
|
goto ret;
|
|
cb += cbT;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case (USHORT)fnevStatusObjectModified:
|
|
{
|
|
STATUS_OBJECT_NOTIFICATION FAR *pstat = &pntf->info.statobj;
|
|
|
|
if (pstat->lpEntryID)
|
|
{
|
|
pstat->lpEntryID = PvRelocPv(pstat->lpEntryID, pvBaseOld,
|
|
pvBaseNew);
|
|
|
|
// Whoa, this is not sufficient to buffer the size of
|
|
// the entryid. If the entryid is not aligned, then the
|
|
// the properties that follow will not be aligned either.
|
|
//
|
|
Assert (FIsAligned (pstat->lpEntryID));
|
|
cb += AlignProp(pstat->cbEntryID);
|
|
}
|
|
if (pstat->cValues)
|
|
{
|
|
pstat->lpPropVals = PvRelocPv(pstat->lpPropVals,
|
|
pvBaseOld, pvBaseNew);
|
|
Assert (FIsAligned (pstat->lpPropVals));
|
|
if (sc = ScRelocProps((int)pstat->cValues, pstat->lpPropVals,
|
|
pvBaseOld, pvBaseNew, &cbT))
|
|
goto ret;
|
|
cb += cbT;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
DebugTraceArg(ScRelocNotification, TEXT("invalid ulEventType"));
|
|
goto badNotif;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
DebugTraceArg(ScRelocNotification, TEXT("invalid ulEventType"));
|
|
goto badNotif;
|
|
}
|
|
}
|
|
|
|
if (pcb)
|
|
*pcb = cb;
|
|
|
|
ret:
|
|
DebugTraceSc(ScRelocNotifications, sc);
|
|
return sc;
|
|
|
|
badNotif:
|
|
// trace already issued
|
|
return E_INVALIDARG;
|
|
}
|
|
#endif // NOTIFICATIONS
|
|
|
|
STDAPI_(LPSPropValue)
|
|
LpValFindProp( ULONG ulPropTag, ULONG cprop, LPSPropValue rgprop)
|
|
{
|
|
// Mutate the property tag to a property ID
|
|
ulPropTag = PROP_ID(ulPropTag);
|
|
|
|
while (cprop--)
|
|
{
|
|
Assert( !IsBadReadPtr( rgprop, sizeof(SPropValue)));
|
|
|
|
if (PROP_ID(rgprop->ulPropTag) == ulPropTag)
|
|
{
|
|
return rgprop;
|
|
}
|
|
|
|
rgprop++;
|
|
}
|
|
|
|
// No match was found so return NULL.
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* ScCountPropsEx()
|
|
*
|
|
* Internal routine that computes the size required
|
|
* to hold a given propval array based on specified alignment
|
|
*/
|
|
|
|
SCODE
|
|
ScCountPropsEx(int cprop, LPSPropValue rgprop, ULONG ulAlign, ULONG FAR *pcb)
|
|
{
|
|
LPSPropValue pprop;
|
|
ULONG cb = 0;
|
|
ULONG cbMV;
|
|
int iValue;
|
|
|
|
#define Align(_cb) ((ULONG)( ((DWORD_PTR) ((_cb) + (ulAlign-1))) & ~(((DWORD_PTR) ulAlign-1))))
|
|
|
|
// validate parameters
|
|
|
|
AssertSz(ulAlign && ulAlign <= ALIGN_RISC,
|
|
TEXT("invalid alignment value"));
|
|
|
|
AssertSz(!pcb || !IsBadWritePtr(pcb, sizeof(ULONG)),
|
|
TEXT("pcb fails address check"));
|
|
|
|
//$ SIZE Some of the multi-valued cases could be collapsed if we don't
|
|
//$ mind assuming that the counts and pointers are in the same place.
|
|
|
|
if ( (rgprop && !cprop)
|
|
|| IsBadReadPtr(rgprop, cprop*sizeof(SPropValue)))
|
|
{
|
|
DebugTraceArg(ScCountProps, TEXT("rgprop fails address check"));
|
|
return MAPI_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
for (pprop = rgprop; cprop--; ++pprop)
|
|
{
|
|
ULONG ulID = PROP_ID(pprop->ulPropTag);
|
|
ULONG ulType = PROP_TYPE(pprop->ulPropTag);
|
|
|
|
// Check for valid PROP_ID
|
|
if ( (ulID == PROP_ID_INVALID)
|
|
|| ((ulType == PT_NULL) && (ulID != PROP_ID_NULL))
|
|
|| ((ulID == PROP_ID_NULL) && (ulType != PT_NULL) && (ulType != PT_ERROR)))
|
|
return MAPI_E_INVALID_PARAMETER;
|
|
|
|
// Check for valid PROP_TYPE and count memory consumed
|
|
cb += sizeof(SPropValue);
|
|
switch ( PROP_TYPE(pprop->ulPropTag) )
|
|
{
|
|
case PT_UNSPECIFIED:
|
|
default:
|
|
DebugTrace( TEXT("ScCountProps: Unknown property type %s (index %d)\n"), SzDecodeUlPropTag(pprop->ulPropTag), pprop - rgprop);
|
|
return MAPI_E_INVALID_PARAMETER;
|
|
|
|
case PT_I2:
|
|
case PT_LONG:
|
|
case PT_R4:
|
|
case PT_APPTIME:
|
|
case PT_DOUBLE:
|
|
case PT_BOOLEAN:
|
|
case PT_CURRENCY:
|
|
case PT_SYSTIME:
|
|
case PT_I8:
|
|
case PT_ERROR:
|
|
case PT_OBJECT:
|
|
case PT_NULL:
|
|
break;
|
|
|
|
case PT_CLSID:
|
|
if (IsBadReadPtr(pprop->Value.lpguid, sizeof(GUID)))
|
|
goto badProp;
|
|
cb += Align(sizeof(GUID));
|
|
break;
|
|
|
|
case PT_BINARY:
|
|
//$Hack: IsBadReadPtr works funny under Win16.
|
|
//$Hack: It doesn't handle the case of 0 cb, and
|
|
//$Hack: non-0 lpb.
|
|
if (pprop->Value.bin.cb && IsBadReadPtr( pprop->Value.bin.lpb
|
|
, (UINT) (pprop->Value.bin.cb)))
|
|
goto badProp;
|
|
|
|
cb += Align(pprop->Value.bin.cb);
|
|
break;
|
|
|
|
case PT_STRING8:
|
|
if (IsBadStringPtrA(pprop->Value.lpszA, INFINITE))
|
|
goto badProp;
|
|
cb += Align((lstrlenA( pprop->Value.lpszA ) + 1) * sizeof(CHAR));
|
|
|
|
break;
|
|
|
|
case PT_UNICODE:
|
|
#if defined(WIN32) && !defined(MAC)
|
|
//$ No validation code available on Win16
|
|
if (IsBadStringPtrW(pprop->Value.lpszW, INFINITE))
|
|
goto badProp;
|
|
#endif
|
|
cb += Align((lstrlenW( pprop->Value.lpszW ) + 1) * sizeof(WCHAR));
|
|
break;
|
|
|
|
|
|
// Note! MVxxx.cValues may NOT be zero (DCR 2789).
|
|
|
|
case PT_MV_I2:
|
|
if ( !(cbMV = pprop->Value.MVi.cValues * sizeof(short int))
|
|
|| IsBadReadPtr(pprop->Value.MVi.lpi, (UINT) cbMV))
|
|
goto badProp;
|
|
cb += Align(cbMV);
|
|
break;
|
|
|
|
case PT_MV_LONG:
|
|
if ( !(cbMV = pprop->Value.MVl.cValues * sizeof(LONG))
|
|
|| IsBadReadPtr(pprop->Value.MVl.lpl, (UINT) cbMV))
|
|
goto badProp;
|
|
cb += Align(cbMV);
|
|
break;
|
|
|
|
case PT_MV_R4:
|
|
if ( !(cbMV = pprop->Value.MVflt.cValues * sizeof(float))
|
|
|| IsBadReadPtr(pprop->Value.MVflt.lpflt, (UINT) cbMV))
|
|
goto badProp;
|
|
cb += Align(cbMV);
|
|
break;
|
|
|
|
case PT_MV_APPTIME:
|
|
if ( !(cbMV = pprop->Value.MVat.cValues * sizeof(double))
|
|
|| IsBadReadPtr(pprop->Value.MVat.lpat, (UINT) cbMV))
|
|
goto badProp;
|
|
cb += cbMV;
|
|
break;
|
|
|
|
case PT_MV_DOUBLE:
|
|
if ( !(cbMV = pprop->Value.MVdbl.cValues * sizeof(double))
|
|
|| IsBadReadPtr(pprop->Value.MVdbl.lpdbl, (UINT) cbMV))
|
|
goto badProp;
|
|
cb += cbMV;
|
|
break;
|
|
|
|
case PT_MV_CURRENCY:
|
|
if ( !(cbMV = pprop->Value.MVcur.cValues * sizeof(CURRENCY))
|
|
|| IsBadReadPtr(pprop->Value.MVcur.lpcur, (UINT) cbMV))
|
|
goto badProp;
|
|
cb += cbMV;
|
|
break;
|
|
|
|
case PT_MV_SYSTIME:
|
|
if ( !(cbMV = pprop->Value.MVft.cValues * sizeof(FILETIME))
|
|
|| IsBadReadPtr(pprop->Value.MVft.lpft, (UINT) cbMV))
|
|
goto badProp;
|
|
cb += cbMV;
|
|
break;
|
|
|
|
case PT_MV_CLSID:
|
|
if ( !(cbMV = pprop->Value.MVguid.cValues * sizeof(GUID))
|
|
|| IsBadReadPtr(pprop->Value.MVguid.lpguid, (UINT) cbMV))
|
|
goto badProp;
|
|
cb += cbMV;
|
|
break;
|
|
|
|
case PT_MV_I8:
|
|
if ( !(cbMV = pprop->Value.MVli.cValues * sizeof(LARGE_INTEGER))
|
|
|| IsBadReadPtr(pprop->Value.MVli.lpli, (UINT) cbMV))
|
|
goto badProp;
|
|
cb += cbMV;
|
|
break;
|
|
|
|
|
|
case PT_MV_BINARY:
|
|
if ( !(cbMV = pprop->Value.MVbin.cValues * sizeof(SBinary))
|
|
|| IsBadReadPtr(pprop->Value.MVbin.lpbin, (UINT) cbMV))
|
|
goto badProp;
|
|
|
|
Assert(Align(cbMV) == cbMV);
|
|
cb += cbMV;
|
|
|
|
for ( iValue = 0;
|
|
(ULONG)iValue < pprop->Value.MVbin.cValues;
|
|
iValue++ )
|
|
{
|
|
if (IsBadReadPtr(pprop->Value.MVbin.lpbin[iValue].lpb,
|
|
(UINT)pprop->Value.MVbin.lpbin[iValue].cb))
|
|
goto badProp;
|
|
cb += Align(pprop->Value.MVbin.lpbin[iValue].cb);
|
|
}
|
|
|
|
break;
|
|
|
|
case PT_MV_STRING8:
|
|
if ( !(cbMV = pprop->Value.MVszA.cValues * sizeof(LPVOID))
|
|
|| IsBadReadPtr(pprop->Value.MVszA.lppszA, (UINT) cbMV))
|
|
goto badProp;
|
|
|
|
cb += cbMV;
|
|
|
|
for ( iValue = 0;
|
|
(ULONG)iValue < pprop->Value.MVszA.cValues;
|
|
iValue++ )
|
|
{
|
|
if (IsBadStringPtrA(pprop->Value.MVszA.lppszA[iValue],
|
|
INFINITE))
|
|
goto badProp;
|
|
cb += lstrlenA(pprop->Value.MVszA.lppszA[iValue]) + 1;
|
|
}
|
|
|
|
cb = Align(cb);
|
|
|
|
break;
|
|
|
|
case PT_MV_UNICODE:
|
|
if ( !(cbMV = pprop->Value.MVszW.cValues * sizeof(LPVOID))
|
|
|| IsBadReadPtr(pprop->Value.MVszW.lppszW, (UINT) cbMV))
|
|
goto badProp;
|
|
|
|
cb += cbMV;
|
|
|
|
for ( iValue = 0;
|
|
(ULONG)iValue < pprop->Value.MVszW.cValues;
|
|
iValue++ )
|
|
{
|
|
#if defined(WIN32) && !defined(MAC)
|
|
//$ No validation on Win16
|
|
if (IsBadStringPtrW(pprop->Value.MVszW.lppszW[iValue], INFINITE))
|
|
goto badProp;
|
|
#endif
|
|
cb += (lstrlenW(pprop->Value.MVszW.lppszW[iValue]) + 1)
|
|
* sizeof(WCHAR);
|
|
}
|
|
|
|
cb = Align(cb);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pcb)
|
|
{
|
|
Assert(!IsBadWritePtr(pcb, sizeof(ULONG)));
|
|
*pcb = cb;
|
|
}
|
|
return S_OK;
|
|
|
|
badProp:
|
|
DebugTrace( TEXT("ScCountProps: Unreadable property %s (index %d)\n"), SzDecodeUlPropTag(pprop->ulPropTag), pprop - rgprop);
|
|
return MAPI_E_INVALID_PARAMETER;
|
|
|
|
#undef Align
|
|
}
|
|
|
|
STDAPI_(SCODE)
|
|
ScCountProps(int cprop, LPSPropValue rgprop, ULONG FAR *pcb)
|
|
{
|
|
#if defined (_AMD64_) || defined(_IA64_)
|
|
return ScCountPropsEx( cprop, rgprop, ALIGN_RISC, pcb );
|
|
#else
|
|
return ScCountPropsEx( cprop, rgprop, ALIGN_X86, pcb );
|
|
#endif
|
|
}
|
|
|
|
STDAPI_(SCODE)
|
|
ScCopyProps(int cprop, LPSPropValue rgprop, LPVOID pvDst, ULONG FAR *pcb)
|
|
{
|
|
LPSPropValue pprop;
|
|
LPSPropValue ppropDst;
|
|
ULONG cb;
|
|
ULONG cbMV;
|
|
LPBYTE pb;
|
|
UINT cbT;
|
|
int iValue;
|
|
|
|
// validate parameters
|
|
|
|
AssertSz(!cprop || !IsBadReadPtr(rgprop, sizeof(SPropValue) * cprop),
|
|
TEXT("rgprop fails address check"));
|
|
|
|
AssertSz(!cprop || !IsBadWritePtr(pvDst, sizeof(SPropValue) * cprop),
|
|
TEXT("pvDst fails address check"));
|
|
|
|
AssertSz(!pcb || !IsBadWritePtr(pcb, sizeof(ULONG)),
|
|
TEXT("pcb fails address check"));
|
|
|
|
//$ SIZE Some of the multi-valued cases could be collapsed if we don't
|
|
//$ mind assuming that the counts and pointers are in the same place.
|
|
|
|
cb = cprop * sizeof(SPropValue);
|
|
MemCopy(pvDst, rgprop, (UINT)cb);
|
|
pb = (LPBYTE)pvDst + cb;
|
|
|
|
for (pprop = rgprop, ppropDst = pvDst; cprop--; ++pprop, ++ppropDst)
|
|
{
|
|
// Tricky: common code after the switch increments pb and cb
|
|
// by the amount copied. If no increment is necessary, the case
|
|
// uses 'continue' rather than 'break' to exit the switch, thus
|
|
// skipping the increment -- AND any other code which may be
|
|
// added after the switch.
|
|
|
|
switch ( PROP_TYPE(pprop->ulPropTag) )
|
|
{
|
|
default:
|
|
DebugTrace( TEXT("ScCopyProps: Unknown property type %s (index %d)\n"), SzDecodeUlPropTag(pprop->ulPropTag), pprop - rgprop);
|
|
return E_INVALIDARG;
|
|
|
|
case PT_I2:
|
|
case PT_LONG:
|
|
case PT_R4:
|
|
case PT_APPTIME:
|
|
case PT_DOUBLE:
|
|
case PT_BOOLEAN:
|
|
case PT_CURRENCY:
|
|
case PT_SYSTIME:
|
|
case PT_I8:
|
|
case PT_ERROR:
|
|
case PT_OBJECT:
|
|
case PT_NULL:
|
|
continue; // nothing to add
|
|
|
|
case PT_CLSID:
|
|
ppropDst->Value.lpguid = (LPGUID) pb;
|
|
cbT = sizeof(GUID);
|
|
MemCopy(pb, (LPBYTE) pprop->Value.lpguid, cbT);
|
|
break;
|
|
|
|
case PT_BINARY:
|
|
ppropDst->Value.bin.lpb = pb;
|
|
cbT = (UINT)pprop->Value.bin.cb;
|
|
MemCopy(pb, pprop->Value.bin.lpb, cbT);
|
|
break;
|
|
|
|
case PT_STRING8:
|
|
ppropDst->Value.lpszA = (LPSTR)pb;
|
|
cbT = lstrlenA( pprop->Value.lpszA ) + 1;
|
|
MemCopy(pb, pprop->Value.lpszA, cbT);
|
|
break;
|
|
|
|
case PT_UNICODE:
|
|
ppropDst->Value.lpszW = (LPWSTR)pb;
|
|
cbT = (lstrlenW( pprop->Value.lpszW ) + 1) * sizeof(WCHAR);
|
|
MemCopy(pb, pprop->Value.lpszW, cbT);
|
|
break;
|
|
|
|
case PT_MV_I2:
|
|
ppropDst->Value.MVi.lpi = (short int FAR *)pb;
|
|
cbT = (UINT)pprop->Value.MVi.cValues * sizeof(short int);
|
|
MemCopy(pb, pprop->Value.MVi.lpi, cbT);
|
|
break;
|
|
|
|
case PT_MV_LONG:
|
|
ppropDst->Value.MVl.lpl = (LONG FAR *)pb;
|
|
cbT = (UINT)pprop->Value.MVl.cValues * sizeof(LONG);
|
|
MemCopy(pb, pprop->Value.MVl.lpl, cbT);
|
|
break;
|
|
|
|
case PT_MV_R4:
|
|
ppropDst->Value.MVflt.lpflt = (float FAR *)pb;
|
|
cbT = (UINT)pprop->Value.MVflt.cValues * sizeof(float);
|
|
MemCopy(pb, pprop->Value.MVflt.lpflt, cbT);
|
|
break;
|
|
|
|
case PT_MV_APPTIME:
|
|
ppropDst->Value.MVat.lpat = (double FAR *)pb;
|
|
cbT = (UINT)pprop->Value.MVat.cValues * sizeof(double);
|
|
MemCopy(pb, pprop->Value.MVat.lpat, cbT);
|
|
break;
|
|
|
|
case PT_MV_DOUBLE:
|
|
ppropDst->Value.MVdbl.lpdbl = (double FAR *)pb;
|
|
cbT = (UINT)pprop->Value.MVdbl.cValues * sizeof(double);
|
|
MemCopy(pb, pprop->Value.MVdbl.lpdbl, cbT);
|
|
break;
|
|
|
|
case PT_MV_CURRENCY:
|
|
ppropDst->Value.MVcur.lpcur = (CURRENCY FAR *)pb;
|
|
cbT = (UINT)pprop->Value.MVcur.cValues * sizeof(CURRENCY);
|
|
MemCopy(pb, pprop->Value.MVcur.lpcur, cbT);
|
|
break;
|
|
|
|
case PT_MV_SYSTIME:
|
|
ppropDst->Value.MVft.lpft = (FILETIME FAR *)pb;
|
|
cbT = (UINT)pprop->Value.MVft.cValues * sizeof(FILETIME);
|
|
MemCopy(pb, pprop->Value.MVft.lpft, cbT);
|
|
break;
|
|
|
|
case PT_MV_CLSID:
|
|
ppropDst->Value.MVguid.lpguid = (GUID FAR *)pb;
|
|
cbT = (UINT)pprop->Value.MVguid.cValues * sizeof(GUID);
|
|
MemCopy(pb, pprop->Value.MVguid.lpguid, cbT);
|
|
break;
|
|
|
|
case PT_MV_I8:
|
|
ppropDst->Value.MVli.lpli = (LARGE_INTEGER FAR *)pb;
|
|
cbT = (UINT)pprop->Value.MVli.cValues * sizeof(LARGE_INTEGER);
|
|
MemCopy(pb, pprop->Value.MVli.lpli, cbT);
|
|
break;
|
|
|
|
case PT_MV_BINARY:
|
|
ppropDst->Value.MVbin.lpbin = (SBinary *) pb;
|
|
cbMV = pprop->Value.MVbin.cValues * sizeof(SBinary);
|
|
pb += cbMV;
|
|
cb += cbMV;
|
|
for (iValue = 0;
|
|
(ULONG)iValue < pprop->Value.MVbin.cValues;
|
|
iValue++)
|
|
{
|
|
ppropDst->Value.MVbin.lpbin[iValue].lpb = pb;
|
|
cbT = (UINT)pprop->Value.MVbin.lpbin[iValue].cb;
|
|
ppropDst->Value.MVbin.lpbin[iValue].cb = (ULONG)cbT;
|
|
MemCopy(pb, pprop->Value.MVbin.lpbin[iValue].lpb, cbT);
|
|
cbT = AlignProp(cbT);
|
|
cb += cbT;
|
|
pb += cbT;
|
|
}
|
|
continue; // already updated, don't do it again
|
|
|
|
case PT_MV_STRING8:
|
|
ppropDst->Value.MVszA.lppszA = (LPSTR *) pb;
|
|
cbMV = pprop->Value.MVszA.cValues * sizeof(LPSTR);
|
|
pb += cbMV;
|
|
cb += cbMV;
|
|
for (iValue = 0;
|
|
(ULONG)iValue < pprop->Value.MVszA.cValues;
|
|
iValue++)
|
|
{
|
|
ppropDst->Value.MVszA.lppszA[iValue] = (LPSTR)pb;
|
|
cbT = lstrlenA(pprop->Value.MVszA.lppszA[iValue]) + 1;
|
|
MemCopy(pb, pprop->Value.MVszA.lppszA[iValue], cbT);
|
|
pb += cbT;
|
|
cb += cbT;
|
|
}
|
|
cbT = (UINT)AlignProp(cb);
|
|
pb += cbT - cb;
|
|
cb = cbT;
|
|
continue; // already updated, don't do it again
|
|
|
|
case PT_MV_UNICODE:
|
|
ppropDst->Value.MVszW.lppszW = (LPWSTR *) pb;
|
|
cbMV = pprop->Value.MVszW.cValues * sizeof(LPWSTR);
|
|
pb += cbMV;
|
|
cb += cbMV;
|
|
for (iValue = 0;
|
|
(ULONG)iValue < pprop->Value.MVszW.cValues;
|
|
iValue++)
|
|
{
|
|
ppropDst->Value.MVszW.lppszW[iValue] = (LPWSTR)pb;
|
|
cbT = (lstrlenW(pprop->Value.MVszW.lppszW[iValue]) + 1)
|
|
* sizeof(WCHAR);
|
|
MemCopy(pb, pprop->Value.MVszW.lppszW[iValue], cbT);
|
|
pb += cbT;
|
|
cb += cbT;
|
|
}
|
|
cbT = (UINT)AlignProp(cb);
|
|
pb += cbT - cb;
|
|
cb = cbT;
|
|
continue; // already updated, don't do it again
|
|
}
|
|
|
|
// Advance pointer and total count by the amount copied
|
|
cbT = AlignProp(cbT);
|
|
pb += cbT;
|
|
cb += cbT;
|
|
}
|
|
|
|
if (pcb)
|
|
{
|
|
Assert(!IsBadWritePtr(pcb, sizeof(ULONG)));
|
|
*pcb = cb;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
#ifdef NOTIFICATIONS
|
|
STDAPI_(SCODE)
|
|
ScRelocProps( int cprop,
|
|
LPSPropValue rgprop,
|
|
LPVOID pvBaseOld,
|
|
LPVOID pvBaseNew,
|
|
ULONG FAR *pcb)
|
|
{
|
|
LPSPropValue pprop;
|
|
ULONG cb;
|
|
UINT cbT;
|
|
LPVOID pvT;
|
|
int iValue;
|
|
BOOL fBaseNewValid = !IsBadReadPtr (pvBaseNew, sizeof (LPVOID));
|
|
|
|
// validate parameters
|
|
|
|
AssertSz(!cprop || !IsBadWritePtr(rgprop, sizeof(SPropValue) * cprop),
|
|
TEXT("rgprop fails address check"));
|
|
|
|
AssertSz(!pcb || !IsBadWritePtr(pcb, sizeof(ULONG)),
|
|
TEXT("pcb fails address check"));
|
|
|
|
// The old behavior of this code assumed that pvBaseNew was a usable
|
|
// pointer and that there would be no relocation to or from an unusable
|
|
// pointer. We've changed this so that you may relocate to or from an
|
|
// unusable pointer -- but logic to figure out whether to use the
|
|
// original or new pointer to fixup internal pointers was added.
|
|
// What we mean by this is that things like strlens and mv prop arrays
|
|
// need to be computed based on where the data ** CURRENTLY ** lives.
|
|
// The old rules allowed us to assume that the NEW location was always
|
|
// the right place. The new rules make us figure it out based on the
|
|
// validity of the two pointers pvBaseNew/Old, that are passed in.
|
|
//
|
|
// In order to preserve the old behavior, we try to use the new pointer
|
|
// (the one that was always used before) as the basis for internal
|
|
// pointer fixup. If it is bad (for example if we are relocating from
|
|
// something to zero), we will use the old pointer.
|
|
//
|
|
// A new wrinkle in the behavior of this code is a return of
|
|
// MAPI_E_INVALID_PARAMETER if both addresses appear invalid. This is
|
|
// to help protect this code for the mv or strlen case (though all
|
|
// other cases would have worked OK).
|
|
|
|
if (!fBaseNewValid && IsBadReadPtr (pvBaseOld, sizeof (LPVOID)))
|
|
{
|
|
DebugTrace ( TEXT("pvBaseOld and pvBaseNew failed address check"));
|
|
DebugTraceSc (ScRelocProps, MAPI_E_INVALID_PARAMETER);
|
|
return MAPI_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
//$ SIZE Some of the multi-valued cases could be collapsed if we don't
|
|
//$ mind assuming that the counts and pointers are in the same place.
|
|
|
|
cb = cprop * sizeof(SPropValue);
|
|
|
|
for (pprop = rgprop; cprop--; ++pprop)
|
|
{
|
|
// Tricky: common code after the switch increments cb.
|
|
// If no increment is necessary, the case
|
|
// uses 'continue' rather than 'break' to exit the switch, thus
|
|
// skipping the increment -- AND any other code which may be
|
|
// added after the switch.
|
|
|
|
switch ( PROP_TYPE(pprop->ulPropTag) )
|
|
{
|
|
default:
|
|
DebugTrace( TEXT("ScRelocProps: Unknown property type %s")
|
|
TEXT(" (index %d)\n"),
|
|
SzDecodeUlPropTag(pprop->ulPropTag), pprop - rgprop);
|
|
return E_INVALIDARG;
|
|
|
|
case PT_I2:
|
|
case PT_LONG:
|
|
case PT_R4:
|
|
case PT_APPTIME:
|
|
case PT_DOUBLE:
|
|
case PT_BOOLEAN:
|
|
case PT_CURRENCY:
|
|
case PT_SYSTIME:
|
|
case PT_I8:
|
|
case PT_ERROR:
|
|
case PT_OBJECT:
|
|
case PT_NULL:
|
|
continue; // nothing to add or relocate
|
|
|
|
case PT_CLSID:
|
|
pprop->Value.lpguid = PvRelocPv(pprop->Value.lpguid,
|
|
pvBaseOld, pvBaseNew);
|
|
cbT = sizeof(GUID);
|
|
break;
|
|
|
|
case PT_BINARY:
|
|
pprop->Value.bin.lpb = PvRelocPv(pprop->Value.bin.lpb,
|
|
pvBaseOld, pvBaseNew);
|
|
cbT = (UINT)pprop->Value.bin.cb;
|
|
break;
|
|
|
|
case PT_STRING8:
|
|
|
|
// If we're assuming that the old pointer is OK (this
|
|
// means that we determined that the new one is not OK),
|
|
// save the current lpszA value in a temp variable. After
|
|
// the relocation, if the reverse is true, we'll put the
|
|
// relocated lpszA value into the temp variable.
|
|
//
|
|
// We then use the strlen of the string we hope the temp
|
|
// variable is pointing to, in order to compute the amount
|
|
// of space in the blob which is occupied by the string.
|
|
|
|
if (!fBaseNewValid)
|
|
pvT = pprop->Value.lpszA;
|
|
|
|
pprop->Value.lpszA = PvRelocPv(pprop->Value.lpszA,
|
|
pvBaseOld, pvBaseNew);
|
|
|
|
if (fBaseNewValid)
|
|
pvT = pprop->Value.lpszA;
|
|
|
|
cbT = lstrlenA((LPSTR)pvT) + 1;
|
|
|
|
break;
|
|
|
|
case PT_UNICODE:
|
|
|
|
// If we're assuming that the old pointer is OK (this
|
|
// means that we determined that the new one is not OK),
|
|
// save the current lpszW value in a temp variable. After
|
|
// the relocation, if the reverse is true, we'll put the
|
|
// relocated lpszW value into the temp variable.
|
|
//
|
|
// We then use the strlen of the string we hope the temp
|
|
// variable is pointing to, in order to compute the amount
|
|
// of space in the blob which is occupied by the string.
|
|
|
|
if (!fBaseNewValid)
|
|
pvT = pprop->Value.lpszW;
|
|
|
|
pprop->Value.lpszW = PvRelocPv(pprop->Value.lpszW,
|
|
pvBaseOld, pvBaseNew);
|
|
|
|
if (fBaseNewValid)
|
|
pvT = pprop->Value.lpszW;
|
|
|
|
cbT = (lstrlenW((LPWSTR)pvT) + 1) * sizeof(WCHAR);
|
|
|
|
break;
|
|
|
|
case PT_MV_I2:
|
|
pprop->Value.MVi.lpi = PvRelocPv(pprop->Value.MVi.lpi,
|
|
pvBaseOld, pvBaseNew);
|
|
cbT = (UINT)pprop->Value.MVi.cValues * sizeof(short int);
|
|
break;
|
|
|
|
case PT_MV_LONG:
|
|
pprop->Value.MVl.lpl = PvRelocPv(pprop->Value.MVl.lpl,
|
|
pvBaseOld, pvBaseNew);
|
|
cbT = (UINT)pprop->Value.MVl.cValues * sizeof(LONG);
|
|
break;
|
|
|
|
case PT_MV_R4:
|
|
pprop->Value.MVflt.lpflt = PvRelocPv(pprop->Value.MVflt.lpflt,
|
|
pvBaseOld, pvBaseNew);
|
|
cbT = (UINT)pprop->Value.MVflt.cValues * sizeof(float);
|
|
break;
|
|
|
|
case PT_MV_APPTIME:
|
|
pprop->Value.MVat.lpat = PvRelocPv(pprop->Value.MVat.lpat,
|
|
pvBaseOld, pvBaseNew);
|
|
cbT = (UINT)pprop->Value.MVat.cValues * sizeof(double);
|
|
break;
|
|
|
|
case PT_MV_DOUBLE:
|
|
pprop->Value.MVdbl.lpdbl = PvRelocPv(pprop->Value.MVdbl.lpdbl,
|
|
pvBaseOld, pvBaseNew);
|
|
cbT = (UINT)pprop->Value.MVdbl.cValues * sizeof(double);
|
|
break;
|
|
|
|
case PT_MV_CURRENCY:
|
|
pprop->Value.MVcur.lpcur = PvRelocPv(pprop->Value.MVcur.lpcur,
|
|
pvBaseOld, pvBaseNew);
|
|
cbT = (UINT)pprop->Value.MVcur.cValues * sizeof(CURRENCY);
|
|
break;
|
|
|
|
case PT_MV_SYSTIME:
|
|
pprop->Value.MVft.lpft = PvRelocPv(pprop->Value.MVft.lpft,
|
|
pvBaseOld, pvBaseNew);
|
|
cbT = (UINT)pprop->Value.MVft.cValues * sizeof(FILETIME);
|
|
break;
|
|
|
|
case PT_MV_CLSID:
|
|
pprop->Value.MVguid.lpguid = PvRelocPv(pprop->Value.MVguid.lpguid,
|
|
pvBaseOld, pvBaseNew);
|
|
cbT = (UINT)pprop->Value.MVguid.cValues * sizeof(GUID);
|
|
break;
|
|
|
|
case PT_MV_I8:
|
|
pprop->Value.MVli.lpli = PvRelocPv(pprop->Value.MVli.lpli,
|
|
pvBaseOld, pvBaseNew);
|
|
cbT = (UINT)pprop->Value.MVli.cValues * sizeof(LARGE_INTEGER);
|
|
break;
|
|
|
|
case PT_MV_BINARY:
|
|
{
|
|
LPSBinary lpsbT = pprop->Value.MVbin.lpbin;
|
|
|
|
pprop->Value.MVbin.lpbin = PvRelocPv(lpsbT, pvBaseOld, pvBaseNew);
|
|
|
|
// We've already set up a temporary variable to point to the
|
|
// pvBaseOld memory location. If pvBaseNew was OK, then we'll
|
|
// redirect the temp variable to the relocated memory before
|
|
// using it to correct the pointers in the MVbin array.
|
|
|
|
if (fBaseNewValid)
|
|
lpsbT = pprop->Value.MVbin.lpbin;
|
|
|
|
for (iValue = 0;
|
|
(ULONG)iValue < pprop->Value.MVbin.cValues;
|
|
iValue++)
|
|
{
|
|
lpsbT[iValue].lpb = PvRelocPv(lpsbT[iValue].lpb, pvBaseOld, pvBaseNew);
|
|
cb += (UINT)AlignProp(lpsbT[iValue].cb);
|
|
}
|
|
continue; // already updated, don't do it again
|
|
}
|
|
|
|
case PT_MV_STRING8:
|
|
{
|
|
LPSTR * lppszT = pprop->Value.MVszA.lppszA;
|
|
|
|
pprop->Value.MVszA.lppszA = PvRelocPv(lppszT, pvBaseOld, pvBaseNew);
|
|
|
|
// We've already set up a temporary variable to point to the
|
|
// pvBaseOld memory location. If pvBaseNew was OK, then we'll
|
|
// redirect the temp variable to the relocated memory before
|
|
// using it to correct the pointers in the MVszA array.
|
|
|
|
if (fBaseNewValid)
|
|
lppszT = pprop->Value.MVszA.lppszA;
|
|
|
|
for (iValue = 0;
|
|
(ULONG)iValue < pprop->Value.MVszA.cValues;
|
|
iValue++)
|
|
{
|
|
// If we're assuming that the old pointer is OK (this
|
|
// means that we determined that the new one is not OK),
|
|
// save the current lppszT value in a temp variable. After
|
|
// the relocation, if the reverse is true, we'll put the
|
|
// relocated lppszT value into the temp variable.
|
|
//
|
|
// We then use the strlen of the string we hope the temp
|
|
// variable is pointing to, in order to compute the amount
|
|
// of space in the blob which is occupied by the string.
|
|
|
|
if (!fBaseNewValid)
|
|
pvT = lppszT[iValue];
|
|
|
|
lppszT[iValue] = PvRelocPv(lppszT[iValue], pvBaseOld, pvBaseNew);
|
|
|
|
if (fBaseNewValid)
|
|
pvT = lppszT[iValue];
|
|
|
|
cb += lstrlenA((LPSTR)pvT) + 1;
|
|
}
|
|
cb = AlignProp(cb);
|
|
continue; // already updated, don't do it again
|
|
}
|
|
|
|
case PT_MV_UNICODE:
|
|
{
|
|
LPWSTR * lppszwT = pprop->Value.MVszW.lppszW;
|
|
|
|
pprop->Value.MVszW.lppszW = PvRelocPv(lppszwT, pvBaseOld, pvBaseNew);
|
|
|
|
// We've already set up a temporary variable to point to the
|
|
// pvBaseOld memory location. If pvBaseNew was OK, then we'll
|
|
// redirect the temp variable to the relocated memory before
|
|
// using it to correct the pointers in the MVszW array.
|
|
|
|
if (fBaseNewValid)
|
|
lppszwT = pprop->Value.MVszW.lppszW;
|
|
|
|
for (iValue = 0;
|
|
(ULONG)iValue < pprop->Value.MVszW.cValues;
|
|
iValue++)
|
|
{
|
|
// If we're assuming that the old pointer is OK (this
|
|
// means that we determined that the new one is not OK),
|
|
// save the current lppszwT value in a temp variable. After
|
|
// the relocation, if the reverse is true, we'll put the
|
|
// relocated lppszwT value into the temp variable.
|
|
//
|
|
// We then use the strlen of the string we hope the temp
|
|
// variable is pointing to, in order to compute the amount
|
|
// of space in the blob which is occupied by the string.
|
|
|
|
if (!fBaseNewValid)
|
|
pvT = lppszwT[iValue];
|
|
|
|
lppszwT[iValue] = PvRelocPv(lppszwT[iValue], pvBaseOld, pvBaseNew);
|
|
|
|
if (fBaseNewValid)
|
|
pvT = lppszwT[iValue];
|
|
|
|
cb += (lstrlenW(lppszwT[iValue]) + 1) * sizeof(WCHAR);
|
|
}
|
|
cb = AlignProp(cb);
|
|
continue; // already updated, don't do it again
|
|
}
|
|
}
|
|
|
|
// Advance total count
|
|
cb += AlignProp(cbT);
|
|
}
|
|
|
|
if (pcb)
|
|
{
|
|
Assert(!IsBadWritePtr(pcb, sizeof(ULONG)));
|
|
*pcb = cb;
|
|
}
|
|
return S_OK;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Wrapper function to just duplicate a property value array
|
|
* into a single block of MAPI memory.
|
|
*/
|
|
STDAPI_(SCODE)
|
|
ScDupPropset(int cprop, LPSPropValue rgprop, LPALLOCATEBUFFER palloc,
|
|
LPSPropValue FAR *prgprop)
|
|
{
|
|
ULONG cb;
|
|
SCODE sc;
|
|
|
|
// validate parameters
|
|
|
|
AssertSz(!cprop || !IsBadReadPtr(rgprop, sizeof(SPropValue) * cprop),
|
|
TEXT("rgprop fails address check"));
|
|
|
|
AssertSz(!IsBadCodePtr((FARPROC)palloc), TEXT("palloc fails address check"));
|
|
|
|
AssertSz(!IsBadWritePtr(prgprop, sizeof(LPSPropValue)),
|
|
TEXT("prgprop fails address check"));
|
|
|
|
// Find out how much memory we need
|
|
if (sc = ScCountProps(cprop, rgprop, &cb))
|
|
goto ret;
|
|
// Obtain memory
|
|
if (sc = (*palloc)(cb, (LPVOID *)prgprop))
|
|
goto ret;
|
|
// Copy the properties
|
|
if (sc = ScCopyProps(cprop, rgprop, *prgprop, &cb))
|
|
goto ret;
|
|
|
|
ret:
|
|
DebugTraceSc(ScDupPropset, sc);
|
|
return sc;
|
|
}
|