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.
3954 lines
144 KiB
3954 lines
144 KiB
/*
|
|
* IPROP.C
|
|
*
|
|
* IProperty in memory
|
|
*/
|
|
#include "_apipch.h"
|
|
|
|
// #pragma SEGMENT(IProp)
|
|
|
|
//
|
|
// IPropData jump table is defined here...
|
|
//
|
|
|
|
|
|
IPDAT_Vtbl vtblIPDAT = {
|
|
VTABLE_FILL
|
|
(IPDAT_QueryInterface_METHOD FAR *) UNKOBJ_QueryInterface,
|
|
(IPDAT_AddRef_METHOD FAR *) UNKOBJ_AddRef,
|
|
IPDAT_Release,
|
|
(IPDAT_GetLastError_METHOD FAR *) UNKOBJ_GetLastError,
|
|
IPDAT_SaveChanges,
|
|
IPDAT_GetProps,
|
|
IPDAT_GetPropList,
|
|
IPDAT_OpenProperty,
|
|
IPDAT_SetProps,
|
|
IPDAT_DeleteProps,
|
|
IPDAT_CopyTo,
|
|
IPDAT_CopyProps,
|
|
IPDAT_GetNamesFromIDs,
|
|
IPDAT_GetIDsFromNames,
|
|
IPDAT_HrSetObjAccess,
|
|
IPDAT_HrSetPropAccess,
|
|
IPDAT_HrGetPropAccess,
|
|
IPDAT_HrAddObjProps
|
|
};
|
|
|
|
/* Interface which can be queried fro lpIPDAT.
|
|
*
|
|
* It is important that the order of the interfaces supported be preserved
|
|
* and that IID_IUnknown be the last in the list.
|
|
*/
|
|
IID const FAR * argpiidIPDAT[] =
|
|
{
|
|
&IID_IMAPIPropData,
|
|
&IID_IMAPIProp,
|
|
&IID_IUnknown
|
|
};
|
|
|
|
#define CIID_IPROP_INHERITS 1
|
|
#define CIID_IPROPDATA_INHERITS 2
|
|
|
|
/*
|
|
* Utility functions/macros used by iprop.
|
|
*/
|
|
|
|
#define AlignPropVal(_cb) Align8(_cb)
|
|
|
|
SCODE
|
|
ScDupNameID(LPIPDAT lpIPDAT,
|
|
LPVOID lpvBaseAlloc,
|
|
LPMAPINAMEID lpNameSrc,
|
|
LPMAPINAMEID * lppNameDest)
|
|
{
|
|
SCODE sc;
|
|
|
|
//
|
|
// Allocate space for the name
|
|
//
|
|
sc = UNKOBJ_ScAllocateMore( (LPUNKOBJ) lpIPDAT,
|
|
sizeof(MAPINAMEID),
|
|
lpvBaseAlloc,
|
|
lppNameDest);
|
|
if (FAILED(sc))
|
|
{
|
|
goto err;
|
|
}
|
|
MemCopy(*lppNameDest, lpNameSrc, sizeof(MAPINAMEID));
|
|
|
|
//
|
|
// Copy the lpguid
|
|
//
|
|
sc = UNKOBJ_ScAllocateMore( (LPUNKOBJ) lpIPDAT,
|
|
sizeof(GUID),
|
|
lpvBaseAlloc,
|
|
&((*lppNameDest)->lpguid));
|
|
if (FAILED(sc))
|
|
{
|
|
goto err;
|
|
}
|
|
MemCopy((*lppNameDest)->lpguid, lpNameSrc->lpguid, sizeof(GUID));
|
|
|
|
//
|
|
// conditionally copy the string
|
|
//
|
|
if (lpNameSrc->ulKind == MNID_STRING)
|
|
{
|
|
UINT cbString;
|
|
|
|
cbString = (lstrlenW(lpNameSrc->Kind.lpwstrName)+1)*sizeof(WCHAR);
|
|
|
|
//
|
|
// Copy the lpwstrName
|
|
//
|
|
sc = UNKOBJ_ScAllocateMore( (LPUNKOBJ) lpIPDAT,
|
|
cbString,
|
|
lpvBaseAlloc,
|
|
&((*lppNameDest)->Kind.lpwstrName));
|
|
if (FAILED(sc))
|
|
{
|
|
goto err;
|
|
}
|
|
MemCopy((*lppNameDest)->Kind.lpwstrName,
|
|
lpNameSrc->Kind.lpwstrName,
|
|
cbString);
|
|
}
|
|
|
|
out:
|
|
return sc;
|
|
|
|
err:
|
|
goto out;
|
|
}
|
|
|
|
SCODE
|
|
ScMakeMAPINames(LPIPDAT lpIPDAT,
|
|
LPSPropTagArray lpsPTaga,
|
|
LPMAPINAMEID ** lpppPropNames)
|
|
{
|
|
SCODE sc;
|
|
LPGUID lpMAPIGuid = NULL;
|
|
int iProp;
|
|
LPMAPINAMEID rgNames = NULL;
|
|
//
|
|
// First off, allocate enough space in lppPropNames
|
|
// to hold all the names.
|
|
//
|
|
|
|
sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT,
|
|
lpsPTaga->cValues*sizeof(LPMAPINAMEID),
|
|
(LPVOID *)lpppPropNames);
|
|
|
|
if (FAILED(sc))
|
|
{
|
|
goto out;
|
|
}
|
|
|
|
//
|
|
// Allocate the guid -
|
|
//$ Do I really need to do this?? bjd
|
|
//
|
|
sc = UNKOBJ_ScAllocateMore( (LPUNKOBJ) lpIPDAT,
|
|
sizeof(GUID),
|
|
*lpppPropNames,
|
|
&lpMAPIGuid);
|
|
if (FAILED(sc))
|
|
{
|
|
goto out;
|
|
}
|
|
MemCopy(lpMAPIGuid, (LPGUID) &PS_MAPI, sizeof(GUID));
|
|
|
|
//
|
|
// Allocate a block of MAPINAMEIDs
|
|
//
|
|
sc = UNKOBJ_ScAllocateMore( (LPUNKOBJ) lpIPDAT,
|
|
lpsPTaga->cValues*sizeof(MAPINAMEID),
|
|
*lpppPropNames,
|
|
&rgNames);
|
|
|
|
if (FAILED(sc))
|
|
{
|
|
goto out;
|
|
}
|
|
|
|
|
|
for (iProp = 0; iProp < (int) lpsPTaga->cValues; iProp++)
|
|
{
|
|
//
|
|
// First make the name
|
|
//
|
|
rgNames[iProp].lpguid = lpMAPIGuid;
|
|
rgNames[iProp].ulKind = MNID_ID;
|
|
rgNames[iProp].Kind.lID = PROP_ID(lpsPTaga->aulPropTag[iProp]);
|
|
|
|
//
|
|
// Now put it in the name array
|
|
//
|
|
(*lpppPropNames)[iProp] = &(rgNames[iProp]);
|
|
}
|
|
|
|
out:
|
|
return sc;
|
|
}
|
|
|
|
|
|
/*
|
|
* FreeLpLstSPV()
|
|
*
|
|
* Purpose:
|
|
* Releases objects and frees memory used by lpLstSPV.
|
|
* Handles NULL.
|
|
*
|
|
* Arguments
|
|
* lpIPDAT Pointer to IPropData object (alloc and free heap)
|
|
* lpLstSPV The property value list entry which is to be freed.
|
|
*
|
|
* Returns
|
|
* VOID
|
|
*
|
|
*/
|
|
VOID
|
|
FreeLpLstSPV( LPIPDAT lpIPDAT,
|
|
LPLSTSPV lpLstSPV)
|
|
{
|
|
|
|
if (!lpLstSPV)
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* Free the property list node. This also frees the property value
|
|
* and property name string.
|
|
*/
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpLstSPV);
|
|
}
|
|
|
|
|
|
/*
|
|
* LinkLstSPV()
|
|
*
|
|
* Purpose:
|
|
* Link a new property node after an existing property node in a singly
|
|
* linked list. lppLstLnk points to the element that will preceed
|
|
* the newly linked element. This element may be the list head.
|
|
*
|
|
* Arguments
|
|
* lppLstLnk Pointer to list entry (or list head) AFTER which
|
|
* lpLstLnk will be inserted.
|
|
* lpLstLnk The element to be inserted in the singly linked list.
|
|
*
|
|
* Returns
|
|
* VOID
|
|
*/
|
|
VOID
|
|
LinkLstLnk( LPLSTLNK FAR * lppLstLnk,
|
|
LPLSTLNK lpLstLnk)
|
|
{
|
|
/* Always insert at the head of the list.
|
|
*/
|
|
lpLstLnk->lpNext = *lppLstLnk;
|
|
*lppLstLnk = lpLstLnk;
|
|
}
|
|
|
|
|
|
/*
|
|
* UnlinkLstLNK()
|
|
*
|
|
* Purpose:
|
|
* Unlink the next element in the list. You pass a pointer the element
|
|
* before the one to be unlinked (this can be the list head).
|
|
*
|
|
* The input is typed as LPPLSTLNK because the element before the one to
|
|
* be unlinked should point to the one one that is to be linked.
|
|
*
|
|
* Arguments
|
|
* lppLstLnk Pointer to the element before the element that is to be
|
|
* unlinked from the singly linked list.
|
|
*
|
|
* Returns
|
|
* VOID
|
|
*/
|
|
VOID
|
|
UnlinkLstLnk( LPPLSTLNK lppLstLnk)
|
|
{
|
|
/* Unlink the element following the one passed in.
|
|
*/
|
|
if (*lppLstLnk)
|
|
{
|
|
((LPLSTLNK) lppLstLnk)->lpNext = (*lppLstLnk)->lpNext;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* lpplstspvFindProp()
|
|
*
|
|
* Purpose:
|
|
* Locate a property in the linked list of properties (lppLstSPV),
|
|
* return a pointer to pointer to it.
|
|
*
|
|
* Pointer to pointer is returned to make it easy to unlink the singly
|
|
* linked list entry if required.
|
|
*
|
|
* Arguments
|
|
* lppLstLnkHead Pointer to the head of a singly linked list which is
|
|
* to be searched. It may also point to the element
|
|
* before the first one to be searched if a partial list
|
|
* search (lppLstLnkHead->next to the end) is desired.
|
|
* ulPropTag The property tag for which a match is desired.
|
|
* NOTE! Only the PROP_ID portion is compared.
|
|
*
|
|
* Returns:
|
|
* NULL if the requested property is not in the list
|
|
* lppLstSPV to the property it found in the list.
|
|
*/
|
|
LPPLSTLNK
|
|
LPPLSTLNKFindProp( LPPLSTLNK lppLstLnkHead,
|
|
ULONG ulPropTag)
|
|
{
|
|
ULONG ulID2Find = PROP_ID(ulPropTag);
|
|
LPLSTLNK lpLstLnk;
|
|
LPPLSTLNK lppLstLnk;
|
|
|
|
for ( lpLstLnk = *lppLstLnkHead, lppLstLnk = lppLstLnkHead
|
|
; lpLstLnk
|
|
; lppLstLnk = (LPPLSTLNK) lpLstLnk, lpLstLnk = lpLstLnk->lpNext)
|
|
{
|
|
/* If this property matches the one we are looking for return a
|
|
* pointer to the one before it.
|
|
*/
|
|
if (ulID2Find == PROP_ID(lpLstLnk->ulKey))
|
|
{
|
|
return lppLstLnk;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
* ScCreateSPV()
|
|
*
|
|
* Purpose:
|
|
* Create a lstSPV for the given property and copy the property to it.
|
|
*
|
|
* Arguments
|
|
* lpIPDAT Pointer to IPropData object (alloc and free heap)
|
|
* lpPropToAdd Pointer to a property value for which a property value
|
|
* list entry is to be created.
|
|
* lppLstSPV Pointer to the memory location which will receive a pointer
|
|
* to the newly allocated list entry.
|
|
*
|
|
* Returns
|
|
* SCODE
|
|
*/
|
|
SCODE
|
|
ScCreateSPV(LPIPDAT lpIPDAT,
|
|
LPSPropValue lpPropToAdd,
|
|
LPLSTSPV FAR * lppLstSPV)
|
|
{
|
|
SCODE sc = S_OK;
|
|
LPLSTSPV lpLstSPV = NULL;
|
|
LPSPropValue lpPropNew = NULL;
|
|
ULONG cbToAllocate = 0;
|
|
|
|
|
|
/* Calculate the space needed to hold the entire property
|
|
*/
|
|
sc = ScCountProps( 1, lpPropToAdd, &cbToAllocate );
|
|
if (FAILED(sc))
|
|
{
|
|
DebugTrace(TEXT("ScCreateSPV() - ScCountProps failed (SCODE = 0x%08lX)\n"), sc );
|
|
goto error;
|
|
}
|
|
|
|
/* Account for the base LSTSPV.
|
|
*/
|
|
cbToAllocate += AlignPropVal(CBLSTSPV);
|
|
|
|
/* Allocate the whole chunk
|
|
*/
|
|
if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT, cbToAllocate, &lpLstSPV)))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
lpPropNew = (LPSPropValue) (((LPBYTE)lpLstSPV) + AlignPropVal(CBLSTSPV));
|
|
|
|
/* Initialize the property node.
|
|
*/
|
|
lpLstSPV->ulAccess = IPROP_READWRITE | IPROP_DIRTY;
|
|
lpLstSPV->lstlnk.ulKey = lpPropToAdd->ulPropTag;
|
|
|
|
/* Copy the property.
|
|
*/
|
|
if (sc = ScCopyProps(1, lpPropToAdd, lpPropNew, NULL))
|
|
{
|
|
DebugTrace(TEXT("ScCreateSPV() - Error copying prop (SCODE = 0x%08lX)\n"), sc );
|
|
goto error;
|
|
}
|
|
|
|
/* Link in the new property value...
|
|
*/
|
|
lpLstSPV->lpPropVal = lpPropNew;
|
|
|
|
/* ...and return the new property node.
|
|
*/
|
|
*lppLstSPV = lpLstSPV;
|
|
|
|
goto out;
|
|
|
|
error:
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpLstSPV);
|
|
|
|
out:
|
|
return sc;
|
|
}
|
|
|
|
|
|
SCODE
|
|
ScMakeNamePropList( LPIPDAT lpIPDAT,
|
|
ULONG ulCount,
|
|
LPLSTSPN lplstSpn,
|
|
LPSPropTagArray FAR * lppPropTagArray,
|
|
ULONG ulFlags,
|
|
LPGUID lpGuid)
|
|
{
|
|
SCODE sc;
|
|
UNALIGNED ULONG FAR * lpulPropTag;
|
|
|
|
|
|
if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT,
|
|
CbNewSPropTagArray(ulCount),
|
|
(LPVOID *) lppPropTagArray)))
|
|
{
|
|
return sc;
|
|
}
|
|
|
|
|
|
/* Initialize the count of PropTags to 0.
|
|
*/
|
|
(*lppPropTagArray)->cValues = 0;
|
|
|
|
for ( lpulPropTag = (*lppPropTagArray)->aulPropTag
|
|
; lplstSpn
|
|
; lplstSpn = (LPLSTSPN)lplstSpn->lstlnk.lpNext)
|
|
{
|
|
/* Set the next PropTag and increment the count of PropTags.
|
|
*/
|
|
|
|
//
|
|
// See if we have a guid to look for.
|
|
// If it's not the one we're looking for, then we keep looking.
|
|
//
|
|
if (lpGuid &&
|
|
(memcmp(lpGuid, lplstSpn->lpPropName->lpguid, sizeof(GUID))) )
|
|
continue;
|
|
|
|
//
|
|
// Three cases here:
|
|
// We don't want strings
|
|
// We don't want IDs
|
|
// We don't care - we want all.
|
|
//
|
|
if ( ((lplstSpn->lpPropName->ulKind == MNID_ID) &&
|
|
(ulFlags & MAPI_NO_IDS))
|
|
|| ((lplstSpn->lpPropName->ulKind == MNID_STRING) &&
|
|
(ulFlags & MAPI_NO_STRINGS)) )
|
|
continue;
|
|
|
|
//
|
|
// We want these tags
|
|
//
|
|
*lpulPropTag = lplstSpn->lstlnk.ulKey;
|
|
lpulPropTag++;
|
|
(*lppPropTagArray)->cValues++;
|
|
|
|
}
|
|
|
|
return sc;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* ScMakePropList
|
|
*
|
|
* Purpose:
|
|
* Allocate memory for, and fill in a complete list of properties for
|
|
* the given lpIPDAT.
|
|
*
|
|
* Arguments
|
|
* lpIPDAT Pointer to IPropData object (alloc and free heap)
|
|
* lppPropTagArray Pointer to the memory location which will receive a
|
|
* pointer to the newly allocated Tag array.
|
|
*
|
|
* Returns
|
|
* SCODE
|
|
*/
|
|
SCODE
|
|
ScMakePropList( LPIPDAT lpIPDAT,
|
|
ULONG ulCount,
|
|
LPLSTLNK lplstLink,
|
|
LPSPropTagArray FAR * lppPropTagArray,
|
|
ULONG ulUpperBound)
|
|
{
|
|
SCODE sc;
|
|
UNALIGNED ULONG FAR * lpulPropTag;
|
|
|
|
|
|
if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT,
|
|
CbNewSPropTagArray(ulCount),
|
|
(LPVOID *) lppPropTagArray)))
|
|
{
|
|
return sc;
|
|
}
|
|
|
|
|
|
/* Initialize the count of PropTags to 0.
|
|
*/
|
|
(*lppPropTagArray)->cValues = 0;
|
|
|
|
for ( lpulPropTag = (*lppPropTagArray)->aulPropTag
|
|
; lplstLink
|
|
; lplstLink = lplstLink->lpNext)
|
|
{
|
|
/* Set the next PropTag and increment the count of PropTags.
|
|
*/
|
|
if (PROP_ID(lplstLink->ulKey) < ulUpperBound) // Not <= !
|
|
{
|
|
*lpulPropTag = lplstLink->ulKey;
|
|
(*lppPropTagArray)->cValues++;
|
|
lpulPropTag++;
|
|
}
|
|
}
|
|
|
|
return sc;
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************
|
|
*
|
|
- CreateIProp
|
|
-
|
|
* Purpose
|
|
* Used for creating a property interface in memory.
|
|
*
|
|
*
|
|
* Arguments
|
|
* lpInterface Pointer to the interface ID of the object the caller
|
|
* wants. This should match IID_IMAPIPropData for the
|
|
* current version of IPROP.DLL.
|
|
* lpfAllocateBuffer Pointer to MAPI memory allocator.
|
|
* lpfAllocateMore Pointer to MAPI memory allocate more.
|
|
* lpfFreeBuffer Pointer to MAPI memory de-allocator.
|
|
* lppMAPIPropData Pointer to memory location which will receive a
|
|
* pointer to the new IMAPIPropData object.
|
|
*
|
|
* Notes
|
|
* The caller must insure the MAPI support object from which it drew the
|
|
* memory allocation routines is not Released before the new IPropData.
|
|
*
|
|
* Returns
|
|
* SCODE
|
|
*
|
|
*/
|
|
|
|
|
|
STDAPI_(SCODE)
|
|
CreateIProp(LPCIID lpInterface,
|
|
ALLOCATEBUFFER FAR *lpfAllocateBuffer,
|
|
ALLOCATEMORE FAR * lpfAllocateMore,
|
|
FREEBUFFER FAR * lpfFreeBuffer,
|
|
LPVOID lpvReserved,
|
|
LPPROPDATA FAR * lppMAPIPropData )
|
|
{
|
|
|
|
SCODE sc;
|
|
LPIPDAT lpIPDAT = NULL;
|
|
|
|
|
|
// validate paremeters
|
|
|
|
AssertSz( lpfAllocateBuffer && !IsBadCodePtr( (FARPROC)lpfAllocateBuffer ),
|
|
TEXT("lpfAllocateBuffer fails address check") );
|
|
|
|
AssertSz( !lpfAllocateMore || !IsBadCodePtr( (FARPROC)lpfAllocateMore ),
|
|
TEXT("lpfAllocateMore fails address check") );
|
|
|
|
AssertSz( !lpfFreeBuffer || !IsBadCodePtr( (FARPROC)lpfFreeBuffer ),
|
|
TEXT("lpfFreeBuffer fails address check") );
|
|
|
|
AssertSz( lppMAPIPropData && !IsBadWritePtr( lppMAPIPropData, sizeof( LPPROPDATA ) ),
|
|
TEXT("LppMAPIPropData fails address check") );
|
|
|
|
/* Make sure that the caller is asking for an object that we support.
|
|
*/
|
|
if ( lpInterface
|
|
&& !IsEqualGUID(lpInterface, &IID_IMAPIPropData))
|
|
{
|
|
sc = MAPI_E_INTERFACE_NOT_SUPPORTED;
|
|
goto error;
|
|
}
|
|
|
|
//
|
|
// Create a IPDAT per object for lpMAPIPropInternal so that it gets
|
|
// called first.
|
|
|
|
if (FAILED(sc = lpfAllocateBuffer(CBIPDAT, &lpIPDAT)))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
/* Init the object to 0, NULL
|
|
*/
|
|
memset( (BYTE *) lpIPDAT, 0, sizeof(*lpIPDAT));
|
|
|
|
/* Fill in the object specific instance data.
|
|
*/
|
|
lpIPDAT->inst.lpfAllocateBuffer = lpfAllocateBuffer;
|
|
lpIPDAT->inst.lpfAllocateMore = lpfAllocateMore;
|
|
lpIPDAT->inst.lpfFreeBuffer = lpfFreeBuffer;
|
|
|
|
#ifndef MAC
|
|
lpIPDAT->inst.hinst = hinstMapiX;//HinstMapi();
|
|
|
|
#ifdef DEBUG
|
|
if (lpIPDAT->inst.hinst == NULL)
|
|
TraceSz1( TEXT("IPROP: GetModuleHandle failed with error %08lX"),
|
|
GetLastError());
|
|
#endif /* DEBUG */
|
|
|
|
#else
|
|
lpIPDAT->inst.hinst = hinstMapiX;//(HINSTANCE) GetCurrentProcess();
|
|
#endif
|
|
|
|
|
|
/* Initialize the TEXT("standard") object.
|
|
* This must be the last operation that
|
|
* can fail. If not, explicitly call
|
|
* UNKOBJ_Deinit() for failures after
|
|
* a successful UNKOBJ_Init.
|
|
*/
|
|
if (FAILED(sc = UNKOBJ_Init( (LPUNKOBJ) lpIPDAT
|
|
, (UNKOBJ_Vtbl FAR *) &vtblIPDAT
|
|
, sizeof(vtblIPDAT)
|
|
, (LPIID FAR *) argpiidIPDAT
|
|
, dimensionof( argpiidIPDAT)
|
|
, &(lpIPDAT->inst))))
|
|
{
|
|
DebugTrace( TEXT("CreateIProp() - Error initializing IPDAT object (SCODE = 0x%08lX)\n"), sc );
|
|
goto error;
|
|
}
|
|
|
|
/* Initialize the defaults in IPROP specific part of the object.
|
|
*/
|
|
lpIPDAT->ulObjAccess = IPROP_READWRITE;
|
|
lpIPDAT->ulNextMapID = 0x8000;
|
|
|
|
*lppMAPIPropData = (LPPROPDATA) lpIPDAT;
|
|
|
|
return S_OK;
|
|
|
|
error:
|
|
if (lpIPDAT)
|
|
{
|
|
lpfFreeBuffer(lpIPDAT);
|
|
}
|
|
|
|
return sc;
|
|
}
|
|
|
|
|
|
|
|
|
|
// --------
|
|
// IUnknown
|
|
|
|
|
|
|
|
/*
|
|
- IPDAT_Release
|
|
-
|
|
* Purpose:
|
|
* Decrements reference count on the IPropData object and
|
|
* removes instance data if reference count becomes zero.
|
|
*
|
|
* Arguments:
|
|
* lpIPDAT The IPropData object to be released.
|
|
*
|
|
* Returns:
|
|
* Decremented reference count
|
|
*
|
|
* Side effects:
|
|
*
|
|
* Errors:
|
|
*/
|
|
STDMETHODIMP_(ULONG)
|
|
IPDAT_Release (LPIPDAT lpIPDAT)
|
|
{
|
|
ULONG ulcRef;
|
|
|
|
#if !defined(NO_VALIDATION)
|
|
/* Make sure the object is valid.
|
|
*/
|
|
if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, Release, lpVtbl))
|
|
{
|
|
DebugTrace( TEXT("IPDAT::Release() - Bad object passed\n") );
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
|
|
UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
ulcRef = --lpIPDAT->ulcRef;
|
|
UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
|
|
/* Free the object.
|
|
*
|
|
* No critical section lock is required since we are guaranteed to be
|
|
* the only thread accessing the object (ie ulcRef == 0).
|
|
*/
|
|
if (!ulcRef)
|
|
{
|
|
LPLSTLNK lpLstLnk;
|
|
LPLSTLNK lpLstLnkNext;
|
|
FREEBUFFER * lpfFreeBuffer;
|
|
|
|
/* Free the property value list.
|
|
*/
|
|
for ( lpLstLnk = (LPLSTLNK) (lpIPDAT->lpLstSPV); lpLstLnk; )
|
|
{
|
|
lpLstLnkNext = lpLstLnk->lpNext;
|
|
FreeLpLstSPV( lpIPDAT, (LPLSTSPV) lpLstLnk);
|
|
lpLstLnk = lpLstLnkNext;
|
|
}
|
|
|
|
/* Free the ID to NAME map list.
|
|
*/
|
|
for ( lpLstLnk = (LPLSTLNK) (lpIPDAT->lpLstSPN); lpLstLnk; )
|
|
{
|
|
lpLstLnkNext = lpLstLnk->lpNext;
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpLstLnk);
|
|
lpLstLnk = lpLstLnkNext;
|
|
}
|
|
|
|
/* Free the object.
|
|
*/
|
|
|
|
lpfFreeBuffer = lpIPDAT->inst.lpfFreeBuffer;
|
|
UNKOBJ_Deinit((LPUNKOBJ) lpIPDAT);
|
|
|
|
lpIPDAT->lpVtbl = NULL;
|
|
lpfFreeBuffer(lpIPDAT);
|
|
}
|
|
|
|
|
|
return ulcRef;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
- IPDAT_SaveChanges
|
|
-
|
|
* Purpose:
|
|
* This DOES not actually save changes since all changes (SetProps etc)
|
|
* become effective immediately. This method will invalidate or keep
|
|
* the IPropData object open depending on the flags passed in.
|
|
*
|
|
* Arguments:
|
|
* lpIPDAT IPropData object to save changes on.
|
|
* ulFlags KEEP_OPEN_READONLY
|
|
* KEEP_OPEN_READWRITE
|
|
* FORCE_SAVE (valid but no support)
|
|
*
|
|
* Returns:
|
|
* HRESULT
|
|
*
|
|
*/
|
|
STDMETHODIMP
|
|
IPDAT_SaveChanges (LPIPDAT lpIPDAT,
|
|
ULONG ulFlags)
|
|
{
|
|
SCODE sc = S_OK;
|
|
|
|
|
|
#if !defined(NO_VALIDATION)
|
|
/* Make sure the object is valid.
|
|
*/
|
|
if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, SaveChanges, lpVtbl))
|
|
{
|
|
DebugTrace( TEXT("IPDAT::SaveChanges() - Bad object passed\n") );
|
|
return ResultFromScode(MAPI_E_INVALID_PARAMETER);
|
|
}
|
|
|
|
Validate_IMAPIProp_SaveChanges( lpIPDAT, ulFlags );
|
|
|
|
#endif
|
|
|
|
/* The error exit assumes that we are already in a critical section.
|
|
*/
|
|
UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
|
|
|
|
//$REVIEW is this really needed?
|
|
/* Check object access rights.
|
|
*/
|
|
if (!(lpIPDAT->ulObjAccess & IPROP_READWRITE))
|
|
{
|
|
sc = MAPI_E_NO_ACCESS;
|
|
goto error;
|
|
}
|
|
|
|
|
|
/* IPROP objects are always up to date (saved to memory) so all
|
|
* we have to do is figure out whether and how to leave it open.
|
|
*/
|
|
if (!(ulFlags & (KEEP_OPEN_READONLY | KEEP_OPEN_READWRITE)))
|
|
{
|
|
/* We really should invalidate the object here but we have no
|
|
* clear cut way to call the MakeInvalid method since
|
|
* we don't have a pointer to the support object!
|
|
*/
|
|
//$REVIEW If we are ever going to hand the client an unwrapped interface
|
|
//$REVIEW to IMAPIProp then we must get our own support object!
|
|
|
|
sc = S_OK;
|
|
goto out;
|
|
}
|
|
|
|
//$BUG Combine the READWRITE and READONLY flags to IPROP_WRITABLE.
|
|
else if (ulFlags & KEEP_OPEN_READWRITE)
|
|
{
|
|
lpIPDAT->ulObjAccess |= IPROP_READWRITE;
|
|
lpIPDAT->ulObjAccess &= ~IPROP_READONLY;
|
|
}
|
|
|
|
else
|
|
{
|
|
lpIPDAT->ulObjAccess |= IPROP_READONLY;
|
|
lpIPDAT->ulObjAccess &= ~IPROP_READWRITE;
|
|
}
|
|
|
|
goto out;
|
|
|
|
|
|
error:
|
|
UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0);
|
|
|
|
out:
|
|
UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
|
|
return ResultFromScode(sc);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
- IPDAT_GetProps
|
|
-
|
|
* Purpose:
|
|
* Returns in lpcValues and lppPropArray the values of the properties
|
|
* in lpPropTagArray. If the latter is NULL, all properties available
|
|
* (except PT_OBJECT) from the IPropData object are returned.
|
|
*
|
|
* Arguments:
|
|
* lpIPDAT The IPropData object whose properties are requested.
|
|
* lpPropTagArray Pointer to a counted array of property tags of
|
|
* properties requested.
|
|
* lpcValues Pointer to the memory location which will receive the
|
|
* number of values returned.
|
|
* lppPropArray Pointer to the memory location which will receive the
|
|
* address of the returned property value array.
|
|
*
|
|
* Returns:
|
|
* HRESULT
|
|
*
|
|
* Notes:
|
|
* Now UNICODE enabled. If UNICODE is set, then any string properties
|
|
* not otherwise specified to be String8 are returned in UNICODE, otherwise
|
|
* unspecified string properties are in String8. String Properties with
|
|
* unspecified types occur when GetProps() is used with a NULL for the
|
|
* lpPropTagArray.
|
|
*
|
|
*/
|
|
STDMETHODIMP
|
|
IPDAT_GetProps (LPIPDAT lpIPDAT, LPSPropTagArray lpPropTagArray,
|
|
ULONG ulFlags,
|
|
ULONG FAR * lpcValues, LPSPropValue FAR * lppPropArray)
|
|
{
|
|
SCODE sc = S_OK;
|
|
ULONG ulcWarning = 0;
|
|
ULONG iProp = 0;
|
|
LPSPropValue lpPropValue = NULL;
|
|
|
|
#if !defined(NO_VALIDATION)
|
|
/* Make sure the object is valid.
|
|
*/
|
|
if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, GetProps, lpVtbl))
|
|
{
|
|
DebugTrace( TEXT("IPDAT::GetProps() - Bad object passed\n") );
|
|
return ResultFromScode(MAPI_E_INVALID_PARAMETER);
|
|
}
|
|
|
|
Validate_IMAPIProp_GetProps(lpIPDAT,
|
|
lpPropTagArray,
|
|
ulFlags,
|
|
lpcValues,
|
|
lppPropArray);
|
|
#endif
|
|
|
|
/* The error exit assumes that we are already in a critical section.
|
|
*/
|
|
UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
|
|
/* If they aren't asking for anything specific, then
|
|
* just copy what we have and be done with it.
|
|
*/
|
|
if (!lpPropTagArray)
|
|
{
|
|
LPLSTSPV lpLstSPV;
|
|
|
|
if (!lpIPDAT->ulCount)
|
|
{
|
|
/* iProp is initialized to 0 on entry. */
|
|
*lpcValues = iProp;
|
|
*lppPropArray = lpPropValue;
|
|
goto out;
|
|
}
|
|
|
|
/* Allocate space for all listed properties. Space allocated for
|
|
* properties which are not actually returned is simply wasted.
|
|
*/
|
|
//$REVIEW This would be a good place for a MAPI reallocBuf function.
|
|
if (sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT , lpIPDAT->ulCount * sizeof (SPropValue) , &lpPropValue))
|
|
{
|
|
//
|
|
// Memory error
|
|
//
|
|
goto error;
|
|
}
|
|
|
|
*lpcValues = 0;
|
|
|
|
/* iProp is initialized to 0 on method entry.
|
|
*/
|
|
for ( lpLstSPV = lpIPDAT->lpLstSPV; lpLstSPV; lpLstSPV = (LPLSTSPV) (lpLstSPV->lstlnk.lpNext))
|
|
{
|
|
/* Copy the property.
|
|
*/
|
|
switch (PROP_TYPE(lpLstSPV->lpPropVal->ulPropTag))
|
|
{
|
|
case PT_OBJECT:
|
|
case PT_NULL:
|
|
/* These properties with type PT_NULL and PT_OBJECT are handled
|
|
* specially. PropCopyMore doesn't handle them now.
|
|
*/
|
|
lpPropValue[iProp].ulPropTag = lpLstSPV->lpPropVal->ulPropTag;
|
|
iProp++;
|
|
break;
|
|
|
|
default:
|
|
if (FAILED(sc = PropCopyMore( &(lpPropValue[iProp]), (LPSPropValue) (lpLstSPV->lpPropVal),
|
|
lpIPDAT->inst.lpfAllocateMore, lpPropValue)))
|
|
{
|
|
goto error;
|
|
}
|
|
iProp++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Return the propValue array and the count of properties actually
|
|
* returned.
|
|
*/
|
|
*lpcValues = iProp;
|
|
*lppPropArray = lpPropValue;
|
|
|
|
// Handle UNICODE / String conversions depending on ulFlags
|
|
//
|
|
// Default WAB Handling is going to be in Unicode so don't need to worry about the MAPI_UNICODE
|
|
// flag. Only when the flag is not supplied do we have to provide the non-Unicode data
|
|
//
|
|
// We'll leave the Unicode code in place anyway for now
|
|
if (ulFlags & MAPI_UNICODE )
|
|
{
|
|
if(sc = ScConvertAPropsToW(lpIPDAT->inst.lpfAllocateMore, *lppPropArray, *lpcValues, 0))
|
|
goto error;
|
|
}
|
|
else
|
|
{
|
|
if(sc = ScConvertWPropsToA(lpIPDAT->inst.lpfAllocateMore, *lppPropArray, *lpcValues, 0))
|
|
goto error;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// So they want only specific properties
|
|
//
|
|
|
|
// Allocate space for the new stuff - enuf to give them all they want
|
|
if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT, lpPropTagArray->cValues * sizeof (SPropValue),
|
|
&lpPropValue)))
|
|
goto error;
|
|
|
|
//
|
|
// Go through the list of prop tags they want, find each one
|
|
// in lpIPDAT->lpLstSPV, and copy it over to lpPropValue
|
|
//
|
|
for (iProp = 0; iProp < lpPropTagArray->cValues; iProp++)
|
|
{
|
|
LPPLSTLNK lppLstLnk;
|
|
LPLSTSPV lpLstSPV;
|
|
ULONG ulProp2Find = lpPropTagArray->aulPropTag[iProp];
|
|
ULONG ulType2Find = PROP_TYPE(ulProp2Find);
|
|
|
|
/* If the property is in our list try to copy it.
|
|
*/
|
|
if ( (lppLstLnk = LPPLSTLNKFindProp( (LPPLSTLNK) &(lpIPDAT->lpLstSPV), ulProp2Find)) &&
|
|
(lpLstSPV = (LPLSTSPV) (*lppLstLnk)))
|
|
{
|
|
ULONG ulType2Check = PROP_TYPE(lpLstSPV->lpPropVal->ulPropTag);
|
|
|
|
/* Make sure the property value can be returned in the form the
|
|
* caller expects. If not then set a PT_ERROR scode and make
|
|
* sure we return an error.
|
|
*/
|
|
if (!( ((ulType2Find == PT_STRING8) && (ulType2Check == PT_UNICODE)) ||
|
|
((ulType2Find == PT_UNICODE) && (ulType2Check == PT_STRING8)) ||
|
|
((ulType2Find == PT_MV_STRING8) && (ulType2Check == PT_MV_UNICODE)) ||
|
|
((ulType2Find == PT_MV_UNICODE) && (ulType2Check == PT_MV_STRING8)) ))
|
|
{
|
|
if ( (ulType2Find != ulType2Check)
|
|
&& (ulType2Find != PT_UNSPECIFIED))
|
|
{
|
|
lpPropValue[iProp].ulPropTag = PROP_TAG( PT_ERROR , PROP_ID(ulProp2Find));
|
|
lpPropValue[iProp].Value.err = MAPI_E_INVALID_TYPE;
|
|
ulcWarning += 1;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/* Copy the property.
|
|
* Properties of these types are handled specially because
|
|
* PropCopyMore can't handle them now.
|
|
*/
|
|
if ( (ulType2Check == PT_OBJECT) || (ulType2Check == PT_NULL) || (ulType2Check == PT_ERROR))
|
|
{
|
|
MemCopy( (BYTE *) &(lpPropValue[iProp]), (BYTE *) (lpLstSPV->lpPropVal), sizeof(SPropValue));
|
|
}
|
|
else
|
|
{
|
|
// @todo [PaulHi] 1/19/99
|
|
// The problem with first copying the string properties and THEN converting
|
|
// them if necessary is that an allocation is preformed for each step. The
|
|
// original allocation isn't released until the property array is released.
|
|
// It would be more efficient (memory wise) to do the allocation once, after
|
|
// any necessary conversion is done. Vikram had special code to do this (similar
|
|
// to else condition below) but missed multi-valued strings. This makes for more
|
|
// complex and duplicate code. Should this code be changed accordingly?
|
|
|
|
// First copy the property
|
|
if (FAILED(sc = PropCopyMore( &(lpPropValue[iProp]), (LPSPropValue)(lpLstSPV->lpPropVal),
|
|
lpIPDAT->inst.lpfAllocateMore, lpPropValue)))
|
|
{
|
|
goto error;
|
|
}
|
|
//
|
|
// Next convert ANSI-UNICODE or UNICODE-ANSI as requested by caller
|
|
//
|
|
if ( ((ulType2Find == PT_UNICODE) && (ulType2Check == PT_STRING8)) ||
|
|
((ulType2Find == PT_MV_UNICODE) && (ulType2Check == PT_MV_STRING8)) )
|
|
{
|
|
// Convert single or multiple value ANSI store string to UNICODE
|
|
if(FAILED(sc = ScConvertAPropsToW(lpIPDAT->inst.lpfAllocateMore, lpPropValue, iProp+1, iProp)))
|
|
goto error;
|
|
}
|
|
else if ( ((ulType2Find == PT_STRING8) && (ulType2Check == PT_UNICODE)) ||
|
|
((ulType2Find == PT_MV_STRING8) && (ulType2Check == PT_MV_UNICODE)) )
|
|
{
|
|
// Convert single or multiple value UNICODE store string to ANSI
|
|
if(FAILED(sc = ScConvertWPropsToA(lpIPDAT->inst.lpfAllocateMore, lpPropValue, iProp+1, iProp)))
|
|
goto error;
|
|
}
|
|
}
|
|
}
|
|
/* Property wasn't found.
|
|
*/
|
|
else
|
|
{
|
|
//
|
|
// [PaulHi] 1/14/99 Raid 63006
|
|
// If a property of type PR_EMAIL_ADDRESS was requested and not found
|
|
// then check to see if an email address is in the multi-valued
|
|
// PR_CONTACT_EMAIL_ADDRESSES property. If so copy the first email
|
|
// address to the PR_EMAIL_ADDRESS slot.
|
|
//
|
|
ULONG ulProp2Check = PR_EMAIL_ADDRESS;
|
|
if (PROP_ID(ulProp2Find) == PROP_ID(ulProp2Check) )
|
|
{
|
|
// Look for a PR_CONTACT_EMAIL_ADDRESSES property
|
|
LPPLSTLNK lppLstLnk;
|
|
LPLSTSPV lpLstSPV;
|
|
ULONG ulNewProp2Find = PR_CONTACT_EMAIL_ADDRESSES;
|
|
|
|
if ( (lppLstLnk = LPPLSTLNKFindProp((LPPLSTLNK) &(lpIPDAT->lpLstSPV), ulNewProp2Find)) &&
|
|
(lpLstSPV = (LPLSTSPV) (*lppLstLnk)) )
|
|
{
|
|
ULONG ulType2Check = PROP_TYPE(lpLstSPV->lpPropVal->ulPropTag);
|
|
BYTE * pPropBuf = NULL;
|
|
UINT cBufSize = 0;
|
|
|
|
// We know that we looked up a MV string so just check for ANSI
|
|
// or UNICODE property types
|
|
if (ulType2Check == PT_MV_STRING8)
|
|
{
|
|
LPSTR lpstr = NULL;
|
|
|
|
//
|
|
// Get the first ANSI email string in array
|
|
//
|
|
if ( ((LPSPropValue)(lpLstSPV->lpPropVal))->Value.MVszA.cValues == 0 )
|
|
{
|
|
Assert(0);
|
|
goto convert_error;
|
|
}
|
|
lpstr = ((LPSPropValue)(lpLstSPV->lpPropVal))->Value.MVszA.lppszA[0];
|
|
cBufSize = lstrlenA(lpstr)+1;
|
|
|
|
// If caller requested UNICODE then convert before allocating MAPI
|
|
// buffer space
|
|
if (ulType2Find == PT_UNICODE)
|
|
{
|
|
// Allocate room for the new UNICODE string
|
|
if ( lpIPDAT->inst.lpfAllocateMore((cBufSize * sizeof(WCHAR)), lpPropValue, &pPropBuf) )
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
if ( MultiByteToWideChar(CP_ACP, 0, lpstr, -1, (LPWSTR)pPropBuf, cBufSize) == 0 )
|
|
{
|
|
Assert(0);
|
|
goto convert_error;
|
|
}
|
|
|
|
// Assign property and fix up property tag
|
|
lpPropValue[iProp].ulPropTag = PROP_TAG(PT_UNICODE, PROP_ID(ulProp2Find));
|
|
lpPropValue[iProp].Value.lpszW = (LPWSTR)pPropBuf;
|
|
}
|
|
else
|
|
{
|
|
// Otherwise just copy string property to property value
|
|
// array
|
|
|
|
// Allocate room for the new ANSI string
|
|
if (lpIPDAT->inst.lpfAllocateMore(cBufSize, lpPropValue, &pPropBuf))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
// Copy property and fix up property tag
|
|
MemCopy((BYTE *)pPropBuf, (BYTE *)lpstr, cBufSize);
|
|
lpPropValue[iProp].ulPropTag = PROP_TAG(PT_STRING8, PROP_ID(ulProp2Find));
|
|
lpPropValue[iProp].Value.lpszA = (LPSTR)pPropBuf;
|
|
}
|
|
}
|
|
else if (ulType2Check == PT_MV_UNICODE)
|
|
{
|
|
LPWSTR lpwstr = NULL;
|
|
|
|
//
|
|
// Get the first UNICODE email string in array
|
|
//
|
|
if ( ((LPSPropValue)(lpLstSPV->lpPropVal))->Value.MVszW.cValues == 0 )
|
|
{
|
|
Assert(0);
|
|
goto convert_error;
|
|
}
|
|
lpwstr = ((LPSPropValue)(lpLstSPV->lpPropVal))->Value.MVszW.lppszW[0];
|
|
|
|
// If caller requested ANSI then convert before allocating MAPI
|
|
// buffer space
|
|
if (ulType2Find == PT_STRING8)
|
|
{
|
|
cBufSize = WideCharToMultiByte(CP_ACP, 0, lpwstr, -1, NULL, 0, NULL, NULL) + 1;
|
|
|
|
// Allocate room for the new ANSI string
|
|
if ( lpIPDAT->inst.lpfAllocateMore(cBufSize, lpPropValue, &pPropBuf) )
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
if ( WideCharToMultiByte(CP_ACP, 0, lpwstr, -1, (LPSTR)pPropBuf, cBufSize, NULL, NULL) == 0 )
|
|
{
|
|
Assert(0);
|
|
goto convert_error;
|
|
}
|
|
|
|
// Assign property and fix up property tag
|
|
lpPropValue[iProp].ulPropTag = PROP_TAG(PT_STRING8, PROP_ID(ulProp2Find));
|
|
lpPropValue[iProp].Value.lpszA = (LPSTR)pPropBuf;
|
|
}
|
|
else
|
|
{
|
|
// Otherwise just copy string property to property value
|
|
// array
|
|
|
|
cBufSize = lstrlenW(lpwstr)+1;
|
|
|
|
// Allocate room for the new UNICODE string
|
|
if (lpIPDAT->inst.lpfAllocateMore((sizeof(WCHAR) * cBufSize), lpPropValue, &pPropBuf))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
// Copy property and fix up property tag
|
|
MemCopy((BYTE *)pPropBuf, (BYTE *)lpwstr, (sizeof(WCHAR) * cBufSize));
|
|
lpPropValue[iProp].ulPropTag = PROP_TAG(PT_UNICODE, PROP_ID(ulProp2Find));
|
|
lpPropValue[iProp].Value.lpszW = (LPWSTR)pPropBuf;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Assert(0);
|
|
goto convert_error;
|
|
}
|
|
|
|
// Success
|
|
continue;
|
|
}
|
|
}
|
|
|
|
convert_error:
|
|
|
|
// Otherwise return error for this property
|
|
lpPropValue[iProp].ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(ulProp2Find));
|
|
lpPropValue[iProp].Value.err = MAPI_E_NOT_FOUND;
|
|
|
|
/* Increment the warning count to trigger MAPI_W_ERRORS_RETURNED.
|
|
*/
|
|
ulcWarning += 1;
|
|
}
|
|
}
|
|
|
|
*lpcValues = iProp;
|
|
*lppPropArray = lpPropValue;
|
|
}
|
|
|
|
// [PaulHi] 1/15/99
|
|
// Mass property conversion (ANIS/UNICODE) should only be done when the caller
|
|
// doesn't specifically request property tag types.
|
|
#if 0
|
|
//
|
|
// Handle UNICODE / String conversions depending on ulFlags
|
|
//
|
|
// Default WAB Handling is going to be in Unicode so don't need to worry about the MAPI_UNICODE
|
|
// flag. Only when the flag is not supplied do we have to provide the non-Unicode data
|
|
//
|
|
// We'll leave the Unicode code in place anyway for now
|
|
|
|
if (ulFlags & MAPI_UNICODE )
|
|
{
|
|
if(sc = ScConvertAPropsToW(lpIPDAT->inst.lpfAllocateMore, *lppPropArray, *lpcValues, 0))
|
|
goto error;
|
|
}
|
|
else
|
|
{
|
|
if(sc = ScConvertWPropsToA(lpIPDAT->inst.lpfAllocateMore, *lppPropArray, *lpcValues, 0))
|
|
goto error;
|
|
}
|
|
#endif
|
|
|
|
goto out;
|
|
|
|
error:
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpPropValue );
|
|
UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0);
|
|
|
|
out:
|
|
if (ulcWarning)
|
|
sc = MAPI_W_ERRORS_RETURNED;
|
|
|
|
UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
return ResultFromScode(sc);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
- IPDAT_GetPropList
|
|
-
|
|
* Purpose:
|
|
* Returns in lpPropTagArray the list of all currently available properties
|
|
* (including PT_OBJECT) in the IPropData object.
|
|
*
|
|
* Now supports UNICODE flag in ulFlag. Conversion of String Proptags based
|
|
* whether MAPI_UNICODE is set or not.
|
|
*
|
|
* Arguments:
|
|
* lpIPDAT The IPropData object whose properties are requested.
|
|
* lppPropTagArray Pointer to the memory location which will receive
|
|
* a property tag array of the listed properties.
|
|
* Returns:
|
|
* HRESULT
|
|
*
|
|
*/
|
|
STDMETHODIMP
|
|
IPDAT_GetPropList (LPIPDAT lpIPDAT,
|
|
ULONG ulFlags,
|
|
LPSPropTagArray FAR * lppPropTagArray)
|
|
{
|
|
SCODE sc = S_OK;
|
|
ULONG uTagA = 0, uTagW = 0, iTag = 0;
|
|
|
|
#if !defined(NO_VALIDATION)
|
|
/* Make sure the object is valid.
|
|
*/
|
|
if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, GetPropList, lpVtbl))
|
|
{
|
|
DebugTrace( TEXT("IPDAT::GetPropList() - Bad object passed\n") );
|
|
return ResultFromScode(MAPI_E_INVALID_PARAMETER);
|
|
}
|
|
|
|
Validate_IMAPIProp_GetPropList( lpIPDAT, ulFlags, lppPropTagArray );
|
|
|
|
#endif // not NO_VALIDATION
|
|
|
|
/* The error exit assumes that we are already in a critical section.
|
|
*/
|
|
UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
|
|
sc = ScMakePropList( lpIPDAT, lpIPDAT->ulCount, (LPLSTLNK) lpIPDAT->lpLstSPV,
|
|
lppPropTagArray, (ULONG) -1 );
|
|
if ( FAILED( sc ) )
|
|
goto error;
|
|
|
|
// Support for UNICODE / String8
|
|
for ( iTag = 0; iTag < (*lppPropTagArray)->cValues; iTag++ )
|
|
{
|
|
uTagA = uTagW = 0;
|
|
switch(PROP_TYPE( (*lppPropTagArray)->aulPropTag[iTag] ))
|
|
{
|
|
case PT_STRING8:
|
|
uTagW = PT_UNICODE;
|
|
break;
|
|
case PT_MV_STRING8:
|
|
uTagW = PT_MV_UNICODE;
|
|
break;
|
|
case PT_UNICODE:
|
|
uTagA = PT_STRING8;
|
|
break;
|
|
case PT_MV_UNICODE:
|
|
uTagA = PT_MV_STRING8;
|
|
break;
|
|
default:
|
|
continue;
|
|
break;
|
|
}
|
|
if ( ulFlags & MAPI_UNICODE && uTagW)
|
|
(*lppPropTagArray)->aulPropTag[iTag] = CHANGE_PROP_TYPE( (*lppPropTagArray)->aulPropTag[iTag], uTagW);
|
|
else if ( ulFlags & ~MAPI_UNICODE && uTagA)
|
|
(*lppPropTagArray)->aulPropTag[iTag] = CHANGE_PROP_TYPE( (*lppPropTagArray)->aulPropTag[iTag], uTagA);
|
|
}
|
|
|
|
goto out;
|
|
|
|
error:
|
|
UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0);
|
|
|
|
out:
|
|
UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
|
|
return MakeResult(sc);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
- IPDAT_OpenProperty
|
|
-
|
|
* Purpose:
|
|
* OpenProperty is not supported for IPROP.DLL. It will, however, validate
|
|
* the input parameters.
|
|
*
|
|
* Arguments:
|
|
* lpIPDAT The IPropData object which contains the property/
|
|
* ulPropTag Property tag for the desired property.
|
|
* lpiid Pointer to the ID for the requested interface.
|
|
* ulInterfaceOptions Specifies interface-specific behavior
|
|
* ulFlags MAPI_CREATE, MAPI_MODIFY, MAPI_DEFERRED_ERRORS
|
|
* lppUnk Pointer to the newly created interface pointer
|
|
*
|
|
* Returns:
|
|
* HRESULT
|
|
*
|
|
*/
|
|
STDMETHODIMP
|
|
IPDAT_OpenProperty (LPIPDAT lpIPDAT,
|
|
ULONG ulPropTag,
|
|
LPCIID lpiid,
|
|
ULONG ulInterfaceOptions,
|
|
ULONG ulFlags,
|
|
LPUNKNOWN FAR * lppUnk)
|
|
{
|
|
SCODE sc = S_OK;
|
|
|
|
|
|
#if !defined(NO_VALIDATION)
|
|
/* Make sure the object is valid.
|
|
*/
|
|
if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, OpenProperty, lpVtbl))
|
|
{
|
|
DebugTrace( TEXT("IPDAT::OpenProperty() - Bad object passed\n") );
|
|
return ResultFromScode(MAPI_E_INVALID_PARAMETER);
|
|
}
|
|
|
|
Validate_IMAPIProp_OpenProperty(
|
|
lpIPDAT,
|
|
ulPropTag,
|
|
lpiid,
|
|
ulInterfaceOptions,
|
|
ulFlags,
|
|
lppUnk);
|
|
|
|
#endif // not NO_VALIDATION
|
|
|
|
/* The error exit assumes that we are already in a critical section.
|
|
*/
|
|
UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
|
|
|
|
/* We don't support OpenProperty.
|
|
*/
|
|
sc = MAPI_E_INTERFACE_NOT_SUPPORTED;
|
|
|
|
/*
|
|
*error:
|
|
*/
|
|
UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0);
|
|
|
|
/*
|
|
*out:
|
|
*/
|
|
UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
|
|
return MakeResult(sc);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
- IPDAT_SetProps
|
|
-
|
|
* Purpose:
|
|
* Sets the properties listed in <lpPropArray>.
|
|
* Returns an array of problems in <lppProblems> if there were any,
|
|
* NULL If there weren't any.
|
|
*
|
|
* Arguments:
|
|
* lpIPDAT The IPropData object whose properties are to be set.
|
|
* cValues The count of properties to be set.
|
|
* lpPropArray Pointer to a an array of <cValues> property value
|
|
* structures.
|
|
* lppProblems Pointer to memory location which will receive a
|
|
* pointer to a problem array if non-catastrophic
|
|
* errors occur. NULL if no problem array is desired.
|
|
*
|
|
* Returns:
|
|
* HRESULT
|
|
*
|
|
*/
|
|
STDMETHODIMP
|
|
IPDAT_SetProps (LPIPDAT lpIPDAT,
|
|
ULONG cValues,
|
|
LPSPropValue lpPropArray,
|
|
LPSPropProblemArray FAR * lppProblems)
|
|
{
|
|
SCODE sc = S_OK;
|
|
int iProp = 0;
|
|
LPLSTSPV lpLstSPVNew = NULL;
|
|
LPSPropProblemArray lpProblems = NULL;
|
|
LPSPropValue lpPropToAdd = NULL;
|
|
|
|
#if !defined(NO_VALIDATION)
|
|
// Make sure the object is valid.
|
|
if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, SetProps, lpVtbl))
|
|
{
|
|
DebugTrace( TEXT("IPDAT::SetProps() - Bad object passed\n") );
|
|
return ResultFromScode(MAPI_E_INVALID_PARAMETER);
|
|
}
|
|
|
|
Validate_IMAPIProp_SetProps( lpIPDAT, cValues, lpPropArray, lppProblems);
|
|
#endif // not NO_VALIDATION
|
|
|
|
/* The error exit assumes that we are already in a critical section.
|
|
*/
|
|
UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
|
|
/* Check access rights...
|
|
*/
|
|
if (!(lpIPDAT->ulObjAccess & IPROP_READWRITE))
|
|
{
|
|
sc = MAPI_E_NO_ACCESS;
|
|
goto error;
|
|
}
|
|
|
|
|
|
if (lppProblems)
|
|
{
|
|
/* Initially indicate no problems.
|
|
*/
|
|
*lppProblems = NULL;
|
|
|
|
/* Allocate the property problem array.
|
|
* Because we expect the property list to be of TEXT("reasonable") size we
|
|
* go ahead and allocate enough entries for every property to have a
|
|
* problem.
|
|
*/
|
|
//$REVIEW This is a place where a MAPI reallocBuf function would be useful.
|
|
if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT
|
|
, CbNewSPropProblemArray(cValues)
|
|
, &lpProblems)))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
lpProblems->cProblem = 0;
|
|
}
|
|
|
|
|
|
/* Loop through the list of properties to set..
|
|
*/
|
|
for (iProp = 0; iProp < (int)cValues; iProp++)
|
|
{
|
|
ULONG ulProp2Find = lpPropArray[iProp].ulPropTag;
|
|
LPPLSTLNK lppLstLnk;
|
|
LPLSTSPV lpLstSPV;
|
|
|
|
/* Reset the temp prop name and value pointers so we don't accidentally
|
|
* free the wrong one on an error.
|
|
*/
|
|
lpLstSPVNew = NULL;
|
|
|
|
lpPropToAdd = NULL;
|
|
|
|
/* Ignore properties with type PT_ERROR or PR_NULL.
|
|
*/
|
|
if ((PROP_TYPE(ulProp2Find) == PT_ERROR) || (ulProp2Find == PR_NULL))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
/* PT_OBJECT and PT_UNSPECIFIED properties get caught in parameter
|
|
* validation.
|
|
*/
|
|
|
|
/* If a writable property with the given tag already exists then
|
|
* delete it (we will create another version of it later).
|
|
*
|
|
* If a readonly property with the given tag already exists then
|
|
* include an error in the problem array.
|
|
*/
|
|
|
|
if ( (lppLstLnk = LPPLSTLNKFindProp( (LPPLSTLNK) &(lpIPDAT->lpLstSPV) , ulProp2Find))
|
|
&& (lpLstSPV = (LPLSTSPV) (*lppLstLnk)))
|
|
{
|
|
/* If it is readonly then put an entry into the problem
|
|
* array.
|
|
*/
|
|
if (!(lpLstSPV->ulAccess & IPROP_READWRITE))
|
|
{
|
|
AddProblem( lpProblems
|
|
, iProp
|
|
, lpPropArray[iProp].ulPropTag
|
|
, MAPI_E_NO_ACCESS);
|
|
|
|
goto nextProp;
|
|
}
|
|
|
|
/* Unlink the found property and free its memory.
|
|
*/
|
|
UnlinkLstLnk( lppLstLnk);
|
|
lpIPDAT->ulCount -= 1;
|
|
FreeLpLstSPV( lpIPDAT, lpLstSPV);
|
|
}
|
|
|
|
// Native string storage within the WAB is now in UNICODE
|
|
// so if any property being set on the object is in ANSI/DBCS .. convert this to UNICODE
|
|
// before trying to add it here ..
|
|
if( PROP_TYPE(lpPropArray[iProp].ulPropTag) == PT_STRING8 ||
|
|
PROP_TYPE(lpPropArray[iProp].ulPropTag) == PT_MV_STRING8 )
|
|
{
|
|
// Create a temp copy of this sepcific property array so that we can munge the
|
|
// data .. I would rather not munge the original array because caller might expect to use it
|
|
// .. there's no gaurantee its safely modifiable
|
|
//
|
|
ULONG cbToAllocate = 0;
|
|
|
|
sc = ScCountProps( 1, &(lpPropArray[iProp]), &cbToAllocate );
|
|
if (FAILED(sc))
|
|
{
|
|
DebugTrace(TEXT("SetProps() - ScCountProps failed (SCODE = 0x%08lX)\n"), sc );
|
|
goto error;
|
|
}
|
|
|
|
/* Allocate the whole chunk
|
|
*/
|
|
if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT, cbToAllocate, &lpPropToAdd)))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
/* Copy the property.
|
|
*/
|
|
if (sc = ScCopyProps(1, &(lpPropArray[iProp]), lpPropToAdd, NULL))
|
|
{
|
|
DebugTrace(TEXT("SetProps() - Error copying prop (SCODE = 0x%08lX)\n"), sc );
|
|
goto error;
|
|
}
|
|
|
|
// Now convert all the strings in this temp duplicate
|
|
if ( sc = ScConvertAPropsToW(lpIPDAT->inst.lpfAllocateMore, lpPropToAdd, 1, 0))
|
|
{
|
|
DebugTrace(TEXT("SetProps() - error convert W to A\n"));
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
/* Create a new property value list entry.
|
|
*
|
|
* NOTE! This automatically marks the property as dirty and writeable.
|
|
*/
|
|
if (FAILED(sc = ScCreateSPV( lpIPDAT,
|
|
lpPropToAdd ? lpPropToAdd : &(lpPropArray[iProp]),
|
|
&lpLstSPVNew)))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
/* Link the new property to our list of props.
|
|
*/
|
|
LinkLstLnk( (LPLSTLNK FAR *) &(lpIPDAT->lpLstSPV)
|
|
, &(lpLstSPVNew->lstlnk));
|
|
lpIPDAT->ulCount += 1;
|
|
|
|
nextProp:
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpPropToAdd);
|
|
}
|
|
|
|
if (lppProblems && lpProblems->cProblem)
|
|
{
|
|
*lppProblems = lpProblems;
|
|
}
|
|
|
|
else
|
|
{
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpProblems);
|
|
}
|
|
|
|
goto out;
|
|
|
|
|
|
error:
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpLstSPVNew);
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpProblems);
|
|
UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0);
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpPropToAdd);
|
|
|
|
out:
|
|
UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
|
|
return MakeResult(sc);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
- IPDAT_DeleteProps
|
|
-
|
|
* Purpose:
|
|
* Deletes the properties listed in lpPropTagArray from the IPropData
|
|
* object. Returns a list of problems in <lppProblems) if there were
|
|
* problems deleting specific properties, NULL If there weren't any.
|
|
*
|
|
* Arguments:
|
|
* lpIPDAT The IPropData object whose properties are to be
|
|
* deleted.
|
|
* lpPropTagArray Pointer to a counted array of property tags of the
|
|
* properties to be deleted. Must not be NULL.
|
|
* lppProblems Pointer to address of a property problem structure
|
|
* to be returned. NULL if no problem array is
|
|
* desired.
|
|
* Returns:
|
|
* HRESULT
|
|
*/
|
|
STDMETHODIMP
|
|
IPDAT_DeleteProps( LPIPDAT lpIPDAT,
|
|
LPSPropTagArray lpPropTagArray,
|
|
LPSPropProblemArray FAR *lppProblems)
|
|
{
|
|
SCODE sc = S_OK;
|
|
LPSPropProblemArray lpProblems = NULL;
|
|
int iProp;
|
|
LPULONG lpulProp2Find;
|
|
|
|
|
|
#if !defined(NO_VALIDATION)
|
|
/* Make sure the object is valid.
|
|
*/
|
|
if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, DeleteProps, lpVtbl))
|
|
{
|
|
DebugTrace( TEXT("IPDAT::DeleteProps() - Bad object passed\n") );
|
|
return ResultFromScode(MAPI_E_INVALID_PARAMETER);
|
|
}
|
|
|
|
Validate_IMAPIProp_DeleteProps( lpIPDAT, lpPropTagArray, lppProblems );
|
|
|
|
#endif // not NO_VALIDATION
|
|
|
|
/* The error exit assumes that we are already in a critical section.
|
|
*/
|
|
UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
|
|
|
|
/* Check access rights...
|
|
*/
|
|
if (!(lpIPDAT->ulObjAccess & IPROP_READWRITE))
|
|
{
|
|
sc = MAPI_E_NO_ACCESS;
|
|
goto error;
|
|
}
|
|
|
|
|
|
if (lppProblems)
|
|
{
|
|
/* Initially indicate no problems.
|
|
*/
|
|
*lppProblems = NULL;
|
|
|
|
/* Allocate the property problem array.
|
|
* Because we expect the property list to be of TEXT("reasonable") size we
|
|
* go ahead and allocate enough entries for every property to have a
|
|
* problem.
|
|
*/
|
|
//$REVIEW This is a place where a MAPI reallocBuf function would be useful.
|
|
if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT
|
|
, CbNewSPropProblemArray(lpPropTagArray->cValues)
|
|
, &lpProblems)))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
lpProblems->cProblem = 0;
|
|
}
|
|
|
|
|
|
// Loop through the list of properties to delete..
|
|
for ( iProp = 0, lpulProp2Find = ((LPULONG)(lpPropTagArray->aulPropTag))
|
|
; iProp < (int)(lpPropTagArray->cValues)
|
|
; lpulProp2Find++, iProp++)
|
|
{
|
|
LPPLSTLNK lppLstLnk;
|
|
LPLSTSPV lpLstSPV;
|
|
|
|
/* If a writable property with the given ID already exists then
|
|
* delete it.
|
|
*
|
|
* If a readonly property with the given ID already exists then
|
|
* include an error in the problem array.
|
|
*/
|
|
|
|
if ( (lppLstLnk = LPPLSTLNKFindProp( (LPPLSTLNK) &(lpIPDAT->lpLstSPV)
|
|
, *lpulProp2Find))
|
|
&& (lpLstSPV = (LPLSTSPV) (*lppLstLnk)))
|
|
{
|
|
/* If it is readonly then put an entry into the problem
|
|
* array.
|
|
*/
|
|
if (!(lpLstSPV->ulAccess & IPROP_READWRITE))
|
|
{
|
|
AddProblem( lpProblems
|
|
, iProp
|
|
, *lpulProp2Find
|
|
, MAPI_E_NO_ACCESS);
|
|
|
|
continue;
|
|
}
|
|
|
|
/* Unlink the found property and free its memory.
|
|
*/
|
|
UnlinkLstLnk( lppLstLnk);
|
|
lpIPDAT->ulCount -= 1;
|
|
FreeLpLstSPV( lpIPDAT, lpLstSPV);
|
|
}
|
|
}
|
|
|
|
if (lppProblems && lpProblems->cProblem)
|
|
{
|
|
*lppProblems = lpProblems;
|
|
}
|
|
|
|
else
|
|
{
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpProblems);
|
|
}
|
|
|
|
goto out;
|
|
|
|
|
|
error:
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpProblems);
|
|
UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0);
|
|
|
|
out:
|
|
UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
|
|
return MakeResult(sc);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Name: FTagExists()
|
|
//
|
|
// Description:
|
|
// Determines if a Proptag exists in proptag array.
|
|
//
|
|
// Parameters:
|
|
// Returns:
|
|
// Effects:
|
|
// Notes:
|
|
// Revision:
|
|
//---------------------------------------------------------------------------
|
|
static BOOL FTagExists( LPSPropTagArray lptaga, ULONG ulTagToFind )
|
|
{
|
|
LONG ctag = (LONG)lptaga->cValues - 1;
|
|
|
|
for ( ; ctag >= 0; --ctag )
|
|
{
|
|
if ( lptaga->aulPropTag[ctag] == ulTagToFind )
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
- HrCopyProps
|
|
-
|
|
* Purpose:
|
|
* Copies properties from an IPropData object to
|
|
* another object with an IMAPIProp interface.
|
|
*
|
|
* If lpptaInclude is not null then only properties listed by it will
|
|
* be copied. If lpptaExclude is not NULL then none of the properties
|
|
* listed by it will be copied regardless of whether they appear in
|
|
* lpptaInclude. PROP_TYPEs in lpptaInclude and lpptaExclude are
|
|
* ignored.
|
|
*
|
|
* Property names are copied!
|
|
* If a property is named in the source object (lpIPDAT) and the name
|
|
* does not exist in the destination object, a new named property ID
|
|
* will be requested from the destination
|
|
*
|
|
* If the IMAPIPropData interface is supplied for the destination
|
|
* then individual property access flags will be copied to the destination.
|
|
*
|
|
* Arguments:
|
|
* lpIPDATSrc The source IPropData object.
|
|
* lpIPDATDst The destination IPropData object. May be NULL.
|
|
* lpmpDst The destination IMAPIProp object. May NOT be NULL.
|
|
* lpptaInclude Pointer to a counted array of property tags of
|
|
* properties that will be copied. May be NULL.
|
|
* lpptaExclude Pointer to a counted array of property tags of
|
|
* properties not to be copied. May be NULL.
|
|
* ulFlags MAPI_MOVE
|
|
* MAPI_NOREPLACE
|
|
* MAPI_DIALOG (not supported)
|
|
* MAPI_STD_DIALOG (not supported)
|
|
* lppProblems Pointer to memory location which will receive a
|
|
* pointer the the list of problems. NULL if no
|
|
* propblem array is desired.
|
|
*
|
|
* Returns:
|
|
* HRESULT
|
|
*
|
|
* Side effects:
|
|
*
|
|
* Notes:
|
|
*
|
|
* Rewrote copy prop handling to call Destination MAPIProp object twice. Once
|
|
* for Names to ID mappings and the other for one SetProps.
|
|
*
|
|
* Errors:
|
|
*/
|
|
STDMETHODIMP
|
|
HrCopyProps ( LPIPDAT lpIPDATSrc,
|
|
LPPROPDATA lpIPDATDst,
|
|
LPMAPIPROP lpmpDst,
|
|
LPSPropTagArray lptagaInclude,
|
|
LPSPropTagArray lptagaExclude,
|
|
ULONG ulFlags,
|
|
LPSPropProblemArray FAR * lppProblems)
|
|
{
|
|
SCODE sc = S_OK;
|
|
HRESULT hr;
|
|
LPSPropProblemArray lpProbDest = NULL;
|
|
LPSPropProblemArray lpOurProblems = NULL;
|
|
LPSPropTagArray lptagaDst = NULL;
|
|
LPSPropValue rgspvSrcProps = NULL;
|
|
ULONG FAR * rgulSrcAccess = NULL;
|
|
ULONG cPropsSrc;
|
|
LPSPropTagArray lptagaSrc = NULL;
|
|
LPSPropTagArray lptagaNamedIDTags = NULL;
|
|
ULONG FAR * rgulSpvRef;
|
|
WORD idx;
|
|
ULONG cPropNames = 0;
|
|
LPMAPINAMEID FAR * lppPropNames = NULL;
|
|
LPSPropTagArray lpNamedTagsDst = NULL;
|
|
LPSPropValue lpspv;
|
|
#if DEBUG
|
|
ULONG cSrcProps = lpIPDATSrc->ulCount;
|
|
#endif
|
|
|
|
|
|
|
|
// If the MAPI_NOREPLACE flag was set then we need to know what properties
|
|
// the destination already has.
|
|
|
|
if ( ulFlags & MAPI_NOREPLACE )
|
|
{
|
|
hr = lpmpDst->lpVtbl->GetPropList( lpmpDst, MAPI_UNICODE, &lptagaDst );
|
|
|
|
if ( HR_FAILED( hr ) )
|
|
goto error;
|
|
}
|
|
|
|
// If MAPI_MOVE, we need to know what props we have to delete from the source.
|
|
// Get source access rights if destination supports IMAPIPropData
|
|
|
|
if ( lpIPDATDst || ulFlags & MAPI_MOVE )
|
|
{
|
|
if ( !lptagaInclude )
|
|
{
|
|
hr = IPDAT_GetPropList( lpIPDATSrc, 0, &lptagaSrc );
|
|
|
|
if ( HR_FAILED( hr ) )
|
|
goto error;
|
|
}
|
|
else
|
|
{
|
|
// Dup the include prop tag list so we can write in
|
|
// updated Named IDs
|
|
|
|
sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDATSrc,
|
|
CbSPropTagArray( lptagaInclude ), &lptagaSrc );
|
|
if ( FAILED( sc ) )
|
|
{
|
|
hr = ResultFromScode(sc);
|
|
goto error;
|
|
}
|
|
|
|
memcpy( lptagaSrc, lptagaInclude, CbSPropTagArray( lptagaInclude ) );
|
|
}
|
|
|
|
if ( lpIPDATDst )
|
|
{
|
|
hr = IPDAT_HrGetPropAccess( lpIPDATSrc, &lptagaInclude, &rgulSrcAccess );
|
|
|
|
if ( HR_FAILED( hr ) )
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
// Preset the problem array pointer to NULL (ie no problems).
|
|
|
|
if ( lppProblems )
|
|
{
|
|
*lppProblems = NULL;
|
|
|
|
// Setup our own problem array if there are any problems with
|
|
// GetIDsFromNames or GetNamesFromIDs...
|
|
|
|
sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDATSrc,
|
|
CbNewSPropProblemArray( lpIPDATSrc->ulCount ), &lpOurProblems );
|
|
if ( FAILED( sc ) )
|
|
{
|
|
hr = ResultFromScode( sc );
|
|
goto error;
|
|
}
|
|
|
|
lpOurProblems->cProblem = 0;
|
|
}
|
|
|
|
hr = IPDAT_GetProps( lpIPDATSrc, lptagaInclude, 0, &cPropsSrc,
|
|
&rgspvSrcProps );
|
|
|
|
if ( HR_FAILED( hr ) )
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
// allocate a proptag array to handle named ID mapping
|
|
|
|
sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDATSrc,
|
|
CbNewSPropTagArray( cPropsSrc ), &lptagaNamedIDTags );
|
|
|
|
if ( FAILED( sc ) )
|
|
{
|
|
hr = ResultFromScode( sc );
|
|
goto error;
|
|
}
|
|
|
|
// Allocate the Named ID cross ref array to allow cross ref of
|
|
// Named ID back to the original property.
|
|
|
|
sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDATSrc, cPropsSrc * sizeof(ULONG),
|
|
&rgulSpvRef );
|
|
|
|
if ( FAILED( sc ) )
|
|
{
|
|
hr = ResultFromScode( sc );
|
|
goto error;
|
|
}
|
|
|
|
lptagaNamedIDTags->cValues = 0;
|
|
|
|
// strafe throught the prop array to deal with excluded
|
|
// and/or named ID proptags
|
|
|
|
for ( lpspv = rgspvSrcProps,
|
|
idx = 0;
|
|
|
|
idx < cPropsSrc;
|
|
|
|
++idx,
|
|
++lpspv )
|
|
{
|
|
// check for excluded props
|
|
|
|
if ( lptagaExclude )
|
|
{
|
|
if ( FTagExists( lptagaExclude, lpspv->ulPropTag ) )
|
|
{
|
|
if ( lptagaSrc )
|
|
{
|
|
// We're assuming that IMAPIPropData keeps the proplist
|
|
// and the propvalue array in sync.
|
|
|
|
Assert( lptagaSrc->aulPropTag[idx] == lpspv->ulPropTag );
|
|
lptagaSrc->aulPropTag[idx] = PR_NULL;
|
|
}
|
|
|
|
lpspv->ulPropTag = PR_NULL;
|
|
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// if in named ID range.
|
|
|
|
if ( MIN_NAMED_PROP_ID <= PROP_ID(lpspv->ulPropTag)
|
|
&& PROP_ID(lpspv->ulPropTag) <= MAX_NAMED_PROP_ID )
|
|
{
|
|
lptagaNamedIDTags->aulPropTag[lptagaNamedIDTags->cValues] = lpspv->ulPropTag;
|
|
|
|
// remember which propval ID references
|
|
|
|
rgulSpvRef[lptagaNamedIDTags->cValues] = (ULONG)idx;
|
|
++lptagaNamedIDTags->cValues;
|
|
}
|
|
}
|
|
|
|
// Did we find any named IDs
|
|
|
|
if ( lptagaNamedIDTags->cValues )
|
|
{
|
|
hr = IPDAT_GetNamesFromIDs( lpIPDATSrc,
|
|
&lptagaNamedIDTags,
|
|
NULL,
|
|
0,
|
|
&cPropNames,
|
|
&lppPropNames );
|
|
|
|
// Report any failures in our problem array.
|
|
|
|
if ( hr )
|
|
{
|
|
goto NameIDProblem;
|
|
}
|
|
|
|
// assert that we got what we requested
|
|
|
|
Assert( cPropNames == lptagaNamedIDTags->cValues );
|
|
|
|
// Get Tag IDs from the Destination, create them if they don't exist.
|
|
|
|
hr = lpmpDst->lpVtbl->GetIDsFromNames( lpmpDst, cPropNames, lppPropNames,
|
|
MAPI_CREATE, &lpNamedTagsDst );
|
|
|
|
// Deal with Named ID errors/warnings.
|
|
|
|
NameIDProblem:
|
|
|
|
if ( hr )
|
|
{
|
|
for ( idx = 0; idx < lptagaNamedIDTags->cValues ;idx++ )
|
|
{
|
|
// if we got a MAPI failure set problem array with that error for the
|
|
// affected proptags
|
|
|
|
if ( HR_FAILED( hr ) )
|
|
{
|
|
if ( lppProblems )
|
|
{
|
|
AddProblem( lpOurProblems, rgulSpvRef[idx],
|
|
lptagaNamedIDTags->aulPropTag[idx], GetScode( hr ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Assert( cPropNames == lptagaNamedIDTags->cValues );
|
|
|
|
if ( !lppPropNames[idx]->Kind.lpwstrName
|
|
|| ( lpNamedTagsDst
|
|
&& PROP_TYPE(lpNamedTagsDst->aulPropTag[idx]) == PT_ERROR ) )
|
|
{
|
|
if ( lppProblems )
|
|
{
|
|
AddProblem( lpOurProblems, rgulSpvRef[idx],
|
|
lptagaNamedIDTags->aulPropTag[idx], MAPI_E_NOT_FOUND );
|
|
}
|
|
}
|
|
}
|
|
// Set src propval's proptag and proptag to PR_NULL so we don't
|
|
// process it any further.
|
|
|
|
rgspvSrcProps[rgulSpvRef[idx]].ulPropTag = PR_NULL;
|
|
lptagaSrc->aulPropTag[rgulSpvRef[idx]] = PR_NULL;
|
|
}
|
|
}
|
|
|
|
// Fix up the src propvalue tags
|
|
|
|
for ( idx = 0; idx < cPropNames; ++idx )
|
|
{
|
|
if ( rgspvSrcProps[rgulSpvRef[idx]].ulPropTag == PR_NULL )
|
|
continue;
|
|
|
|
rgspvSrcProps[rgulSpvRef[idx]].ulPropTag
|
|
= CHANGE_PROP_TYPE( lpNamedTagsDst->aulPropTag[idx],
|
|
PROP_TYPE( rgspvSrcProps[rgulSpvRef[idx]].ulPropTag ) );
|
|
}
|
|
}
|
|
|
|
// If propval exists in the destination remove from src propvals.
|
|
// We do this here after the named IDs have been fixed up.
|
|
|
|
if ( ulFlags & MAPI_NOREPLACE )
|
|
{
|
|
// spin through the props one more time
|
|
|
|
for ( lpspv = rgspvSrcProps,
|
|
idx = 0;
|
|
|
|
idx < cPropsSrc;
|
|
|
|
++idx,
|
|
++lpspv )
|
|
{
|
|
if ( FTagExists( lptagaDst, lpspv->ulPropTag ) )
|
|
{
|
|
// ensure that proptag list and propval array are in sync
|
|
|
|
Assert( !lpIPDATDst || lpspv->ulPropTag == lptagaSrc->aulPropTag[idx] );
|
|
|
|
lpspv->ulPropTag = PR_NULL;
|
|
|
|
if ( lpIPDATDst )
|
|
{
|
|
// We can't be modifying access rights on NOREPLACE
|
|
|
|
lptagaSrc->aulPropTag[idx] = PR_NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now set the props...
|
|
|
|
hr = lpmpDst->lpVtbl->SetProps( lpmpDst, cPropsSrc, rgspvSrcProps, &lpProbDest );
|
|
|
|
if ( HR_FAILED( hr ) )
|
|
goto error;
|
|
|
|
// Handle MAPI_MOVE
|
|
|
|
if ( ulFlags & MAPI_MOVE )
|
|
{
|
|
// Do we care about problems if delete from the source has any? Nah...
|
|
|
|
hr = IPDAT_DeleteProps( lpIPDATSrc, lptagaSrc, NULL );
|
|
if ( HR_FAILED( hr ) )
|
|
goto error;
|
|
}
|
|
|
|
// Transfer the access rights
|
|
|
|
if ( lpIPDATDst )
|
|
{
|
|
// Did we find any Named IDs
|
|
|
|
if ( lptagaNamedIDTags->cValues )
|
|
{
|
|
// fix up the proptags to match the dest.
|
|
|
|
for ( idx = 0; idx < cPropNames; ++idx )
|
|
{
|
|
if ( lptagaSrc->aulPropTag[rgulSpvRef[idx]] == PR_NULL )
|
|
continue;
|
|
|
|
lptagaSrc->aulPropTag[rgulSpvRef[idx]]
|
|
= CHANGE_PROP_TYPE( lpNamedTagsDst->aulPropTag[idx],
|
|
PROP_TYPE( lptagaSrc->aulPropTag[rgulSpvRef[idx]] ) );
|
|
}
|
|
}
|
|
|
|
hr = IPDAT_HrSetPropAccess( (LPIPDAT)lpIPDATDst, lptagaSrc, rgulSrcAccess );
|
|
|
|
if ( HR_FAILED( hr ) )
|
|
goto error;
|
|
}
|
|
|
|
// Return the problem array if requested and there were problems...
|
|
|
|
if ( lppProblems )
|
|
{
|
|
if ( lpProbDest && lpProbDest->cProblem )
|
|
{
|
|
Assert( lpProbDest->cProblem + lpOurProblems->cProblem <= cSrcProps );
|
|
|
|
// move/merge the lpProbDest (dest) into our problem array
|
|
|
|
for ( idx = 0; idx < lpProbDest->cProblem; idx++ )
|
|
{
|
|
AddProblem( lpOurProblems, lpProbDest->aProblem[idx].ulIndex,
|
|
lpProbDest->aProblem[idx].ulPropTag,
|
|
lpProbDest->aProblem[idx].scode );
|
|
}
|
|
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, lpProbDest );
|
|
}
|
|
|
|
if ( lpOurProblems->cProblem )
|
|
{
|
|
*lppProblems = lpOurProblems;
|
|
hr = ResultFromScode( MAPI_W_ERRORS_RETURNED );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// ...else dispose of the problem array.
|
|
|
|
UNKOBJ_Free( (LPUNKOBJ)lpIPDATSrc, lpOurProblems );
|
|
}
|
|
|
|
out:
|
|
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, lptagaSrc );
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, lptagaDst );
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, rgulSrcAccess );
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, rgspvSrcProps );
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, lptagaNamedIDTags );
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, lppPropNames );
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, lpNamedTagsDst );
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, rgulSpvRef );
|
|
|
|
DebugTraceResult( HrCopyProps, hr );
|
|
|
|
return hr;
|
|
|
|
error:
|
|
/* Free the prop problem array.
|
|
*/
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, lpOurProblems );
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, lpProbDest );
|
|
goto out;
|
|
}
|
|
|
|
|
|
/*
|
|
- IPDAT_CopyTo
|
|
-
|
|
* Purpose:
|
|
* Copies all but the excluded properties from this IPropData object to
|
|
* another object which must support the IMAPIProp interface.
|
|
*
|
|
* Property names are copied!
|
|
* If a property is named in the source object (lpIPDAT) and the name
|
|
* does not exist in the destination object, a new named property ID
|
|
* will be requested from the destination
|
|
*
|
|
* If the IMAPIPropData interface is supported on the destination is not
|
|
* excluded by the caller then individual property access flags will be
|
|
* copied to the destination.
|
|
*
|
|
* Arguments:
|
|
* lpIPDAT The source IPropData object.
|
|
* ciidExclude Count of excluded interfaces in rgiidExclude
|
|
* rgiidExclude Array of iid's specifying excluded interfaces
|
|
* lpPropTagArray Pointer to a counted array of property tags of
|
|
* properties not to be copied, can be NULL
|
|
* ulUIParam Handle of parent window cast to ULONG, NULL if
|
|
* no dialog reqeuested
|
|
* lpInterface Interface ID of the interface of lpDestObj
|
|
* (not used).
|
|
* lpvDestObj destination object
|
|
* ulFlags MAPI_MOVE
|
|
* MAPI_NOREPLACE
|
|
* MAPI_DIALOG (not supported)
|
|
* MAPI_STD_DIALOG (not supported)
|
|
* lppProblems Pointer to memory location which will receive a
|
|
* pointer the the list of problems. NULL if no
|
|
* propblem array is desired.
|
|
*
|
|
* Returns:
|
|
* HRESULT
|
|
*
|
|
* Side effects:
|
|
*
|
|
* Errors:
|
|
*/
|
|
STDMETHODIMP
|
|
IPDAT_CopyTo ( LPIPDAT lpIPDAT,
|
|
ULONG ciidExclude,
|
|
LPCIID rgiidExclude,
|
|
LPSPropTagArray lpExcludeProps,
|
|
ULONG_PTR ulUIParam,
|
|
LPMAPIPROGRESS lpProgress,
|
|
LPCIID lpInterface,
|
|
LPVOID lpDestObj,
|
|
ULONG ulFlags,
|
|
LPSPropProblemArray FAR * lppProblems)
|
|
{
|
|
HRESULT hResult = hrSuccess;
|
|
LPUNKNOWN lpunkDest = (LPUNKNOWN) lpDestObj;
|
|
LPPROPDATA lpPropData = NULL;
|
|
LPMAPIPROP lpMapiProp = NULL;
|
|
UINT ucT;
|
|
LPCIID FAR *lppiid;
|
|
|
|
#if !defined(NO_VALIDATION)
|
|
/* Make sure the object is valid.
|
|
*/
|
|
if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, CopyTo, lpVtbl))
|
|
{
|
|
DebugTrace( TEXT("IPDAT::CopyTo() - Bad object passed\n") );
|
|
return ResultFromScode(MAPI_E_INVALID_PARAMETER);
|
|
}
|
|
|
|
Validate_IMAPIProp_CopyTo(
|
|
lpIPDAT,
|
|
ciidExclude,
|
|
rgiidExclude,
|
|
lpExcludeProps,
|
|
ulUIParam,
|
|
lpProgress,
|
|
lpInterface,
|
|
lpDestObj,
|
|
ulFlags,
|
|
lppProblems);
|
|
|
|
#endif // not NO_VALIDATION
|
|
|
|
// Make sure we're not copying to ourselves
|
|
|
|
if ( (LPVOID)lpIPDAT == (LPVOID)lpDestObj )
|
|
{
|
|
DebugTrace( TEXT("IProp: Copying to self is not supported\n") );
|
|
return ResultFromScode( MAPI_E_NO_ACCESS );
|
|
}
|
|
|
|
/* The error exit assumes that we are already in a critical section.
|
|
*/
|
|
UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
|
|
|
|
/* Determine the best interface to copy contents into. It really doesn't
|
|
* matter what MAPI specified as the interface ID to the destination. We
|
|
* only understand IMAPIPropData and IMAPIProp.
|
|
*
|
|
* We depend on IUnknown being last in the array of IDs that we support.
|
|
*/
|
|
for ( ucT = (UINT)(lpIPDAT->ulcIID), lppiid = (LPCIID FAR *) argpiidIPDAT
|
|
; ucT > CIID_IPROP_INHERITS
|
|
; lppiid++, ucT--)
|
|
{
|
|
/* See if the interface is excluded.
|
|
*/
|
|
if ( !FIsExcludedIID( *lppiid, rgiidExclude, ciidExclude)
|
|
&& !HR_FAILED(lpunkDest->lpVtbl->QueryInterface( lpunkDest
|
|
, *lppiid
|
|
, (LPVOID FAR *)
|
|
&lpMapiProp)))
|
|
{
|
|
/* We found a good destination interface so quit looking.
|
|
*/
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/* Determine which interface we ended up with and set up to use that
|
|
* interface.
|
|
*/
|
|
if (ucT <= CIID_IPROP_INHERITS)
|
|
{
|
|
/* Didn't find an interface at least as good as IProp so we can't
|
|
* do the CopyTo.
|
|
*/
|
|
hResult = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
|
|
goto error;
|
|
}
|
|
|
|
|
|
/* If we ended up with IPropData as the best common interface then use it.
|
|
*/
|
|
if (*lppiid == &IID_IMAPIPropData)
|
|
{
|
|
lpPropData = (LPPROPDATA) lpMapiProp;
|
|
}
|
|
|
|
/* Copy all properties that are not excluded. Copy extra prop access
|
|
* information if IPropData is supported by the destination.
|
|
*/
|
|
if (HR_FAILED(hResult = HrCopyProps( lpIPDAT
|
|
, lpPropData
|
|
, lpMapiProp
|
|
, NULL
|
|
, lpExcludeProps
|
|
, ulFlags
|
|
, lppProblems)))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
|
|
out:
|
|
/* Release the object obtained with QueryInterface.
|
|
*/
|
|
if (lpMapiProp) {
|
|
UlRelease(lpMapiProp);
|
|
}
|
|
|
|
/* Free the prop tag array that we got from the destination.
|
|
*/
|
|
UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
|
|
DebugTraceResult( IPDAT_CopyTo, hResult);
|
|
return hResult;
|
|
|
|
error:
|
|
/* Free the prop problem array.
|
|
*/
|
|
UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, GetScode(hResult), 0);
|
|
goto out;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
- IPDAT_CopyProps
|
|
-
|
|
* Purpose:
|
|
* Copies all the listed properties from this IPropData object to
|
|
* another object which must support the IMAPIProp interface.
|
|
*
|
|
* Property names are copied!
|
|
* If a property is named in the source object (lpIPDAT) and the name
|
|
* does not exist in the destination object, a new named property ID
|
|
* will be requested from the destination
|
|
*
|
|
* If the IMAPIPropData interface is supported on the destination is not
|
|
* excluded by the caller then individual property access flags will be
|
|
* copied to the destination.
|
|
*
|
|
* Arguments:
|
|
* lpIPDAT The source IPropData object.
|
|
* lpPropTagArray Pointer to a counted array of property tags of
|
|
* properties to be copied, CAN NOT be NULL
|
|
* ulUIParam Handle of parent window cast to ULONG, NULL if
|
|
* no dialog reqeuested
|
|
* lpInterface Interface ID of the interface of lpDestObj
|
|
* (not used).
|
|
* lpvDestObj destination object
|
|
* ulFlags MAPI_MOVE
|
|
* MAPI_NOREPLACE
|
|
* MAPI_DIALOG (not supported)
|
|
* MAPI_STD_DIALOG (not supported)
|
|
* lppProblems Pointer to memory location which will receive a
|
|
* pointer the the list of problems. NULL if no
|
|
* propblem array is desired.
|
|
*
|
|
* Returns:
|
|
* HRESULT
|
|
*
|
|
* Side effects:
|
|
*
|
|
* Errors:
|
|
*/
|
|
STDMETHODIMP
|
|
IPDAT_CopyProps ( LPIPDAT lpIPDAT,
|
|
LPSPropTagArray lpPropTagArray,
|
|
ULONG_PTR ulUIParam,
|
|
LPMAPIPROGRESS lpProgress,
|
|
LPCIID lpInterface,
|
|
LPVOID lpDestObj,
|
|
ULONG ulFlags,
|
|
LPSPropProblemArray FAR * lppProblems)
|
|
{
|
|
HRESULT hResult;
|
|
LPUNKNOWN lpunkDest = (LPUNKNOWN) lpDestObj;
|
|
LPPROPDATA lpPropData = NULL;
|
|
LPMAPIPROP lpMapiProp = NULL;
|
|
UINT ucT;
|
|
LPCIID FAR *lppiid;
|
|
|
|
#if !defined(NO_VALIDATION)
|
|
/* Make sure the object is valid.
|
|
*/
|
|
if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, CopyProps, lpVtbl))
|
|
{
|
|
DebugTrace( TEXT("IPDAT::CopyProps() - Bad object passed\n") );
|
|
return ResultFromScode(MAPI_E_INVALID_PARAMETER);
|
|
}
|
|
|
|
Validate_IMAPIProp_CopyProps(
|
|
lpIPDAT,
|
|
lpPropTagArray,
|
|
ulUIParam,
|
|
lpProgress,
|
|
lpInterface,
|
|
lpDestObj,
|
|
ulFlags,
|
|
lppProblems);
|
|
|
|
#endif // not NO_VALIDATION
|
|
|
|
/* The error exit assumes that we are already in a critical section.
|
|
*/
|
|
UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
|
|
|
|
/* Determine the best interface to copy contents into. It really doesn't
|
|
* matter what MAPI specified as the interface ID to the destination. We
|
|
* only understand IMAPIPropData and IMAPIProp.
|
|
*
|
|
* We depend on IUnknown being last in the array of IDs that we support.
|
|
*/
|
|
for ( ucT = (UINT)(lpIPDAT->ulcIID), lppiid = (LPCIID FAR *) argpiidIPDAT
|
|
; ucT > CIID_IPROP_INHERITS
|
|
; lppiid++, ucT--)
|
|
{
|
|
/* See if the interface is excluded.
|
|
*/
|
|
if (!HR_FAILED(lpunkDest->lpVtbl->QueryInterface( lpunkDest
|
|
, *lppiid
|
|
, (LPVOID FAR *)
|
|
&lpMapiProp)))
|
|
{
|
|
/* We found a good destination interface so quit looking.
|
|
*/
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/* Determine which interface we ended up with and set up to use that
|
|
* interface.
|
|
*/
|
|
if (ucT <= CIID_IPROP_INHERITS)
|
|
{
|
|
/* Didn't find an interface at least as good as IProp so we can't
|
|
* do the CopyTo.
|
|
*/
|
|
hResult = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
|
|
goto error;
|
|
}
|
|
|
|
|
|
/* If we ended up with IPropData as the best common interface then use it.
|
|
*/
|
|
if (*lppiid == &IID_IMAPIPropData)
|
|
{
|
|
lpPropData = (LPPROPDATA) lpMapiProp;
|
|
}
|
|
|
|
/* Copy all properties that are not excluded. Copy extra prop access
|
|
* information if IPropData is supported by the destination.
|
|
*/
|
|
if (HR_FAILED(hResult = HrCopyProps( lpIPDAT
|
|
, lpPropData
|
|
, lpMapiProp
|
|
, lpPropTagArray
|
|
, NULL
|
|
, ulFlags
|
|
, lppProblems)))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
|
|
out:
|
|
/* Release the object obtained with QueryInterface.
|
|
*/
|
|
if (lpMapiProp) {
|
|
UlRelease(lpMapiProp);
|
|
}
|
|
|
|
/* Free the prop tag array that we got from the destination.
|
|
*/
|
|
UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
|
|
DebugTraceResult( IPDAT_CopyProps, hResult);
|
|
return hResult;
|
|
|
|
error:
|
|
/* Free the prop problem array.
|
|
*/
|
|
UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, GetScode(hResult), 0);
|
|
goto out;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
- IPDAT_GetNamesFromIDs
|
|
-
|
|
* Purpose:
|
|
* Return the unicode string associated with the given ID
|
|
*
|
|
* Arguments:
|
|
* lpIPDAT The IPropData object whose property name is desired.
|
|
* lppPropTags Pointer to pointer to a property tag array listing
|
|
* the properties whose names are desired. If it
|
|
* points to NULL then we will create a property tag
|
|
* array listing ALL properties available from the
|
|
* IPropData object.
|
|
* ulFlags reserved, must be 0
|
|
* lpcPropNames Pointer to memory location which will receive the
|
|
* count of strings listed in lpppszPropNames.
|
|
* lpppszPropNames pointer to variable for address of an array of
|
|
* unicode property name strings. Freed by
|
|
* MAPIFreeBuffer
|
|
* Returns:
|
|
* HRESULT
|
|
*
|
|
* Side effects:
|
|
*
|
|
* Errors:
|
|
*/
|
|
STDMETHODIMP
|
|
IPDAT_GetNamesFromIDs ( LPIPDAT lpIPDAT,
|
|
LPSPropTagArray FAR * lppPropTags,
|
|
LPGUID lpPropSetGuid,
|
|
ULONG ulFlags,
|
|
ULONG FAR * lpcPropNames,
|
|
LPMAPINAMEID FAR * FAR *lpppPropNames)
|
|
{
|
|
SCODE sc = S_OK;
|
|
LPSPropTagArray lpsPTaga = NULL;
|
|
LPSPropTagArray lpsptOut = NULL;
|
|
ULONG cTags;
|
|
ULONG FAR *lpulProp2Find;
|
|
LPMAPINAMEID FAR * lppPropNames = NULL;
|
|
LPMAPINAMEID FAR * lppNameT;
|
|
BOOL fWarning = FALSE;
|
|
|
|
|
|
#if !defined(NO_VALIDATION)
|
|
/* Make sure the object is valid.
|
|
*/
|
|
if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, GetNamesFromIDs, lpVtbl))
|
|
{
|
|
DebugTrace( TEXT("IPDAT::GetNamesFromIDs() - Bad object passed\n") );
|
|
return ResultFromScode(MAPI_E_INVALID_PARAMETER);
|
|
}
|
|
|
|
Validate_IMAPIProp_GetNamesFromIDs(
|
|
lpIPDAT,
|
|
lppPropTags,
|
|
lpPropSetGuid,
|
|
ulFlags,
|
|
lpcPropNames,
|
|
lpppPropNames);
|
|
|
|
#endif // not NO_VALIDATION
|
|
|
|
/* The error exit assumes that we are already in a critical section.
|
|
*/
|
|
UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
|
|
|
|
/* If no prop tag array was passed in then create one...
|
|
*/
|
|
if (!(*lppPropTags))
|
|
{
|
|
if (lpPropSetGuid && !memcmp(lpPropSetGuid, &PS_MAPI, sizeof(GUID)))
|
|
{
|
|
//
|
|
// We're dealing with the mapi property set
|
|
// In this case, we need to build up a list
|
|
// of all the properties on this object less
|
|
// than 0x8000 - not quite the same as GetPropList().
|
|
//
|
|
sc = ScMakePropList(lpIPDAT,
|
|
lpIPDAT->ulCount,
|
|
(LPLSTLNK) lpIPDAT->lpLstSPV,
|
|
&lpsPTaga,
|
|
(ULONG)0x8000);
|
|
|
|
if (FAILED(sc))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
//
|
|
// For each one of these proptags, we need to
|
|
// build up the names for them using the PS_MAPI
|
|
// guid.
|
|
//
|
|
sc = ScMakeMAPINames(lpIPDAT, lpsPTaga, &lppPropNames);
|
|
if (FAILED(sc))
|
|
{
|
|
goto error;
|
|
}
|
|
*lpppPropNames = lppPropNames;
|
|
*lpcPropNames = lpsPTaga->cValues;
|
|
*lppPropTags = lpsPTaga;
|
|
|
|
// Done: we're outta here!
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (FAILED(sc = ScMakeNamePropList( lpIPDAT,
|
|
(lpIPDAT->ulNextMapID-0x8000),
|
|
lpIPDAT->lpLstSPN,
|
|
&lpsPTaga,
|
|
ulFlags,
|
|
lpPropSetGuid)))
|
|
{
|
|
goto error;
|
|
}
|
|
}
|
|
/* ...else use the one that was passed in.
|
|
*/
|
|
else if (*lppPropTags)
|
|
{
|
|
lpsPTaga = *lppPropTags;
|
|
}
|
|
|
|
|
|
/* Allocate the array of name pointers.
|
|
*/
|
|
if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT
|
|
, lpsPTaga->cValues * sizeof(LPMAPINAMEID)
|
|
, (LPVOID) &lppPropNames)))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
|
|
/* Find each property in the list and see if it has a UNICODE name.
|
|
*/
|
|
for ( cTags = lpsPTaga->cValues
|
|
, lpulProp2Find = (ULONG FAR *) (lpsPTaga->aulPropTag)
|
|
, lppNameT = lppPropNames
|
|
; cTags
|
|
; cTags--, lpulProp2Find++, lppNameT++)
|
|
{
|
|
LPPLSTLNK lppLstLnk;
|
|
LPLSTSPN lpLstSPN;
|
|
|
|
/* If there is a ID to NAME map for the property and it has a name.
|
|
* then copy the UNICODE string and pass it back.
|
|
*/
|
|
if ( (lppLstLnk = LPPLSTLNKFindProp( (LPPLSTLNK)&(lpIPDAT->lpLstSPN)
|
|
, *lpulProp2Find))
|
|
&& (lpLstSPN = (LPLSTSPN) (*lppLstLnk))
|
|
&& lpLstSPN->lpPropName)
|
|
{
|
|
sc = ScDupNameID(lpIPDAT,
|
|
lppPropNames, // Alloc'd more here.
|
|
lpLstSPN->lpPropName,
|
|
lppNameT);
|
|
if (FAILED(sc))
|
|
{
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
/* Else no ID to NAME map exists for the property so return NULL.
|
|
*/
|
|
else
|
|
{
|
|
/* The property has no name, Flag a warning.
|
|
*/
|
|
*lppNameT = NULL;
|
|
fWarning = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
*lpppPropNames = lppPropNames;
|
|
if (!(*lppPropTags))
|
|
{
|
|
*lppPropTags = lpsPTaga;
|
|
}
|
|
*lpcPropNames = lpsPTaga->cValues;
|
|
|
|
goto out;
|
|
|
|
|
|
error:
|
|
/* If we created the tag array then we need to free it on error.
|
|
* lpsPTaga must be NULL on MAPI_E_INVALID_PARAMETER.
|
|
*/
|
|
if (lpsPTaga && !(*lppPropTags))
|
|
{
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpsPTaga);
|
|
}
|
|
|
|
/* Free the array of pointers to names and names.
|
|
*/
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lppPropNames);
|
|
|
|
UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0);
|
|
|
|
out:
|
|
UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
|
|
if ( fWarning )
|
|
sc = MAPI_W_ERRORS_RETURNED;
|
|
|
|
return MakeResult(sc);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
- IPDAT_GetIDsFromNames
|
|
-
|
|
* Purpose:
|
|
* Return the property ID for the properties named by the supplied
|
|
* UNICODE strings. If no property ID is currently TEXT("named") by one of
|
|
* the strings and MAPI_CREATE is specified in the flags then a new
|
|
* property ID in the range 0x8000 to 0xfffe will be allocated for that
|
|
* string a returned in the property tag array.
|
|
*
|
|
* If problems occur (eg. no name found and can't create) then the entry
|
|
* for the name that had the problem will be set to have a NULL PROP_ID
|
|
* and PT_ERROR type.
|
|
*
|
|
* All property tags successfully returned will have type PT_UNSPECIFIED.
|
|
*
|
|
* Arguments:
|
|
* lpIPDAT The IPropData object for which property IDs are
|
|
* requested.
|
|
* cPropNames Count of strings in for which IDs are requested.
|
|
* lppszPropNames Pointer ot array of pointers unicode strings which
|
|
* name the properties for which IDs are requested.
|
|
* ulFlags Reserved, must be 0
|
|
* lppPropTags Pointer to memory location which will receive a
|
|
* pointer to a new property tag array listing the
|
|
* requested property tags.
|
|
*
|
|
* Returns:
|
|
* HRESULT
|
|
*
|
|
* Side effects:
|
|
*
|
|
* Errors:
|
|
*/
|
|
STDMETHODIMP
|
|
IPDAT_GetIDsFromNames ( LPIPDAT lpIPDAT,
|
|
ULONG cPropNames,
|
|
LPMAPINAMEID FAR * lppPropNames,
|
|
ULONG ulFlags,
|
|
LPSPropTagArray FAR * lppPropTags)
|
|
{
|
|
SCODE sc = S_OK;
|
|
ULONG ulcWarnings = 0;
|
|
LPSPropTagArray lpPTaga = NULL;
|
|
LPULONG lpulProp2Set;
|
|
|
|
|
|
#if !defined(NO_VALIDATION)
|
|
/* Make sure the object is valid.
|
|
*/
|
|
if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, GetIDsFromNames, lpVtbl))
|
|
{
|
|
DebugTrace( TEXT("IPDAT::GetIDsFromNames() - Bad object passed\n") );
|
|
return ResultFromScode(MAPI_E_INVALID_PARAMETER);
|
|
}
|
|
|
|
Validate_IMAPIProp_GetIDsFromNames(
|
|
lpIPDAT,
|
|
cPropNames,
|
|
lppPropNames,
|
|
ulFlags,
|
|
lppPropTags);
|
|
|
|
#endif // not NO_VALIDATION
|
|
|
|
/* The error exit assumes that we are already in a critical section.
|
|
*/
|
|
UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
|
|
|
|
/* If the caller wants to change our ID to NAME mapping, make sure access
|
|
* is allowed.
|
|
*/
|
|
if ( (ulFlags & MAPI_CREATE)
|
|
&& !(lpIPDAT->ulObjAccess & IPROP_READWRITE))
|
|
{
|
|
sc = MAPI_E_NO_ACCESS;
|
|
goto error;
|
|
}
|
|
|
|
|
|
/*
|
|
* Check to see if there are no names being passed
|
|
*/
|
|
if (!cPropNames)
|
|
{
|
|
/*
|
|
* There aren't so build up a list of all proptags > 0x8000
|
|
*/
|
|
sc = ScMakeNamePropList( lpIPDAT,
|
|
(lpIPDAT->ulNextMapID-0x8000),
|
|
lpIPDAT->lpLstSPN,
|
|
&lpPTaga,
|
|
0,
|
|
NULL);
|
|
if (FAILED(sc))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
*lppPropTags = lpPTaga;
|
|
goto out;
|
|
}
|
|
|
|
/* Allocate space for the new SPropTagArray.
|
|
*/
|
|
if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT
|
|
, CbNewSPropTagArray(cPropNames)
|
|
, (LPVOID) &lpPTaga)))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
lpPTaga->cValues = cPropNames;
|
|
|
|
/* Find each ID in the list passed in.
|
|
*/
|
|
for ( lpulProp2Set = (LPULONG) (lpPTaga->aulPropTag)
|
|
; cPropNames
|
|
; cPropNames--, lpulProp2Set++, lppPropNames++)
|
|
{
|
|
LPLSTSPN lpLstSPN;
|
|
|
|
//
|
|
// First see if it's from PS_MAPI
|
|
//
|
|
if (!memcmp((*lppPropNames)->lpguid, &PS_MAPI, sizeof(GUID)))
|
|
{
|
|
//
|
|
// Yup, it is, so validate that it is a MNID_ID
|
|
//
|
|
if ((*lppPropNames)->ulKind == MNID_ID)
|
|
{
|
|
*lpulProp2Set = (*lppPropNames)->Kind.lID;
|
|
} else
|
|
{
|
|
*lpulProp2Set = PROP_TAG( PT_ERROR, 0);
|
|
ulcWarnings++;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Next, validate that if we have a PS_PUBLIC_STRINGS...
|
|
//
|
|
if (!memcmp((*lppPropNames)->lpguid, &PS_PUBLIC_STRINGS,
|
|
sizeof(GUID)))
|
|
{
|
|
//
|
|
// ...that it is a MNID_STRING
|
|
//
|
|
if ((*lppPropNames)->ulKind != MNID_STRING)
|
|
{
|
|
//
|
|
// It's not, so it's a malformed name
|
|
//
|
|
*lpulProp2Set = PROP_TAG( PT_ERROR, 0);
|
|
ulcWarnings++;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* Try to find the name in our list of ID to NAME maps.
|
|
*/
|
|
for ( lpLstSPN = lpIPDAT->lpLstSPN
|
|
; lpLstSPN
|
|
; lpLstSPN = (LPLSTSPN) (lpLstSPN->lstlnk.lpNext))
|
|
{
|
|
/* If the name doesn't match keep looking.
|
|
*/
|
|
if (FEqualNames( *lppPropNames, lpLstSPN->lpPropName ))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* If we found a matching NAME then set the ID.
|
|
*/
|
|
if (lpLstSPN)
|
|
{
|
|
*lpulProp2Set = lpLstSPN->lstlnk.ulKey;
|
|
}
|
|
else if (ulFlags & MAPI_CREATE)
|
|
{
|
|
|
|
/* Create a new map if we didn't find one and MAPI_CREATE was
|
|
* specified.
|
|
*/
|
|
|
|
/* Allocate space for the new ID to NAME map.
|
|
*/
|
|
if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT
|
|
, sizeof(LSTSPN)
|
|
, (LPVOID) &lpLstSPN)))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
sc = ScDupNameID(lpIPDAT,
|
|
lpLstSPN, // Alloc'd more here.
|
|
*lppPropNames,
|
|
&(lpLstSPN->lpPropName));
|
|
|
|
if (FAILED(sc))
|
|
{
|
|
//
|
|
// Don't try to add it.
|
|
//
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpLstSPN);
|
|
goto error;
|
|
}
|
|
|
|
|
|
/* Set the ID to NAME map.
|
|
*/
|
|
lpLstSPN->lstlnk.ulKey = PROP_TAG( 0, lpIPDAT->ulNextMapID++);
|
|
|
|
/* Link the new map as the first list element.
|
|
*/
|
|
LinkLstLnk( (LPLSTLNK FAR *) &(lpIPDAT->lpLstSPN)
|
|
, &(lpLstSPN->lstlnk));
|
|
|
|
/* Return the newly created Prop Tag.
|
|
*/
|
|
*lpulProp2Set = lpLstSPN->lstlnk.ulKey;
|
|
}
|
|
|
|
/* Else we didn't find the NAME and we can't create one so
|
|
* set ID to error.
|
|
*/
|
|
else
|
|
{
|
|
*lpulProp2Set = PROP_TAG( PT_ERROR, 0);
|
|
ulcWarnings++;
|
|
}
|
|
}
|
|
|
|
|
|
*lppPropTags = lpPTaga;
|
|
|
|
|
|
if (ulcWarnings)
|
|
{
|
|
sc = MAPI_W_ERRORS_RETURNED;
|
|
}
|
|
|
|
goto out;
|
|
|
|
error:
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpPTaga);
|
|
UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0);
|
|
|
|
out:
|
|
UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
|
|
return MakeResult(sc);
|
|
}
|
|
|
|
|
|
/*
|
|
- IPDAT_HrSetObjAccess
|
|
-
|
|
* Purpose:
|
|
* Sets the read/write access and the clean/dirty status of IPropData
|
|
* object as a whole.
|
|
*
|
|
* The read/write access bits can be used to prevent a client from
|
|
* changing or deleting a property via the IMAPIProp methods or from
|
|
* changing the read/write access and status bits of individual properties.
|
|
* It can also be used to prevent the creation of new properties or
|
|
* property names.
|
|
*
|
|
* Arguments:
|
|
* lpIPDAT The IPropData object for which access rights and
|
|
* status will be set.
|
|
* ulAccess The new access/status flags to be set.
|
|
*
|
|
* Returns:
|
|
* HRESULT
|
|
*
|
|
* Side effects:
|
|
*
|
|
* Errors:
|
|
*/
|
|
STDMETHODIMP
|
|
IPDAT_HrSetObjAccess ( LPIPDAT lpIPDAT,
|
|
ULONG ulAccess )
|
|
{
|
|
SCODE sc = S_OK;
|
|
|
|
#if !defined(NO_VALIDATION)
|
|
/* Make sure the object is valid.
|
|
*/
|
|
if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, HrSetObjAccess, lpVtbl))
|
|
{
|
|
DebugTrace( TEXT("IPDAT::HrSetObjAccess() - Bad object passed\n") );
|
|
return ResultFromScode(MAPI_E_INVALID_PARAMETER);
|
|
}
|
|
#endif
|
|
|
|
if (ulAccess & ~(IPROP_READONLY | IPROP_READWRITE))
|
|
{
|
|
return ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
|
|
}
|
|
|
|
if ( !(ulAccess & (IPROP_READONLY | IPROP_READWRITE))
|
|
|| ( (ulAccess & (IPROP_READONLY | IPROP_READWRITE))
|
|
== (IPROP_READONLY | IPROP_READWRITE)))
|
|
{
|
|
DebugTrace( TEXT("IPDAT::HrSetObjAccess() - Conflicting access flags.\n") );
|
|
return ResultFromScode(MAPI_E_INVALID_PARAMETER);
|
|
}
|
|
|
|
UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
|
|
lpIPDAT->ulObjAccess = ulAccess;
|
|
|
|
/*
|
|
*out:
|
|
*/
|
|
UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
|
|
return MakeResult(sc);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
- IPDAT_HrSetPropAccess
|
|
-
|
|
* Purpose:
|
|
* Sets the read/write access and the clean/dirty status of individual
|
|
* properties contained by the IPropData object.
|
|
*
|
|
* The read/write access bits can be used to prevent a client from
|
|
* changing or deleting a property via the IMAPIProp methods.
|
|
*
|
|
* The clean/dirty bits can be used to determine if a client has changed
|
|
* a writable property.
|
|
*
|
|
* Arguments:
|
|
* lpIPDAT The IPropData object for which property access
|
|
* rights and status will be set.
|
|
* lpsPropTagArray List of property tags whose access/status will change.
|
|
* rgulAccess Array of new access/status flags in the same order as
|
|
* as the list of property tags in <lpsPropTagArray>.
|
|
*
|
|
* Returns:
|
|
* HRESULT
|
|
*
|
|
* Side effects:
|
|
*
|
|
* Errors:
|
|
*/
|
|
STDMETHODIMP
|
|
IPDAT_HrSetPropAccess( LPIPDAT lpIPDAT,
|
|
LPSPropTagArray lpsPropTagArray,
|
|
ULONG FAR * rgulAccess)
|
|
{
|
|
SCODE sc = S_OK;
|
|
ULONG ulcProps;
|
|
ULONG FAR *lpulPropTag;
|
|
ULONG FAR *lpulAccess;
|
|
|
|
#if !defined(NO_VALIDATION)
|
|
/* Make sure the object is valid.
|
|
*/
|
|
if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, HrSetPropAccess, lpVtbl))
|
|
{
|
|
DebugTrace( TEXT("IPDAT::HrSetPropAccess() - Bad object passed\n") );
|
|
return ResultFromScode(MAPI_E_INVALID_PARAMETER);
|
|
}
|
|
|
|
/* Validate parameters.
|
|
*/
|
|
if ( FBadDelPTA(lpsPropTagArray)
|
|
|| IsBadReadPtr(rgulAccess, (UINT) (lpsPropTagArray->cValues)*sizeof(ULONG)))
|
|
{
|
|
return ResultFromScode(MAPI_E_INVALID_PARAMETER);
|
|
}
|
|
|
|
/* Make sure they don't try setting reserved access bits.
|
|
*/
|
|
for ( lpulAccess = rgulAccess + lpsPropTagArray->cValues
|
|
; --lpulAccess >= rgulAccess
|
|
; )
|
|
{
|
|
if ( (*lpulAccess & ~( IPROP_READONLY | IPROP_READWRITE
|
|
| IPROP_CLEAN | IPROP_DIRTY))
|
|
|| !(*lpulAccess & (IPROP_READONLY | IPROP_READWRITE))
|
|
|| ( (*lpulAccess & (IPROP_READONLY | IPROP_READWRITE))
|
|
== (IPROP_READONLY | IPROP_READWRITE))
|
|
|| !(*lpulAccess & (IPROP_CLEAN | IPROP_DIRTY))
|
|
|| ( (*lpulAccess & (IPROP_CLEAN | IPROP_DIRTY))
|
|
== (IPROP_CLEAN | IPROP_DIRTY)))
|
|
{
|
|
DebugTrace( TEXT("IPDAT::HrSetPropAccess() - Conflicting access flags.\n") );
|
|
return ResultFromScode(MAPI_E_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* The exit assumes that we are already in a critical section.
|
|
*/
|
|
UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
|
|
|
|
|
|
// Loop through the list of properties on which to set access/status.
|
|
for ( ulcProps = lpsPropTagArray->cValues
|
|
, lpulPropTag = (ULONG FAR *)(lpsPropTagArray->aulPropTag)
|
|
, lpulAccess = rgulAccess
|
|
; ulcProps
|
|
; ulcProps--, lpulPropTag++, lpulAccess++)
|
|
{
|
|
LPPLSTLNK lppLstLnk;
|
|
|
|
/* If the property is in our list then set the new access rights and
|
|
* status flags for it. If it's not in our list then ignore it.
|
|
*/
|
|
if (lppLstLnk = LPPLSTLNKFindProp( (LPPLSTLNK)
|
|
&(lpIPDAT->lpLstSPV)
|
|
, *lpulPropTag))
|
|
{
|
|
((LPLSTSPV) (*lppLstLnk))->ulAccess = *lpulAccess;
|
|
}
|
|
}
|
|
|
|
/*
|
|
*out:
|
|
*/
|
|
UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
|
|
return MakeResult(sc);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
- IPDAT_HrGetPropAccess
|
|
-
|
|
* Purpose:
|
|
* Returns the read/write access and the clean/dirty status of individual
|
|
* properties contained by the IPropData object.
|
|
*
|
|
* The read/write access bits can be used to prevent a client from
|
|
* changing or deleting a property via the IMAPIProp methods.
|
|
*
|
|
* The clean/dirty bits can be used to determine if a client has changed
|
|
* a writable property.
|
|
*
|
|
* Arguments:
|
|
* lpIPDAT The IPropData object for which property access
|
|
* rights and status is requested.
|
|
* lpsPropTagArray List of property tags whose access/status is requested.
|
|
* lprgulAccess Pointer to the memory location which will receive a
|
|
* pointer to an array of access/status flags in the same
|
|
* order as the list of property tags in <lpsPropTagArray>.
|
|
*
|
|
* Returns:
|
|
* HRESULT
|
|
*
|
|
* Side effects:
|
|
*
|
|
* Errors:
|
|
*/
|
|
STDMETHODIMP
|
|
IPDAT_HrGetPropAccess( LPIPDAT lpIPDAT,
|
|
LPSPropTagArray FAR * lppsPropTagArray,
|
|
ULONG FAR * FAR * lprgulAccess)
|
|
{
|
|
SCODE sc = S_OK;
|
|
HRESULT hResult = hrSuccess;
|
|
ULONG ulcProps;
|
|
LPSPropTagArray lpsPTaga = NULL;
|
|
ULONG FAR *lpulPropTag;
|
|
ULONG FAR *lpulAccessNew = NULL;
|
|
ULONG FAR *lpulAccess;
|
|
|
|
#if !defined(NO_VALIDATION)
|
|
/* Make sure the object is valid.
|
|
*/
|
|
if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, HrGetPropAccess, lpVtbl))
|
|
{
|
|
DebugTrace( TEXT("IPDAT::HrGetPropAccess() - Bad object passed\n") );
|
|
return ResultFromScode(MAPI_E_INVALID_PARAMETER);
|
|
}
|
|
|
|
/* Validate parameters.
|
|
*/
|
|
if ( IsBadReadPtr( lppsPropTagArray, sizeof(LPSPropTagArray))
|
|
|| (*lppsPropTagArray && FBadDelPTA(*lppsPropTagArray))
|
|
|| IsBadWritePtr( lprgulAccess, sizeof(ULONG FAR *)))
|
|
{
|
|
return ResultFromScode(MAPI_E_INVALID_PARAMETER);
|
|
}
|
|
#endif
|
|
|
|
/* The error exit assumes that we are already in a critical section.
|
|
*/
|
|
UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
|
|
|
|
/* If a list of tags was passed in then use it...
|
|
*/
|
|
if (lppsPropTagArray && *lppsPropTagArray)
|
|
{
|
|
lpsPTaga = *lppsPropTagArray;
|
|
} else
|
|
{
|
|
/* ...else get a list of tags for all properties in our list.
|
|
*/
|
|
sc = ScMakePropList(lpIPDAT,
|
|
lpIPDAT->ulCount,
|
|
(LPLSTLNK) lpIPDAT->lpLstSPV,
|
|
&lpsPTaga,
|
|
(ULONG) -1);
|
|
if (FAILED(sc))
|
|
{
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
|
|
/* Allocate space for the list of access rights / status flags.
|
|
*/
|
|
sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT,
|
|
lpsPTaga->cValues * sizeof(ULONG),
|
|
&lpulAccessNew);
|
|
if (FAILED(sc))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
|
|
|
|
/* Loop through the list of properties for which rights/flags are
|
|
* requested.
|
|
*/
|
|
for ( ulcProps = lpsPTaga->cValues
|
|
, lpulPropTag = (ULONG FAR *)(lpsPTaga->aulPropTag)
|
|
, lpulAccess = lpulAccessNew
|
|
; ulcProps
|
|
; ulcProps--, lpulPropTag++, lpulAccess++)
|
|
{
|
|
LPPLSTLNK lppLstLnk;
|
|
|
|
/* If the property is in our list then set the new access rights and
|
|
* status flags for it. If it's not in our list then ignore it.
|
|
*/
|
|
if (lppLstLnk = LPPLSTLNKFindProp( (LPPLSTLNK)
|
|
&(lpIPDAT->lpLstSPV)
|
|
, *lpulPropTag))
|
|
{
|
|
*lpulAccess = ((LPLSTSPV) (*lppLstLnk))->ulAccess;
|
|
}
|
|
}
|
|
|
|
|
|
/* If requested return a tag list to the caller.
|
|
*/
|
|
if (lppsPropTagArray && !*lppsPropTagArray)
|
|
{
|
|
*lppsPropTagArray = lpsPTaga;
|
|
}
|
|
|
|
/* Return the access rights / status flags.
|
|
*/
|
|
*lprgulAccess = lpulAccessNew;
|
|
|
|
goto out;
|
|
|
|
|
|
error:
|
|
/* If we created the tag array then free it.
|
|
*/
|
|
if (!lppsPropTagArray || !*lppsPropTagArray)
|
|
{
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpsPTaga);
|
|
}
|
|
|
|
/* Free the access rights / status flags list.
|
|
*/
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpulAccessNew);
|
|
|
|
UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0);
|
|
|
|
out:
|
|
UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
|
|
return MakeResult(sc);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
- IPDAT_HrAddObjProps
|
|
-
|
|
* Purpose:
|
|
* Since object properties can not be created by SetProps, this method
|
|
* is included so that object properties can be included in the list
|
|
* of properties available from the IPropData object. Adding an object
|
|
* property will result in the property tag showing up in the list when
|
|
* GetPropList is called.
|
|
*
|
|
* Arguments:
|
|
* lpIPDAT The IPropData object for which object properties are
|
|
* to be added.
|
|
* lpPropTags List of object properties to be added.
|
|
* lprgulAccess Pointer to the memory location which will receive a
|
|
* pointer to an array of problem entries if there
|
|
* were problems entering the new properties. NULL if
|
|
* no problems array is desired.
|
|
*
|
|
* Returns:
|
|
* HRESULT
|
|
*
|
|
* Side effects:
|
|
*
|
|
* Errors:
|
|
*/
|
|
STDMETHODIMP
|
|
IPDAT_HrAddObjProps( LPIPDAT lpIPDAT,
|
|
LPSPropTagArray lpPropTags,
|
|
LPSPropProblemArray FAR * lppProblems)
|
|
{
|
|
SCODE sc = S_OK;
|
|
LPSPropProblemArray lpProblems = NULL;
|
|
LPLSTSPV lpLstSPV = NULL;
|
|
SPropValue propVal;
|
|
ULONG UNALIGNED FAR *lpulPropTag;
|
|
ULONG cValues;
|
|
|
|
|
|
#if !defined(NO_VALIDATION)
|
|
/* Make sure the object is valid.
|
|
*/
|
|
if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, HrAddObjProps, lpVtbl))
|
|
{
|
|
DebugTrace( TEXT("IPDAT::HrAddObjProps() - Bad object passed\n") );
|
|
return ResultFromScode(MAPI_E_INVALID_PARAMETER);
|
|
}
|
|
|
|
/* Validate parameters.
|
|
*/
|
|
if ( IsBadReadPtr(lpPropTags, CbNewSPropTagArray(0))
|
|
|| IsBadReadPtr(lpPropTags, CbSPropTagArray(lpPropTags)))
|
|
{
|
|
DebugTrace( TEXT("IPDAT::HrAddObjProps() - Bad Prop Tag Array.\n") );
|
|
return ResultFromScode(MAPI_E_INVALID_PARAMETER);
|
|
}
|
|
|
|
for ( lpulPropTag = lpPropTags->aulPropTag + lpPropTags->cValues
|
|
; --lpulPropTag >= lpPropTags->aulPropTag
|
|
; )
|
|
{
|
|
if ( (PROP_ID(*lpulPropTag) == PROP_ID_NULL)
|
|
|| (PROP_ID(*lpulPropTag) == PROP_ID_INVALID)
|
|
|| (PROP_TYPE(*lpulPropTag) != PT_OBJECT))
|
|
{
|
|
DebugTrace( TEXT("IPDAT::HrAddObjProps() - Bad Prop Tag.\n") );
|
|
return ResultFromScode(MAPI_E_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/* The error exit assumes that we are already in a critical section.
|
|
*/
|
|
UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
|
|
|
|
/* Check access rights...
|
|
*/
|
|
if (!(lpIPDAT->ulObjAccess & IPROP_READWRITE))
|
|
{
|
|
sc = MAPI_E_NO_ACCESS;
|
|
goto error;
|
|
}
|
|
|
|
|
|
if (lppProblems)
|
|
{
|
|
/* Initially indicate that there were no problems.
|
|
*/
|
|
*lppProblems = NULL;
|
|
|
|
|
|
/* Allocate a problem array that is big enough to report problems on
|
|
* all the properties. Unused entries just end up as wasted space.
|
|
*/
|
|
if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT
|
|
, CbNewSPropProblemArray(lpIPDAT->ulCount)
|
|
, &lpProblems)))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
lpProblems->cProblem = 0;
|
|
}
|
|
|
|
|
|
/* Loop through the list and add/replace each property listed.
|
|
*/
|
|
memset( (BYTE *) &propVal, 0, sizeof(SPropValue));
|
|
for ( cValues = lpPropTags->cValues, lpulPropTag = (ULONG FAR *)(lpPropTags->aulPropTag)
|
|
; cValues
|
|
; lpulPropTag++, cValues--)
|
|
{
|
|
LPPLSTLNK lppLstLnk;
|
|
LPLSTSPV lpLstSPV;
|
|
|
|
|
|
/* If the property is in the list and write enabled then delete it
|
|
* from the list.
|
|
*/
|
|
if (lppLstLnk = LPPLSTLNKFindProp( (LPPLSTLNK) &(lpIPDAT->lpLstSPV)
|
|
, *lpulPropTag))
|
|
{
|
|
/* Make sure that we can delete the old property.
|
|
*/
|
|
if ( (lpLstSPV = (LPLSTSPV) (*lppLstLnk))
|
|
&& !(lpLstSPV->ulAccess & IPROP_READWRITE))
|
|
{
|
|
AddProblem( lpProblems
|
|
, cValues
|
|
, *lpulPropTag
|
|
, MAPI_E_NO_ACCESS);
|
|
|
|
continue;
|
|
}
|
|
|
|
|
|
/* Delete the old property.
|
|
*/
|
|
UnlinkLstLnk( lppLstLnk);
|
|
FreeLpLstSPV( lpIPDAT, lpLstSPV);
|
|
lpIPDAT->ulCount -= 1;
|
|
}
|
|
|
|
/* Create a new property entry and link it to our list.
|
|
*/
|
|
|
|
propVal.ulPropTag = *lpulPropTag;
|
|
|
|
if (FAILED(sc = ScCreateSPV( lpIPDAT, &propVal, &lpLstSPV)))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
lpLstSPV->ulAccess = IPROP_READWRITE;
|
|
LinkLstLnk( (LPLSTLNK FAR *) &(lpIPDAT->lpLstSPV)
|
|
, (LPLSTLNK) lpLstSPV);
|
|
lpIPDAT->ulCount += 1;
|
|
}
|
|
|
|
|
|
/* Return the problem array if requested and there were problems...
|
|
*/
|
|
if (lppProblems && lpProblems->cProblem)
|
|
{
|
|
*lppProblems = lpProblems;
|
|
}
|
|
|
|
/* ...else dispose of the problem array.
|
|
*/
|
|
else
|
|
{
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpProblems);
|
|
}
|
|
|
|
goto out;
|
|
|
|
|
|
error:
|
|
/* Free the prop problem array.
|
|
*/
|
|
UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpProblems);
|
|
UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0);
|
|
|
|
out:
|
|
UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
|
|
|
|
return MakeResult(sc);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Synopsis: SCODE ScWCToAnsi()
|
|
//
|
|
// Description:
|
|
// Converts a Wide Char string to an Ansi string with the passed
|
|
// in MAPI More Allocator.
|
|
// If lpMapiAllocMore and lpBase are NULL and *lppszAnsi is not NULL
|
|
// then we assume *lppszAnsi is a pre allocated buffer
|
|
//
|
|
// Parameters:
|
|
// Returns:
|
|
// Effects:
|
|
// Notes:
|
|
// Revision:
|
|
//----------------------------------------------------------------------------
|
|
SCODE ScWCToAnsiMore( LPALLOCATEMORE lpMapiAllocMore, LPVOID lpBase,
|
|
LPWSTR lpszWC, LPSTR * lppszAnsi )
|
|
{
|
|
SCODE sc = S_OK;
|
|
INT cch;
|
|
|
|
if ( !lpszWC )
|
|
{
|
|
if(lpMapiAllocMore && lpBase)
|
|
*lppszAnsi = NULL;
|
|
else
|
|
if(*lppszAnsi)
|
|
*(*lppszAnsi) = '\0';
|
|
goto ret;
|
|
}
|
|
|
|
// [PaulHi] 3/31/99 Raid 73845 Determine the actual DBCS buffer size needed
|
|
// cch = lstrlenW( lpszWC ) + 1;
|
|
cch = WideCharToMultiByte(CP_ACP, 0, lpszWC, -1, NULL, 0, NULL, NULL) + 1;
|
|
|
|
if(lpMapiAllocMore && lpBase)
|
|
{
|
|
sc = lpMapiAllocMore( cch, lpBase, lppszAnsi );
|
|
if ( FAILED( sc ) )
|
|
{
|
|
DebugTrace( TEXT("ScWCToAnsi() OOM\n") );
|
|
goto ret;
|
|
}
|
|
}
|
|
|
|
if (!lppszAnsi || !WideCharToMultiByte(CP_ACP, 0, lpszWC, -1, *lppszAnsi, cch, NULL, NULL))
|
|
{
|
|
DebugTrace( TEXT("ScWcToAnsi(), Conversion from Wide char to multibyte failed\n") );
|
|
sc = MAPI_E_CALL_FAILED;
|
|
goto ret;
|
|
}
|
|
|
|
ret:
|
|
|
|
DebugTraceSc( ScWCToAnsi, sc );
|
|
return sc;
|
|
}
|
|
|
|
/*
|
|
-
|
|
- LPCSTR ConvertWtoA(LPWSTR lpszW);
|
|
*
|
|
* LocalAllocs a ANSI version of an LPWSTR
|
|
*
|
|
* Caller is responsible for freeing
|
|
*/
|
|
LPSTR ConvertWtoA(LPCWSTR lpszW)
|
|
{
|
|
int cch;
|
|
LPSTR lpC = NULL;
|
|
|
|
if ( !lpszW)
|
|
goto ret;
|
|
|
|
// cch = lstrlenW( lpszW ) + 1;
|
|
|
|
cch = WideCharToMultiByte( CP_ACP, 0, lpszW, -1, NULL, 0, NULL, NULL );
|
|
cch = cch + 1;
|
|
|
|
if(lpC = LocalAlloc(LMEM_ZEROINIT, cch))
|
|
{
|
|
WideCharToMultiByte( CP_ACP, 0, lpszW, -1, lpC, cch, NULL, NULL );
|
|
}
|
|
ret:
|
|
return lpC;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Synopsis: SCODE ScAnsiToWC()
|
|
//
|
|
// Description:
|
|
// Converts an ANSI string to a Wide Character string with the
|
|
// passed in MAPI More allocator.
|
|
// If lpMapiAllocMore and lpBase are NULL and *lppszWC is not NULL
|
|
// then we assume *lppszWC is a pre allocated buffer
|
|
// Parameters:
|
|
// Returns:
|
|
// Effects:
|
|
// Notes:
|
|
// Revision:
|
|
//----------------------------------------------------------------------------
|
|
SCODE ScAnsiToWCMore( LPALLOCATEMORE lpMapiAllocMore, LPVOID lpBase,
|
|
LPSTR lpszAnsi, LPWSTR * lppszWC )
|
|
{
|
|
SCODE sc = S_OK;
|
|
INT cch;
|
|
ULONG ulSize;
|
|
|
|
if ( !lpszAnsi )
|
|
{
|
|
if(lpMapiAllocMore && lpBase)
|
|
*lppszWC = NULL;
|
|
goto ret;
|
|
}
|
|
|
|
cch = lstrlenA( lpszAnsi ) + 1;
|
|
ulSize = cch * sizeof( WCHAR );
|
|
|
|
if(lpMapiAllocMore && lpBase)
|
|
{
|
|
sc = lpMapiAllocMore( ulSize, lpBase, lppszWC );
|
|
if ( FAILED( sc ) )
|
|
{
|
|
DebugTrace( TEXT("ScAnsiToWC() OOM\n") );
|
|
goto ret;
|
|
}
|
|
}
|
|
|
|
if ( !MultiByteToWideChar( GetACP(), 0, lpszAnsi, -1, *lppszWC, cch ) )
|
|
{
|
|
DebugTrace( TEXT("ScAnsiToWC(), Conversion from Wide char to multibyte failed\n") );
|
|
sc = MAPI_E_CALL_FAILED;
|
|
goto ret;
|
|
}
|
|
|
|
ret:
|
|
|
|
DebugTraceSc( ScAnsiToWC, sc );
|
|
return sc;
|
|
}
|
|
/*
|
|
-
|
|
- LPCSTR ConvertWtoA(LPWSTR lpszW);
|
|
*
|
|
* LocalAllocs a ANSI version of an LPWSTR
|
|
*
|
|
* Caller is responsible for freeing
|
|
*/
|
|
LPWSTR ConvertAtoW(LPCSTR lpszA)
|
|
{
|
|
int cch;
|
|
LPWSTR lpW = NULL;
|
|
ULONG ulSize;
|
|
|
|
if ( !lpszA)
|
|
goto ret;
|
|
|
|
cch = (lstrlenA( lpszA ) + 1);
|
|
ulSize = cch*sizeof(WCHAR);
|
|
|
|
if(lpW = LocalAlloc(LMEM_ZEROINIT, ulSize))
|
|
{
|
|
MultiByteToWideChar( GetACP(), 0, lpszA, -1, lpW, cch );
|
|
}
|
|
ret:
|
|
return lpW;
|
|
}
|
|
|
|
|
|
/*
|
|
-
|
|
- ScConvertAPropsToW
|
|
-
|
|
* Takes in an SPropValue array and goes in and adds W versions of all strings
|
|
* to replace the A versions
|
|
* It's assumed that all the MAPIAllocations will take place off the root of the
|
|
* SPropValue array
|
|
*
|
|
*/
|
|
SCODE ScConvertAPropsToW(LPALLOCATEMORE lpMapiAllocMore, LPSPropValue lpPropValue, ULONG ulcProps, ULONG ulStart)
|
|
{
|
|
ULONG iProp = 0;
|
|
SCODE sc = 0;
|
|
LPWSTR lpszConvertedW = NULL;
|
|
|
|
// There are 2 types of props we want to convert
|
|
// PT_STRING8 and
|
|
// PT_MV_STRING8
|
|
|
|
for ( iProp = ulStart; iProp < ulcProps; iProp++ )
|
|
{
|
|
// Convert ANSI strings to UNICODE if required
|
|
if (PROP_TYPE( lpPropValue[iProp].ulPropTag ) == PT_STRING8 )
|
|
{
|
|
//if ( !lpPropTagArray ||
|
|
// (lpPropTagArray && ( PROP_TYPE( lpPropTagArray->aulPropTag[iProp] ) == PT_UNSPECIFIED ) ) )
|
|
{
|
|
sc = ScAnsiToWCMore( lpMapiAllocMore, lpPropValue,
|
|
lpPropValue[iProp].Value.lpszA, (LPWSTR *)&lpszConvertedW );
|
|
if ( FAILED( sc ) )
|
|
goto error;
|
|
|
|
lpPropValue[iProp].Value.lpszW = (LPWSTR)lpszConvertedW;
|
|
lpszConvertedW = NULL;
|
|
|
|
// Fix up PropTag
|
|
lpPropValue[iProp].ulPropTag = CHANGE_PROP_TYPE( lpPropValue[iProp].ulPropTag,
|
|
PT_UNICODE );
|
|
}
|
|
}
|
|
else
|
|
if (PROP_TYPE( lpPropValue[iProp].ulPropTag ) == PT_MV_STRING8 )
|
|
{
|
|
//if ( !lpPropTagArray ||
|
|
// (lpPropTagArray && ( PROP_TYPE( lpPropTagArray->aulPropTag[iProp] ) == PT_UNSPECIFIED ) ) )
|
|
{
|
|
ULONG j = 0;
|
|
ULONG ulCount = lpPropValue[iProp].Value.MVszA.cValues;
|
|
LPWSTR * lppszW = NULL;
|
|
|
|
if(sc = lpMapiAllocMore(sizeof(LPWSTR)*ulCount,lpPropValue,
|
|
(LPVOID *)&lppszW))
|
|
goto error;
|
|
|
|
for(j=0;j<ulCount;j++)
|
|
{
|
|
sc = ScAnsiToWCMore(lpMapiAllocMore, lpPropValue,
|
|
lpPropValue[iProp].Value.MVszA.lppszA[j], (LPWSTR *)&lpszConvertedW );
|
|
if ( FAILED( sc ) )
|
|
goto error;
|
|
lppszW[j] = (LPWSTR)lpszConvertedW;
|
|
lpszConvertedW = NULL;
|
|
|
|
// Fix up PropTag
|
|
lpPropValue[iProp].ulPropTag = CHANGE_PROP_TYPE( lpPropValue[iProp].ulPropTag,
|
|
PT_MV_UNICODE );
|
|
}
|
|
lpPropValue[iProp].Value.MVszW.lppszW = lppszW;
|
|
}
|
|
}
|
|
}
|
|
|
|
error:
|
|
|
|
return ResultFromScode(sc);
|
|
}
|
|
|
|
|
|
/*
|
|
-
|
|
- ScConvertWPropsToA
|
|
-
|
|
* Takes in an SPropValue array and goes in and adds A versions of all strings
|
|
* to replace the W versions
|
|
* It's assumed that all the MAPIAllocations will take place off the root of the
|
|
* SPropValue array
|
|
*
|
|
*/
|
|
SCODE ScConvertWPropsToA(LPALLOCATEMORE lpMapiAllocMore, LPSPropValue lpPropValue, ULONG ulcProps, ULONG ulStart)
|
|
{
|
|
ULONG iProp = 0;
|
|
SCODE sc = 0;
|
|
LPSTR lpszConvertedA = NULL;
|
|
|
|
// There are 2 types of props we want to convert
|
|
// PT_STRING8 and
|
|
// PT_MV_STRING8
|
|
|
|
for ( iProp = ulStart; iProp < ulcProps; iProp++ )
|
|
{
|
|
// Convert ANSI strings to UNICODE if required
|
|
if (PROP_TYPE( lpPropValue[iProp].ulPropTag ) == PT_UNICODE )
|
|
{
|
|
//if ( !lpPropTagArray ||
|
|
// (lpPropTagArray && ( PROP_TYPE( lpPropTagArray->aulPropTag[iProp] ) == PT_UNSPECIFIED ) ) )
|
|
{
|
|
sc = ScWCToAnsiMore(lpMapiAllocMore, lpPropValue,
|
|
lpPropValue[iProp].Value.lpszW, (LPSTR *)&lpszConvertedA );
|
|
if ( FAILED( sc ) )
|
|
goto error;
|
|
|
|
lpPropValue[iProp].Value.lpszA = (LPSTR)lpszConvertedA;
|
|
lpszConvertedA = NULL;
|
|
|
|
// Fix up PropTag
|
|
lpPropValue[iProp].ulPropTag = CHANGE_PROP_TYPE( lpPropValue[iProp].ulPropTag,
|
|
PT_STRING8 );
|
|
}
|
|
}
|
|
else
|
|
if (PROP_TYPE( lpPropValue[iProp].ulPropTag ) == PT_MV_UNICODE )
|
|
{
|
|
//if ( !lpPropTagArray ||
|
|
// (lpPropTagArray && ( PROP_TYPE( lpPropTagArray->aulPropTag[iProp] ) == PT_UNSPECIFIED ) ) )
|
|
{
|
|
ULONG j = 0;
|
|
ULONG ulCount = lpPropValue[iProp].Value.MVszW.cValues;
|
|
LPSTR * lppszA = NULL;
|
|
|
|
if(sc = lpMapiAllocMore(sizeof(LPSTR)*ulCount,lpPropValue,
|
|
(LPVOID *)&lppszA))
|
|
goto error;
|
|
|
|
for(j=0;j<ulCount;j++)
|
|
{
|
|
sc = ScWCToAnsiMore(lpMapiAllocMore, lpPropValue,
|
|
lpPropValue[iProp].Value.MVszW.lppszW[j], (LPSTR *)&lpszConvertedA );
|
|
if ( FAILED( sc ) )
|
|
goto error;
|
|
lppszA[j] = (LPSTR)lpszConvertedA;
|
|
lpszConvertedA = NULL;
|
|
|
|
// Fix up PropTag
|
|
lpPropValue[iProp].ulPropTag = CHANGE_PROP_TYPE( lpPropValue[iProp].ulPropTag,
|
|
PT_MV_STRING8 );
|
|
}
|
|
lpPropValue[iProp].Value.MVszA.lppszA = lppszA;
|
|
}
|
|
}
|
|
}
|
|
|
|
error:
|
|
|
|
return ResultFromScode(sc);
|
|
}
|