4 * Copyright 2004 Jon Griffiths
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "wine/list.h"
31 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(mapi
);
36 BOOL WINAPI
FBadRglpszA(LPSTR
*,ULONG
);
38 /* Internal: Check if a property value array is invalid */
39 static inline ULONG
PROP_BadArray(LPSPropValue lpProp
, size_t elemSize
)
41 return IsBadReadPtr(lpProp
->Value
.MVi
.lpi
, lpProp
->Value
.MVi
.cValues
* elemSize
);
44 /*************************************************************************
45 * PropCopyMore@16 (MAPI32.76)
47 * Copy a property value.
50 * lpDest [O] Destination for the copied value
51 * lpSrc [I] Property value to copy to lpDest
52 * lpMore [I] Linked memory allocation function (pass MAPIAllocateMore())
53 * lpOrig [I] Original allocation to which memory will be linked
56 * Success: S_OK. lpDest contains a deep copy of lpSrc.
57 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid,
58 * MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails.
61 * Any elements within the property returned should not be individually
62 * freed, as they will be freed when lpOrig is.
64 SCODE WINAPI
PropCopyMore(LPSPropValue lpDest
, LPSPropValue lpSrc
,
65 ALLOCATEMORE
*lpMore
, LPVOID lpOrig
)
70 TRACE("(%p,%p,%p,%p)\n", lpDest
, lpSrc
, lpMore
, lpOrig
);
72 if (!lpDest
|| IsBadWritePtr(lpDest
, sizeof(SPropValue
)) ||
73 FBadProp(lpSrc
) || !lpMore
)
74 return MAPI_E_INVALID_PARAMETER
;
76 /* Shallow copy first, this is sufficient for properties without pointers */
79 switch (PROP_TYPE(lpSrc
->ulPropTag
))
82 scode
= lpMore(sizeof(GUID
), lpOrig
, (LPVOID
*)&lpDest
->Value
.lpguid
);
84 *lpDest
->Value
.lpguid
= *lpSrc
->Value
.lpguid
;
87 ulLen
= lstrlenA(lpSrc
->Value
.lpszA
) + 1u;
88 scode
= lpMore(ulLen
, lpOrig
, (LPVOID
*)&lpDest
->Value
.lpszA
);
90 memcpy(lpDest
->Value
.lpszA
, lpSrc
->Value
.lpszA
, ulLen
);
93 ulLen
= (lstrlenW(lpSrc
->Value
.lpszW
) + 1u) * sizeof(WCHAR
);
94 scode
= lpMore(ulLen
, lpOrig
, (LPVOID
*)&lpDest
->Value
.lpszW
);
96 memcpy(lpDest
->Value
.lpszW
, lpSrc
->Value
.lpszW
, ulLen
);
99 scode
= lpMore(lpSrc
->Value
.bin
.cb
, lpOrig
, (LPVOID
*)&lpDest
->Value
.bin
.lpb
);
100 if (SUCCEEDED(scode
))
101 memcpy(lpDest
->Value
.bin
.lpb
, lpSrc
->Value
.bin
.lpb
, lpSrc
->Value
.bin
.cb
);
104 if (lpSrc
->ulPropTag
& MV_FLAG
)
106 ulLen
= UlPropSize(lpSrc
);
108 if (PROP_TYPE(lpSrc
->ulPropTag
) == PT_MV_STRING8
||
109 PROP_TYPE(lpSrc
->ulPropTag
) == PT_MV_UNICODE
)
111 /* UlPropSize doesn't account for the string pointers */
112 ulLen
+= lpSrc
->Value
.MVszA
.cValues
* sizeof(char*);
114 else if (PROP_TYPE(lpSrc
->ulPropTag
) == PT_MV_BINARY
)
116 /* UlPropSize doesn't account for the SBinary structs */
117 ulLen
+= lpSrc
->Value
.MVbin
.cValues
* sizeof(SBinary
);
120 lpDest
->Value
.MVi
.cValues
= lpSrc
->Value
.MVi
.cValues
;
121 scode
= lpMore(ulLen
, lpOrig
, (LPVOID
*)&lpDest
->Value
.MVi
.lpi
);
125 /* Note that we could allocate the memory for each value in a
126 * multi-value property separately, however if an allocation failed
127 * we would be left with a bunch of allocated memory, which (while
128 * not really leaked) is unusable until lpOrig is freed. So for
129 * strings and binary arrays we make a single allocation for all
130 * of the data. This is consistent since individual elements can't
134 switch (PROP_TYPE(lpSrc
->ulPropTag
))
138 char *lpNextStr
= (char*)(lpDest
->Value
.MVszA
.lppszA
+
139 lpDest
->Value
.MVszA
.cValues
);
141 for (i
= 0; i
< lpSrc
->Value
.MVszA
.cValues
; i
++)
143 ULONG ulStrLen
= lstrlenA(lpSrc
->Value
.MVszA
.lppszA
[i
]) + 1u;
145 lpDest
->Value
.MVszA
.lppszA
[i
] = lpNextStr
;
146 memcpy(lpNextStr
, lpSrc
->Value
.MVszA
.lppszA
[i
], ulStrLen
);
147 lpNextStr
+= ulStrLen
;
153 WCHAR
*lpNextStr
= (WCHAR
*)(lpDest
->Value
.MVszW
.lppszW
+
154 lpDest
->Value
.MVszW
.cValues
);
156 for (i
= 0; i
< lpSrc
->Value
.MVszW
.cValues
; i
++)
158 ULONG ulStrLen
= lstrlenW(lpSrc
->Value
.MVszW
.lppszW
[i
]) + 1u;
160 lpDest
->Value
.MVszW
.lppszW
[i
] = lpNextStr
;
161 memcpy(lpNextStr
, lpSrc
->Value
.MVszW
.lppszW
[i
], ulStrLen
* sizeof(WCHAR
));
162 lpNextStr
+= ulStrLen
;
168 LPBYTE lpNext
= (LPBYTE
)(lpDest
->Value
.MVbin
.lpbin
+
169 lpDest
->Value
.MVbin
.cValues
);
171 for (i
= 0; i
< lpSrc
->Value
.MVszW
.cValues
; i
++)
173 lpDest
->Value
.MVbin
.lpbin
[i
].cb
= lpSrc
->Value
.MVbin
.lpbin
[i
].cb
;
174 lpDest
->Value
.MVbin
.lpbin
[i
].lpb
= lpNext
;
175 memcpy(lpNext
, lpSrc
->Value
.MVbin
.lpbin
[i
].lpb
, lpDest
->Value
.MVbin
.lpbin
[i
].cb
);
176 lpNext
+= lpDest
->Value
.MVbin
.lpbin
[i
].cb
;
181 /* No embedded pointers, just copy the data over */
182 memcpy(lpDest
->Value
.MVi
.lpi
, lpSrc
->Value
.MVi
.lpi
, ulLen
);
191 /*************************************************************************
192 * UlPropSize@4 (MAPI32.77)
194 * Determine the size of a property in bytes.
197 * lpProp [I] Property to determine the size of
200 * Success: The size of the value in lpProp.
201 * Failure: 0, if a multi-value (array) property is invalid or the type of lpProp
205 * - The size returned does not include the size of the SPropValue struct
206 * or the size of the array of pointers for multi-valued properties that
207 * contain pointers (such as PT_MV_STRING8 or PT-MV_UNICODE).
208 * - MSDN incorrectly states that this function returns MAPI_E_CALL_FAILED if
209 * lpProp is invalid. In reality no checking is performed and this function
210 * will crash if passed an invalid property, or return 0 if the property
211 * type is PT_OBJECT or is unknown.
213 ULONG WINAPI
UlPropSize(LPSPropValue lpProp
)
217 TRACE("(%p)\n", lpProp
);
219 switch (PROP_TYPE(lpProp
->ulPropTag
))
221 case PT_MV_I2
: ulRet
= lpProp
->Value
.MVi
.cValues
;
224 case PT_I2
: ulRet
*= sizeof(USHORT
);
226 case PT_MV_I4
: ulRet
= lpProp
->Value
.MVl
.cValues
;
229 case PT_I4
: ulRet
*= sizeof(LONG
);
231 case PT_MV_I8
: ulRet
= lpProp
->Value
.MVli
.cValues
;
233 case PT_I8
: ulRet
*= sizeof(LONG64
);
235 case PT_MV_R4
: ulRet
= lpProp
->Value
.MVflt
.cValues
;
237 case PT_R4
: ulRet
*= sizeof(float);
240 case PT_MV_R8
: ulRet
= lpProp
->Value
.MVdbl
.cValues
;
243 case PT_R8
: ulRet
*= sizeof(double);
245 case PT_MV_CURRENCY
: ulRet
= lpProp
->Value
.MVcur
.cValues
;
247 case PT_CURRENCY
: ulRet
*= sizeof(CY
);
249 case PT_MV_SYSTIME
: ulRet
= lpProp
->Value
.MVft
.cValues
;
251 case PT_SYSTIME
: ulRet
*= sizeof(FILETIME
);
253 case PT_MV_CLSID
: ulRet
= lpProp
->Value
.MVguid
.cValues
;
255 case PT_CLSID
: ulRet
*= sizeof(GUID
);
257 case PT_MV_STRING8
: ulRet
= 0u;
258 for (i
= 0; i
< lpProp
->Value
.MVszA
.cValues
; i
++)
259 ulRet
+= (lstrlenA(lpProp
->Value
.MVszA
.lppszA
[i
]) + 1u);
261 case PT_STRING8
: ulRet
= lstrlenA(lpProp
->Value
.lpszA
) + 1u;
263 case PT_MV_UNICODE
: ulRet
= 0u;
264 for (i
= 0; i
< lpProp
->Value
.MVszW
.cValues
; i
++)
265 ulRet
+= (lstrlenW(lpProp
->Value
.MVszW
.lppszW
[i
]) + 1u);
266 ulRet
*= sizeof(WCHAR
);
268 case PT_UNICODE
: ulRet
= (lstrlenW(lpProp
->Value
.lpszW
) + 1u) * sizeof(WCHAR
);
270 case PT_MV_BINARY
: ulRet
= 0u;
271 for (i
= 0; i
< lpProp
->Value
.MVbin
.cValues
; i
++)
272 ulRet
+= lpProp
->Value
.MVbin
.lpbin
[i
].cb
;
274 case PT_BINARY
: ulRet
= lpProp
->Value
.bin
.cb
;
284 /*************************************************************************
285 * FPropContainsProp@12 (MAPI32.78)
287 * Find a property with a given property tag in a property array.
290 * lpHaystack [I] Property to match to
291 * lpNeedle [I] Property to find in lpHaystack
292 * ulFuzzy [I] Flags controlling match type and strictness (FL_* flags from "mapidefs.h")
295 * TRUE, if lpNeedle matches lpHaystack according to the criteria of ulFuzzy.
298 * Only property types of PT_STRING8 and PT_BINARY are handled by this function.
300 BOOL WINAPI
FPropContainsProp(LPSPropValue lpHaystack
, LPSPropValue lpNeedle
, ULONG ulFuzzy
)
302 TRACE("(%p,%p,0x%08lx)\n", lpHaystack
, lpNeedle
, ulFuzzy
);
304 if (FBadProp(lpHaystack
) || FBadProp(lpNeedle
) ||
305 PROP_TYPE(lpHaystack
->ulPropTag
) != PROP_TYPE(lpNeedle
->ulPropTag
))
308 /* FIXME: Do later versions support Unicode as well? */
310 if (PROP_TYPE(lpHaystack
->ulPropTag
) == PT_STRING8
)
312 DWORD dwFlags
= 0, dwNeedleLen
, dwHaystackLen
;
314 if (ulFuzzy
& FL_IGNORECASE
)
315 dwFlags
|= NORM_IGNORECASE
;
316 if (ulFuzzy
& FL_IGNORENONSPACE
)
317 dwFlags
|= NORM_IGNORENONSPACE
;
318 if (ulFuzzy
& FL_LOOSE
)
319 dwFlags
|= (NORM_IGNORECASE
|NORM_IGNORENONSPACE
|NORM_IGNORESYMBOLS
);
321 dwNeedleLen
= lstrlenA(lpNeedle
->Value
.lpszA
);
322 dwHaystackLen
= lstrlenA(lpHaystack
->Value
.lpszA
);
324 if ((ulFuzzy
& (FL_SUBSTRING
|FL_PREFIX
)) == FL_PREFIX
)
326 if (dwNeedleLen
<= dwHaystackLen
&&
327 CompareStringA(LOCALE_USER_DEFAULT
, dwFlags
,
328 lpHaystack
->Value
.lpszA
, dwNeedleLen
,
329 lpNeedle
->Value
.lpszA
, dwNeedleLen
) == CSTR_EQUAL
)
330 return TRUE
; /* needle is a prefix of haystack */
332 else if ((ulFuzzy
& (FL_SUBSTRING
|FL_PREFIX
)) == FL_SUBSTRING
)
334 LPSTR (WINAPI
*pStrChrFn
)(LPCSTR
,WORD
) = StrChrA
;
335 LPSTR lpStr
= lpHaystack
->Value
.lpszA
;
337 if (dwFlags
& NORM_IGNORECASE
)
338 pStrChrFn
= StrChrIA
;
340 while ((lpStr
= pStrChrFn(lpStr
, *lpNeedle
->Value
.lpszA
)) != NULL
)
342 dwHaystackLen
-= (lpStr
- lpHaystack
->Value
.lpszA
);
343 if (dwNeedleLen
<= dwHaystackLen
&&
344 CompareStringA(LOCALE_USER_DEFAULT
, dwFlags
,
346 lpNeedle
->Value
.lpszA
, dwNeedleLen
) == CSTR_EQUAL
)
347 return TRUE
; /* needle is a substring of haystack */
351 else if (CompareStringA(LOCALE_USER_DEFAULT
, dwFlags
,
352 lpHaystack
->Value
.lpszA
, dwHaystackLen
,
353 lpNeedle
->Value
.lpszA
, dwNeedleLen
) == CSTR_EQUAL
)
354 return TRUE
; /* full string match */
356 else if (PROP_TYPE(lpHaystack
->ulPropTag
) == PT_BINARY
)
358 if ((ulFuzzy
& (FL_SUBSTRING
|FL_PREFIX
)) == FL_PREFIX
)
360 if (lpNeedle
->Value
.bin
.cb
<= lpHaystack
->Value
.bin
.cb
&&
361 !memcmp(lpNeedle
->Value
.bin
.lpb
, lpHaystack
->Value
.bin
.lpb
,
362 lpNeedle
->Value
.bin
.cb
))
363 return TRUE
; /* needle is a prefix of haystack */
365 else if ((ulFuzzy
& (FL_SUBSTRING
|FL_PREFIX
)) == FL_SUBSTRING
)
367 ULONG ulLen
= lpHaystack
->Value
.bin
.cb
;
368 LPBYTE lpb
= lpHaystack
->Value
.bin
.lpb
;
370 while ((lpb
= memchr(lpb
, *lpNeedle
->Value
.bin
.lpb
, ulLen
)) != NULL
)
372 ulLen
= lpHaystack
->Value
.bin
.cb
- (lpb
- lpHaystack
->Value
.bin
.lpb
);
373 if (lpNeedle
->Value
.bin
.cb
<= ulLen
&&
374 !memcmp(lpNeedle
->Value
.bin
.lpb
, lpb
, lpNeedle
->Value
.bin
.cb
))
375 return TRUE
; /* needle is a substring of haystack */
379 else if (!LPropCompareProp(lpHaystack
, lpNeedle
))
380 return TRUE
; /* needle is an exact match with haystack */
386 /*************************************************************************
387 * FPropCompareProp@12 (MAPI32.79)
389 * Compare two properties.
392 * lpPropLeft [I] Left hand property to compare to lpPropRight
393 * ulOp [I] Comparison operator (RELOP_* enum from "mapidefs.h")
394 * lpPropRight [I] Right hand property to compare to lpPropLeft
397 * TRUE, if the comparison is true, FALSE otherwise.
399 BOOL WINAPI
FPropCompareProp(LPSPropValue lpPropLeft
, ULONG ulOp
, LPSPropValue lpPropRight
)
403 TRACE("(%p,%ld,%p)\n", lpPropLeft
, ulOp
, lpPropRight
);
405 if (ulOp
> RELOP_RE
|| FBadProp(lpPropLeft
) || FBadProp(lpPropRight
))
408 if (ulOp
== RELOP_RE
)
410 FIXME("Comparison operator RELOP_RE not yet implemented!\n");
414 iCmp
= LPropCompareProp(lpPropLeft
, lpPropRight
);
418 case RELOP_LT
: return iCmp
< 0;
419 case RELOP_LE
: return iCmp
<= 0;
420 case RELOP_GT
: return iCmp
> 0;
421 case RELOP_GE
: return iCmp
>= 0;
422 case RELOP_EQ
: return iCmp
== 0;
423 case RELOP_NE
: return iCmp
!= 0;
428 /*************************************************************************
429 * LPropCompareProp@8 (MAPI32.80)
431 * Compare two properties.
434 * lpPropLeft [I] Left hand property to compare to lpPropRight
435 * lpPropRight [I] Right hand property to compare to lpPropLeft
438 * An integer less than, equal to or greater than 0, indicating that
439 * lpszStr is less than, the same, or greater than lpszComp.
441 LONG WINAPI
LPropCompareProp(LPSPropValue lpPropLeft
, LPSPropValue lpPropRight
)
445 TRACE("(%p->0x%08lx,%p->0x%08lx)\n", lpPropLeft
, lpPropLeft
->ulPropTag
,
446 lpPropRight
, lpPropRight
->ulPropTag
);
448 /* If the properties are not the same, sort by property type */
449 if (PROP_TYPE(lpPropLeft
->ulPropTag
) != PROP_TYPE(lpPropRight
->ulPropTag
))
450 return (LONG
)PROP_TYPE(lpPropLeft
->ulPropTag
) - (LONG
)PROP_TYPE(lpPropRight
->ulPropTag
);
452 switch (PROP_TYPE(lpPropLeft
->ulPropTag
))
456 return 0; /* NULLs are equal */
458 return lpPropLeft
->Value
.i
- lpPropRight
->Value
.i
;
460 return lpPropLeft
->Value
.l
- lpPropRight
->Value
.l
;
462 if (lpPropLeft
->Value
.li
.QuadPart
> lpPropRight
->Value
.li
.QuadPart
)
464 if (lpPropLeft
->Value
.li
.QuadPart
== lpPropRight
->Value
.li
.QuadPart
)
468 if (lpPropLeft
->Value
.flt
> lpPropRight
->Value
.flt
)
470 if (lpPropLeft
->Value
.flt
== lpPropRight
->Value
.flt
)
475 if (lpPropLeft
->Value
.dbl
> lpPropRight
->Value
.dbl
)
477 if (lpPropLeft
->Value
.dbl
== lpPropRight
->Value
.dbl
)
481 if (lpPropLeft
->Value
.cur
.int64
> lpPropRight
->Value
.cur
.int64
)
483 if (lpPropLeft
->Value
.cur
.int64
== lpPropRight
->Value
.cur
.int64
)
487 return CompareFileTime(&lpPropLeft
->Value
.ft
, &lpPropRight
->Value
.ft
);
489 return (lpPropLeft
->Value
.b
? 1 : 0) - (lpPropRight
->Value
.b
? 1 : 0);
491 if (lpPropLeft
->Value
.bin
.cb
== lpPropRight
->Value
.bin
.cb
)
492 iRet
= memcmp(lpPropLeft
->Value
.bin
.lpb
, lpPropRight
->Value
.bin
.lpb
,
493 lpPropLeft
->Value
.bin
.cb
);
496 iRet
= memcmp(lpPropLeft
->Value
.bin
.lpb
, lpPropRight
->Value
.bin
.lpb
,
497 min(lpPropLeft
->Value
.bin
.cb
, lpPropRight
->Value
.bin
.cb
));
500 iRet
= lpPropLeft
->Value
.bin
.cb
- lpPropRight
->Value
.bin
.cb
;
504 return lstrcmpA(lpPropLeft
->Value
.lpszA
, lpPropRight
->Value
.lpszA
);
506 return lstrcmpW(lpPropLeft
->Value
.lpszW
, lpPropRight
->Value
.lpszW
);
508 if (lpPropLeft
->Value
.err
> lpPropRight
->Value
.err
)
510 if (lpPropLeft
->Value
.err
== lpPropRight
->Value
.err
)
514 return memcmp(lpPropLeft
->Value
.lpguid
, lpPropRight
->Value
.lpguid
,
517 FIXME("Unhandled property type %ld\n", PROP_TYPE(lpPropLeft
->ulPropTag
));
521 /*************************************************************************
522 * HrGetOneProp@8 (MAPI32.135)
524 * Get a property value from an IMAPIProp object.
527 * lpIProp [I] IMAPIProp object to get the property value in
528 * ulPropTag [I] Property tag of the property to get
529 * lppProp [O] Destination for the returned property
532 * Success: S_OK. *lppProp contains the property value requested.
533 * Failure: MAPI_E_NOT_FOUND, if no property value has the tag given by ulPropTag.
535 HRESULT WINAPI
HrGetOneProp(LPMAPIPROP lpIProp
, ULONG ulPropTag
, LPSPropValue
*lppProp
)
541 TRACE("(%p,%ld,%p)\n", lpIProp
, ulPropTag
, lppProp
);
544 pta
.aulPropTag
[0] = ulPropTag
;
545 hRet
= IMAPIProp_GetProps(lpIProp
, &pta
, 0u, &ulCount
, lppProp
);
546 if (hRet
== MAPI_W_ERRORS_RETURNED
)
548 MAPIFreeBuffer(*lppProp
);
550 hRet
= MAPI_E_NOT_FOUND
;
555 /*************************************************************************
556 * HrSetOneProp@8 (MAPI32.136)
558 * Set a property value in an IMAPIProp object.
561 * lpIProp [I] IMAPIProp object to set the property value in
562 * lpProp [I] Property value to set
565 * Success: S_OK. The value in lpProp is set in lpIProp.
566 * Failure: An error result from IMAPIProp_SetProps().
568 HRESULT WINAPI
HrSetOneProp(LPMAPIPROP lpIProp
, LPSPropValue lpProp
)
570 TRACE("(%p,%p)\n", lpIProp
, lpProp
);
572 return IMAPIProp_SetProps(lpIProp
, 1u, lpProp
, NULL
);
575 /*************************************************************************
576 * FPropExists@8 (MAPI32.137)
578 * Find a property with a given property tag in an IMAPIProp object.
581 * lpIProp [I] IMAPIProp object to find the property tag in
582 * ulPropTag [I] Property tag to find
585 * TRUE, if ulPropTag matches a property held in lpIProp,
589 * if ulPropTag has a property type of PT_UNSPECIFIED, then only the property
590 * Ids need to match for a successful match to occur.
592 BOOL WINAPI
FPropExists(LPMAPIPROP lpIProp
, ULONG ulPropTag
)
596 TRACE("(%p,%ld)\n", lpIProp
, ulPropTag
);
600 LPSPropTagArray lpTags
;
603 if (FAILED(IMAPIProp_GetPropList(lpIProp
, 0u, &lpTags
)))
606 for (i
= 0; i
< lpTags
->cValues
; i
++)
608 if (!FBadPropTag(lpTags
->aulPropTag
[i
]) &&
609 (lpTags
->aulPropTag
[i
] == ulPropTag
||
610 (PROP_TYPE(ulPropTag
) == PT_UNSPECIFIED
&&
611 PROP_ID(lpTags
->aulPropTag
[i
]) == lpTags
->aulPropTag
[i
])))
617 MAPIFreeBuffer(lpTags
);
622 /*************************************************************************
623 * PpropFindProp@12 (MAPI32.138)
625 * Find a property with a given property tag in a property array.
628 * lpProps [I] Property array to search
629 * cValues [I] Number of properties in lpProps
630 * ulPropTag [I] Property tag to find
633 * A pointer to the matching property, or NULL if none was found.
636 * if ulPropTag has a property type of PT_UNSPECIFIED, then only the property
637 * Ids need to match for a successful match to occur.
639 LPSPropValue WINAPI
PpropFindProp(LPSPropValue lpProps
, ULONG cValues
, ULONG ulPropTag
)
641 TRACE("(%p,%ld,%ld)\n", lpProps
, cValues
, ulPropTag
);
643 if (lpProps
&& cValues
)
646 for (i
= 0; i
< cValues
; i
++)
648 if (!FBadPropTag(lpProps
[i
].ulPropTag
) &&
649 (lpProps
[i
].ulPropTag
== ulPropTag
||
650 (PROP_TYPE(ulPropTag
) == PT_UNSPECIFIED
&&
651 PROP_ID(lpProps
[i
].ulPropTag
) == PROP_ID(ulPropTag
))))
658 /*************************************************************************
659 * FreePadrlist@4 (MAPI32.139)
661 * Free the memory used by an address book list.
664 * lpAddrs [I] Address book list to free
669 VOID WINAPI
FreePadrlist(LPADRLIST lpAddrs
)
671 TRACE("(%p)\n", lpAddrs
);
673 /* Structures are binary compatible; use the same implementation */
674 FreeProws((LPSRowSet
)lpAddrs
);
677 /*************************************************************************
678 * FreeProws@4 (MAPI32.140)
680 * Free the memory used by a row set.
683 * lpRowSet [I] Row set to free
688 VOID WINAPI
FreeProws(LPSRowSet lpRowSet
)
690 TRACE("(%p)\n", lpRowSet
);
696 for (i
= 0; i
< lpRowSet
->cRows
; i
++)
697 MAPIFreeBuffer(lpRowSet
->aRow
[i
].lpProps
);
699 MAPIFreeBuffer(lpRowSet
);
703 /*************************************************************************
704 * ScCountProps@12 (MAPI32.170)
706 * Validate and determine the length of an array of properties.
709 * iCount [I] Length of the lpProps array
710 * lpProps [I] Array of properties to validate/size
711 * pcBytes [O] If non-NULL, destination for the size of the property array
714 * Success: S_OK. If pcBytes is non-NULL, it contains the size of the
716 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid or validation
717 * of the property array fails.
719 SCODE WINAPI
ScCountProps(INT iCount
, LPSPropValue lpProps
, ULONG
*pcBytes
)
721 ULONG i
, ulCount
= iCount
, ulBytes
= 0;
723 TRACE("(%d,%p,%p)\n", iCount
, lpProps
, pcBytes
);
725 if (iCount
<= 0 || !lpProps
||
726 IsBadReadPtr(lpProps
, iCount
* sizeof(SPropValue
)))
727 return MAPI_E_INVALID_PARAMETER
;
729 for (i
= 0; i
< ulCount
; i
++)
731 ULONG ulPropSize
= 0;
733 if (FBadProp(&lpProps
[i
]) || lpProps
[i
].ulPropTag
== PROP_ID_NULL
||
734 lpProps
[i
].ulPropTag
== PROP_ID_INVALID
)
735 return MAPI_E_INVALID_PARAMETER
;
737 if (PROP_TYPE(lpProps
[i
].ulPropTag
) != PT_OBJECT
)
739 ulPropSize
= UlPropSize(&lpProps
[i
]);
741 return MAPI_E_INVALID_PARAMETER
;
744 switch (PROP_TYPE(lpProps
[i
].ulPropTag
))
758 ulPropSize
+= sizeof(SPropValue
);
761 ulPropSize
+= lpProps
[i
].Value
.MVszA
.cValues
* sizeof(char*) + sizeof(SPropValue
);
765 ulPropSize
+= lpProps
[i
].Value
.MVszA
.cValues
* sizeof(char*) + sizeof(SPropValue
);
768 ulPropSize
+= lpProps
[i
].Value
.MVbin
.cValues
* sizeof(SBinary
) + sizeof(SPropValue
);
771 ulPropSize
= sizeof(SPropValue
);
774 ulBytes
+= ulPropSize
;
782 /*************************************************************************
783 * ScCopyProps@16 (MAPI32.171)
785 * Copy an array of property values into a buffer suited for serialisation.
788 * cValues [I] Number of properties in lpProps
789 * lpProps [I] Property array to copy
790 * lpDst [O] Destination for the serialised data
791 * lpCount [O] If non-NULL, destination for the number of bytes of data written to lpDst
794 * Success: S_OK. lpDst contains the serialised data from lpProps.
795 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
798 * The resulting property value array is stored in a contiguous block starting at lpDst.
800 SCODE WINAPI
ScCopyProps(int cValues
, LPSPropValue lpProps
, LPVOID lpDst
, ULONG
*lpCount
)
802 LPSPropValue lpDest
= (LPSPropValue
)lpDst
;
803 char *lpDataDest
= (char *)(lpDest
+ cValues
);
807 TRACE("(%d,%p,%p,%p)\n", cValues
, lpProps
, lpDst
, lpCount
);
809 if (!lpProps
|| cValues
< 0 || !lpDest
)
810 return MAPI_E_INVALID_PARAMETER
;
812 memcpy(lpDst
, lpProps
, cValues
* sizeof(SPropValue
));
814 for (iter
= 0; iter
< cValues
; iter
++)
816 switch (PROP_TYPE(lpProps
->ulPropTag
))
819 lpDest
->Value
.lpguid
= (LPGUID
)lpDataDest
;
820 *lpDest
->Value
.lpguid
= *lpProps
->Value
.lpguid
;
821 lpDataDest
+= sizeof(GUID
);
824 ulLen
= lstrlenA(lpProps
->Value
.lpszA
) + 1u;
825 lpDest
->Value
.lpszA
= lpDataDest
;
826 memcpy(lpDest
->Value
.lpszA
, lpProps
->Value
.lpszA
, ulLen
);
830 ulLen
= (lstrlenW(lpProps
->Value
.lpszW
) + 1u) * sizeof(WCHAR
);
831 lpDest
->Value
.lpszW
= (LPWSTR
)lpDataDest
;
832 memcpy(lpDest
->Value
.lpszW
, lpProps
->Value
.lpszW
, ulLen
);
836 lpDest
->Value
.bin
.lpb
= (LPBYTE
)lpDataDest
;
837 memcpy(lpDest
->Value
.bin
.lpb
, lpProps
->Value
.bin
.lpb
, lpProps
->Value
.bin
.cb
);
838 lpDataDest
+= lpProps
->Value
.bin
.cb
;
841 if (lpProps
->ulPropTag
& MV_FLAG
)
843 lpDest
->Value
.MVi
.cValues
= lpProps
->Value
.MVi
.cValues
;
844 /* Note: Assignment uses lppszA but covers all cases by union aliasing */
845 lpDest
->Value
.MVszA
.lppszA
= (char**)lpDataDest
;
847 switch (PROP_TYPE(lpProps
->ulPropTag
))
851 lpDataDest
+= lpProps
->Value
.MVszA
.cValues
* sizeof(char *);
853 for (i
= 0; i
< lpProps
->Value
.MVszA
.cValues
; i
++)
855 ULONG ulStrLen
= lstrlenA(lpProps
->Value
.MVszA
.lppszA
[i
]) + 1u;
857 lpDest
->Value
.MVszA
.lppszA
[i
] = lpDataDest
;
858 memcpy(lpDataDest
, lpProps
->Value
.MVszA
.lppszA
[i
], ulStrLen
);
859 lpDataDest
+= ulStrLen
;
865 lpDataDest
+= lpProps
->Value
.MVszW
.cValues
* sizeof(WCHAR
*);
867 for (i
= 0; i
< lpProps
->Value
.MVszW
.cValues
; i
++)
869 ULONG ulStrLen
= (lstrlenW(lpProps
->Value
.MVszW
.lppszW
[i
]) + 1u) * sizeof(WCHAR
);
871 lpDest
->Value
.MVszW
.lppszW
[i
] = (LPWSTR
)lpDataDest
;
872 memcpy(lpDataDest
, lpProps
->Value
.MVszW
.lppszW
[i
], ulStrLen
);
873 lpDataDest
+= ulStrLen
;
879 lpDataDest
+= lpProps
->Value
.MVszW
.cValues
* sizeof(SBinary
);
881 for (i
= 0; i
< lpProps
->Value
.MVszW
.cValues
; i
++)
883 lpDest
->Value
.MVbin
.lpbin
[i
].cb
= lpProps
->Value
.MVbin
.lpbin
[i
].cb
;
884 lpDest
->Value
.MVbin
.lpbin
[i
].lpb
= (LPBYTE
)lpDataDest
;
885 memcpy(lpDataDest
, lpProps
->Value
.MVbin
.lpbin
[i
].lpb
, lpDest
->Value
.MVbin
.lpbin
[i
].cb
);
886 lpDataDest
+= lpDest
->Value
.MVbin
.lpbin
[i
].cb
;
891 /* No embedded pointers, just copy the data over */
892 ulLen
= UlPropSize(lpProps
);
893 memcpy(lpDest
->Value
.MVi
.lpi
, lpProps
->Value
.MVi
.lpi
, ulLen
);
904 *lpCount
= lpDataDest
- (char *)lpDst
;
909 /*************************************************************************
910 * ScRelocProps@20 (MAPI32.172)
912 * Relocate the pointers in an array of property values after it has been copied.
915 * cValues [I] Number of properties in lpProps
916 * lpProps [O] Property array to relocate the pointers in.
917 * lpOld [I] Position where the data was copied from
918 * lpNew [I] Position where the data was copied to
919 * lpCount [O] If non-NULL, destination for the number of bytes of data at lpDst
922 * Success: S_OK. Any pointers in lpProps are relocated.
923 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
926 * MSDN states that this function can be used for serialisation by passing
927 * NULL as either lpOld or lpNew, thus converting any pointers in lpProps
928 * between offsets and pointers. This does not work in native (it crashes),
929 * and cannot be made to work in Wine because the original interface design
930 * is deficient. The only use left for this function is to remap pointers
931 * in a contiguous property array that has been copied with memcpy() to
932 * another memory location.
934 SCODE WINAPI
ScRelocProps(int cValues
, LPSPropValue lpProps
, LPVOID lpOld
,
935 LPVOID lpNew
, ULONG
*lpCount
)
937 static const BOOL bBadPtr
= TRUE
; /* Windows bug - Assumes source is bad */
938 LPSPropValue lpDest
= lpProps
;
939 ULONG ulCount
= cValues
* sizeof(SPropValue
);
943 TRACE("(%d,%p,%p,%p,%p)\n", cValues
, lpProps
, lpOld
, lpNew
, lpCount
);
945 if (!lpProps
|| cValues
< 0 || !lpOld
|| !lpNew
)
946 return MAPI_E_INVALID_PARAMETER
;
948 /* The reason native doesn't work as MSDN states is that it assumes that
949 * the lpProps pointer contains valid pointers. This is obviously not
950 * true if the array is being read back from serialisation (the pointers
951 * are just offsets). Native can't actually work converting the pointers to
952 * offsets either, because it converts any array pointers to offsets then
953 * _dereferences the offset_ in order to convert the array elements!
955 * The code below would handle both cases except that the design of this
956 * function makes it impossible to know when the pointers in lpProps are
957 * valid. If both lpOld and lpNew are non-NULL, native reads the pointers
958 * after converting them, so we must do the same. It seems this
959 * functionality was never tested by MS.
962 #define RELOC_PTR(p) (((char*)(p)) - (char*)lpOld + (char*)lpNew)
964 for (iter
= 0; iter
< cValues
; iter
++)
966 switch (PROP_TYPE(lpDest
->ulPropTag
))
969 lpDest
->Value
.lpguid
= (LPGUID
)RELOC_PTR(lpDest
->Value
.lpguid
);
970 ulCount
+= sizeof(GUID
);
973 ulLen
= bBadPtr
? 0 : lstrlenA(lpDest
->Value
.lpszA
) + 1u;
974 lpDest
->Value
.lpszA
= RELOC_PTR(lpDest
->Value
.lpszA
);
976 ulLen
= lstrlenA(lpDest
->Value
.lpszA
) + 1u;
980 ulLen
= bBadPtr
? 0 : (lstrlenW(lpDest
->Value
.lpszW
) + 1u) * sizeof(WCHAR
);
981 lpDest
->Value
.lpszW
= (LPWSTR
)RELOC_PTR(lpDest
->Value
.lpszW
);
983 ulLen
= (lstrlenW(lpDest
->Value
.lpszW
) + 1u) * sizeof(WCHAR
);
987 lpDest
->Value
.bin
.lpb
= (LPBYTE
)RELOC_PTR(lpDest
->Value
.bin
.lpb
);
988 ulCount
+= lpDest
->Value
.bin
.cb
;
991 if (lpDest
->ulPropTag
& MV_FLAG
)
993 /* Since we have to access the array elements, don't map the
994 * array unless it is invalid (otherwise, map it at the end)
997 lpDest
->Value
.MVszA
.lppszA
= (LPSTR
*)RELOC_PTR(lpDest
->Value
.MVszA
.lppszA
);
999 switch (PROP_TYPE(lpProps
->ulPropTag
))
1003 ulCount
+= lpDest
->Value
.MVszA
.cValues
* sizeof(char *);
1005 for (i
= 0; i
< lpDest
->Value
.MVszA
.cValues
; i
++)
1007 ULONG ulStrLen
= bBadPtr
? 0 : lstrlenA(lpDest
->Value
.MVszA
.lppszA
[i
]) + 1u;
1009 lpDest
->Value
.MVszA
.lppszA
[i
] = RELOC_PTR(lpDest
->Value
.MVszA
.lppszA
[i
]);
1011 ulStrLen
= lstrlenA(lpDest
->Value
.MVszA
.lppszA
[i
]) + 1u;
1012 ulCount
+= ulStrLen
;
1018 ulCount
+= lpDest
->Value
.MVszW
.cValues
* sizeof(WCHAR
*);
1020 for (i
= 0; i
< lpDest
->Value
.MVszW
.cValues
; i
++)
1022 ULONG ulStrLen
= bBadPtr
? 0 : (lstrlenW(lpDest
->Value
.MVszW
.lppszW
[i
]) + 1u) * sizeof(WCHAR
);
1024 lpDest
->Value
.MVszW
.lppszW
[i
] = (LPWSTR
)RELOC_PTR(lpDest
->Value
.MVszW
.lppszW
[i
]);
1026 ulStrLen
= (lstrlenW(lpDest
->Value
.MVszW
.lppszW
[i
]) + 1u) * sizeof(WCHAR
);
1027 ulCount
+= ulStrLen
;
1033 ulCount
+= lpDest
->Value
.MVszW
.cValues
* sizeof(SBinary
);
1035 for (i
= 0; i
< lpDest
->Value
.MVszW
.cValues
; i
++)
1037 lpDest
->Value
.MVbin
.lpbin
[i
].lpb
= (LPBYTE
)RELOC_PTR(lpDest
->Value
.MVbin
.lpbin
[i
].lpb
);
1038 ulCount
+= lpDest
->Value
.MVbin
.lpbin
[i
].cb
;
1043 ulCount
+= UlPropSize(lpDest
);
1047 lpDest
->Value
.MVszA
.lppszA
= (LPSTR
*)RELOC_PTR(lpDest
->Value
.MVszA
.lppszA
);
1059 /*************************************************************************
1060 * LpValFindProp@12 (MAPI32.173)
1062 * Find a property with a given property id in a property array.
1065 * ulPropTag [I] Property tag containing property id to find
1066 * cValues [I] Number of properties in lpProps
1067 * lpProps [I] Property array to search
1070 * A pointer to the matching property, or NULL if none was found.
1073 * This function matches only on the property id and does not care if the
1074 * property types differ.
1076 LPSPropValue WINAPI
LpValFindProp(ULONG ulPropTag
, ULONG cValues
, LPSPropValue lpProps
)
1078 TRACE("(%ld,%ld,%p)\n", ulPropTag
, cValues
, lpProps
);
1080 if (lpProps
&& cValues
)
1083 for (i
= 0; i
< cValues
; i
++)
1085 if (PROP_ID(ulPropTag
) == PROP_ID(lpProps
[i
].ulPropTag
))
1092 /*************************************************************************
1093 * ScDupPropset@16 (MAPI32.174)
1095 * Duplicate a property value array into a contiguous block of memory.
1098 * cValues [I] Number of properties in lpProps
1099 * lpProps [I] Property array to duplicate
1100 * lpAlloc [I] Memory allocation function, use MAPIAllocateBuffer()
1101 * lpNewProp [O] Destination for the newly duplicated property value array
1104 * Success: S_OK. *lpNewProp contains the duplicated array.
1105 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid,
1106 * MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails.
1108 SCODE WINAPI
ScDupPropset(int cValues
, LPSPropValue lpProps
,
1109 LPALLOCATEBUFFER lpAlloc
, LPSPropValue
*lpNewProp
)
1114 TRACE("(%d,%p,%p,%p)\n", cValues
, lpProps
, lpAlloc
, lpNewProp
);
1116 sc
= ScCountProps(cValues
, lpProps
, &ulCount
);
1119 sc
= lpAlloc(ulCount
, (LPVOID
*)lpNewProp
);
1121 sc
= ScCopyProps(cValues
, lpProps
, *lpNewProp
, &ulCount
);
1126 /*************************************************************************
1127 * FBadRglpszA@8 (MAPI32.175)
1129 * Determine if an array of strings is invalid
1132 * lppszStrs [I] Array of strings to check
1133 * ulCount [I] Number of strings in lppszStrs
1136 * TRUE, if lppszStrs is invalid, FALSE otherwise.
1138 BOOL WINAPI
FBadRglpszA(LPSTR
*lppszStrs
, ULONG ulCount
)
1142 TRACE("(%p,%ld)\n", lppszStrs
, ulCount
);
1147 if (!lppszStrs
|| IsBadReadPtr(lppszStrs
, ulCount
* sizeof(LPWSTR
)))
1150 for (i
= 0; i
< ulCount
; i
++)
1152 if (!lppszStrs
[i
] || IsBadStringPtrA(lppszStrs
[i
], -1))
1158 /*************************************************************************
1159 * FBadRglpszW@8 (MAPI32.176)
1163 BOOL WINAPI
FBadRglpszW(LPWSTR
*lppszStrs
, ULONG ulCount
)
1167 TRACE("(%p,%ld)\n", lppszStrs
, ulCount
);
1172 if (!lppszStrs
|| IsBadReadPtr(lppszStrs
, ulCount
* sizeof(LPWSTR
)))
1175 for (i
= 0; i
< ulCount
; i
++)
1177 if (!lppszStrs
[i
] || IsBadStringPtrW(lppszStrs
[i
], -1))
1183 /*************************************************************************
1184 * FBadRowSet@4 (MAPI32.177)
1186 * Determine if a row is invalid
1189 * lpRow [I] Row to check
1192 * TRUE, if lpRow is invalid, FALSE otherwise.
1194 BOOL WINAPI
FBadRowSet(LPSRowSet lpRowSet
)
1197 TRACE("(%p)\n", lpRowSet
);
1199 if (!lpRowSet
|| IsBadReadPtr(lpRowSet
, CbSRowSet(lpRowSet
)))
1202 for (i
= 0; i
< lpRowSet
->cRows
; i
++)
1204 if (FBadRow(&lpRowSet
->aRow
[i
]))
1210 /*************************************************************************
1211 * FBadPropTag@4 (MAPI32.179)
1213 * Determine if a property tag is invalid
1216 * ulPropTag [I] Property tag to check
1219 * TRUE, if ulPropTag is invalid, FALSE otherwise.
1221 ULONG WINAPI
FBadPropTag(ULONG ulPropTag
)
1223 TRACE("(0x%08lx)\n", ulPropTag
);
1225 switch (ulPropTag
& (~MV_FLAG
& PROP_TYPE_MASK
))
1227 case PT_UNSPECIFIED
:
1249 /*************************************************************************
1250 * FBadRow@4 (MAPI32.180)
1252 * Determine if a row is invalid
1255 * lpRow [I] Row to check
1258 * TRUE, if lpRow is invalid, FALSE otherwise.
1260 ULONG WINAPI
FBadRow(LPSRow lpRow
)
1263 TRACE("(%p)\n", lpRow
);
1265 if (!lpRow
|| IsBadReadPtr(lpRow
, sizeof(SRow
)) || !lpRow
->lpProps
||
1266 IsBadReadPtr(lpRow
->lpProps
, lpRow
->cValues
* sizeof(SPropValue
)))
1269 for (i
= 0; i
< lpRow
->cValues
; i
++)
1271 if (FBadProp(&lpRow
->lpProps
[i
]))
1277 /*************************************************************************
1278 * FBadProp@4 (MAPI32.181)
1280 * Determine if a property is invalid
1283 * lpProp [I] Property to check
1286 * TRUE, if lpProp is invalid, FALSE otherwise.
1288 ULONG WINAPI
FBadProp(LPSPropValue lpProp
)
1290 if (!lpProp
|| IsBadReadPtr(lpProp
, sizeof(SPropValue
)) ||
1291 FBadPropTag(lpProp
->ulPropTag
))
1294 switch (PROP_TYPE(lpProp
->ulPropTag
))
1296 /* Single value properties containing pointers */
1298 if (!lpProp
->Value
.lpszA
|| IsBadStringPtrA(lpProp
->Value
.lpszA
, -1))
1302 if (!lpProp
->Value
.lpszW
|| IsBadStringPtrW(lpProp
->Value
.lpszW
, -1))
1306 if (IsBadReadPtr(lpProp
->Value
.bin
.lpb
, lpProp
->Value
.bin
.cb
))
1310 if (IsBadReadPtr(lpProp
->Value
.lpguid
, sizeof(GUID
)))
1314 /* Multiple value properties (arrays) containing no pointers */
1316 return PROP_BadArray(lpProp
, sizeof(SHORT
));
1318 return PROP_BadArray(lpProp
, sizeof(LONG
));
1319 case PT_MV_LONGLONG
:
1320 return PROP_BadArray(lpProp
, sizeof(LONG64
));
1322 return PROP_BadArray(lpProp
, sizeof(float));
1324 return PROP_BadArray(lpProp
, sizeof(FILETIME
));
1327 return PROP_BadArray(lpProp
, sizeof(double));
1328 case PT_MV_CURRENCY
:
1329 return PROP_BadArray(lpProp
, sizeof(CY
));
1331 return PROP_BadArray(lpProp
, sizeof(GUID
));
1333 /* Multiple value properties containing pointers */
1335 return FBadRglpszA(lpProp
->Value
.MVszA
.lppszA
,
1336 lpProp
->Value
.MVszA
.cValues
);
1338 return FBadRglpszW(lpProp
->Value
.MVszW
.lppszW
,
1339 lpProp
->Value
.MVszW
.cValues
);
1341 return FBadEntryList(&lpProp
->Value
.MVbin
);
1346 /*************************************************************************
1347 * FBadColumnSet@4 (MAPI32.182)
1349 * Determine if an array of property tags is invalid
1352 * lpCols [I] Property tag array to check
1355 * TRUE, if lpCols is invalid, FALSE otherwise.
1357 ULONG WINAPI
FBadColumnSet(LPSPropTagArray lpCols
)
1359 ULONG ulRet
= FALSE
, i
;
1361 TRACE("(%p)\n", lpCols
);
1363 if (!lpCols
|| IsBadReadPtr(lpCols
, CbSPropTagArray(lpCols
)))
1367 for (i
= 0; i
< lpCols
->cValues
; i
++)
1369 if ((lpCols
->aulPropTag
[i
] & PROP_TYPE_MASK
) == PT_ERROR
||
1370 FBadPropTag(lpCols
->aulPropTag
[i
]))
1377 TRACE("Returning %s\n", ulRet
? "TRUE" : "FALSE");
1382 /**************************************************************************
1383 * IPropData {MAPI32}
1385 * A default Mapi interface to provide manipulation of object properties.
1388 * This object provides a default interface suitable in some cases as an
1389 * implementation of the IMAPIProp interface (which has no default
1390 * implementation). In addition to the IMAPIProp() methods inherited, this
1391 * interface allows read/write control over access to the object and its
1392 * individual properties.
1394 * To obtain the default implementation of this interface from Mapi, call
1400 /* A single property in a property data collection */
1404 ULONG ulAccess
; /* The property value access level */
1405 LPSPropValue value
; /* The property value */
1406 } IPropDataItem
, *LPIPropDataItem
;
1408 /* The main property data collection structure */
1411 IPropData IPropData_iface
;
1412 LONG lRef
; /* Reference count */
1413 ALLOCATEBUFFER
*lpAlloc
; /* Memory allocation routine */
1414 ALLOCATEMORE
*lpMore
; /* Linked memory allocation routine */
1415 FREEBUFFER
*lpFree
; /* Memory free routine */
1416 ULONG ulObjAccess
; /* Object access level */
1417 ULONG ulNumValues
; /* Number of items in values list */
1418 struct list values
; /* List of property values */
1419 CRITICAL_SECTION cs
; /* Lock for thread safety */
1422 static inline IPropDataImpl
*impl_from_IPropData(IPropData
*iface
)
1424 return CONTAINING_RECORD(iface
, IPropDataImpl
, IPropData_iface
);
1427 /* Internal - Get a property value, assumes lock is held */
1428 static IPropDataItem
*IMAPIPROP_GetValue(IPropDataImpl
*This
, ULONG ulPropTag
)
1430 struct list
*cursor
;
1432 LIST_FOR_EACH(cursor
, &This
->values
)
1434 LPIPropDataItem current
= LIST_ENTRY(cursor
, IPropDataItem
, entry
);
1435 /* Note that property types don't have to match, just Id's */
1436 if (PROP_ID(current
->value
->ulPropTag
) == PROP_ID(ulPropTag
))
1442 /* Internal - Add a new property value, assumes lock is held */
1443 static IPropDataItem
*IMAPIPROP_AddValue(IPropDataImpl
*This
,
1444 LPSPropValue lpProp
)
1447 LPIPropDataItem lpNew
;
1450 hRet
= This
->lpAlloc(sizeof(IPropDataItem
), &lpMem
);
1452 if (SUCCEEDED(hRet
))
1455 lpNew
->ulAccess
= IPROP_READWRITE
;
1457 /* Allocate the value separately so we can update it easily */
1459 hRet
= This
->lpAlloc(sizeof(SPropValue
), &lpMem
);
1460 if (SUCCEEDED(hRet
))
1462 lpNew
->value
= lpMem
;
1464 hRet
= PropCopyMore(lpNew
->value
, lpProp
, This
->lpMore
, lpMem
);
1465 if (SUCCEEDED(hRet
))
1467 list_add_tail(&This
->values
, &lpNew
->entry
);
1468 This
->ulNumValues
++;
1471 This
->lpFree(lpNew
->value
);
1473 This
->lpFree(lpNew
);
1478 /* Internal - Lock an IPropData object */
1479 static inline void IMAPIPROP_Lock(IPropDataImpl
*This
)
1481 EnterCriticalSection(&This
->cs
);
1484 /* Internal - Unlock an IPropData object */
1485 static inline void IMAPIPROP_Unlock(IPropDataImpl
*This
)
1487 LeaveCriticalSection(&This
->cs
);
1490 /* This one seems to be missing from mapidefs.h */
1491 #define CbNewSPropProblemArray(c) \
1492 (offsetof(SPropProblemArray,aProblem)+(c)*sizeof(SPropProblem))
1494 /**************************************************************************
1495 * IPropData_QueryInterface {MAPI32}
1497 * Inherited method from the IUnknown Interface.
1498 * See IUnknown_QueryInterface.
1500 static HRESULT WINAPI
IPropData_fnQueryInterface(LPPROPDATA iface
, REFIID riid
, LPVOID
*ppvObj
)
1502 IPropDataImpl
*This
= impl_from_IPropData(iface
);
1504 TRACE("(%p,%s,%p)\n", This
, debugstr_guid(riid
), ppvObj
);
1506 if (!ppvObj
|| !riid
)
1507 return MAPI_E_INVALID_PARAMETER
;
1511 if(IsEqualIID(riid
, &IID_IUnknown
) ||
1512 IsEqualIID(riid
, &IID_IMAPIProp
) ||
1513 IsEqualIID(riid
, &IID_IMAPIPropData
))
1515 *ppvObj
= &This
->IPropData_iface
;
1516 IPropData_AddRef(iface
);
1517 TRACE("returning %p\n", *ppvObj
);
1521 TRACE("returning E_NOINTERFACE\n");
1522 return MAPI_E_INTERFACE_NOT_SUPPORTED
;
1525 /**************************************************************************
1526 * IPropData_AddRef {MAPI32}
1528 * Inherited method from the IUnknown Interface.
1529 * See IUnknown_AddRef.
1531 static ULONG WINAPI
IPropData_fnAddRef(LPPROPDATA iface
)
1533 IPropDataImpl
*This
= impl_from_IPropData(iface
);
1535 TRACE("(%p)->(count before=%lu)\n", This
, This
->lRef
);
1537 return InterlockedIncrement(&This
->lRef
);
1540 /**************************************************************************
1541 * IPropData_Release {MAPI32}
1543 * Inherited method from the IUnknown Interface.
1544 * See IUnknown_Release.
1546 static ULONG WINAPI
IPropData_fnRelease(LPPROPDATA iface
)
1548 IPropDataImpl
*This
= impl_from_IPropData(iface
);
1551 TRACE("(%p)->(count before=%lu)\n", This
, This
->lRef
);
1553 lRef
= InterlockedDecrement(&This
->lRef
);
1556 TRACE("Destroying IPropData (%p)\n",This
);
1558 /* Note: No need to lock, since no other thread is referencing iface */
1559 while (!list_empty(&This
->values
))
1561 struct list
*head
= list_head(&This
->values
);
1562 LPIPropDataItem current
= LIST_ENTRY(head
, IPropDataItem
, entry
);
1564 This
->lpFree(current
->value
);
1565 This
->lpFree(current
);
1567 This
->cs
.DebugInfo
->Spare
[0] = 0;
1568 DeleteCriticalSection(&This
->cs
);
1574 /**************************************************************************
1575 * IPropData_GetLastError {MAPI32}
1577 * Get information about the last error that occurred in an IMAPIProp object.
1580 * iface [I] IMAPIProp object that experienced the error
1581 * hRes [I] Result of the call that returned an error
1582 * ulFlags [I] 0=return Ascii strings, MAPI_UNICODE=return Unicode strings
1583 * lppError [O] Destination for detailed error information
1586 * Success: S_OK. *lppError contains details about the last error.
1587 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid,
1588 * MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails.
1591 * - If this function succeeds, the returned information in *lppError must be
1592 * freed using MAPIFreeBuffer() once the caller is finished with it.
1593 * - It is possible for this function to succeed and set *lppError to NULL,
1594 * if there is no further information to report about hRes.
1596 static HRESULT WINAPI
IPropData_fnGetLastError(LPPROPDATA iface
, HRESULT hRes
, ULONG ulFlags
,
1597 LPMAPIERROR
*lppError
)
1599 TRACE("(%p,0x%08lX,0x%08lX,%p)\n", iface
, hRes
, ulFlags
, lppError
);
1601 if (!lppError
|| SUCCEEDED(hRes
) || (ulFlags
& ~MAPI_UNICODE
))
1602 return MAPI_E_INVALID_PARAMETER
;
1608 /**************************************************************************
1609 * IPropData_SaveChanges {MAPI32}
1611 * Update any changes made to a transactional IMAPIProp object.
1614 * iface [I] IMAPIProp object to update
1615 * ulFlags [I] Flags controlling the update.
1618 * Success: S_OK. Any outstanding changes are committed to the object.
1619 * Failure: An HRESULT error code describing the error.
1621 static HRESULT WINAPI
IPropData_fnSaveChanges(LPPROPDATA iface
, ULONG ulFlags
)
1623 TRACE("(%p,0x%08lX)\n", iface
, ulFlags
);
1625 /* Since this object is not transacted we do not need to implement this */
1626 /* FIXME: Should we set the access levels to clean? */
1630 /**************************************************************************
1631 * IPropData_GetProps {MAPI32}
1633 * Get property values from an IMAPIProp object.
1636 * iface [I] IMAPIProp object to get the property values from
1637 * lpTags [I] Property tags of property values to be retrieved
1638 * ulFlags [I] Return 0=Ascii MAPI_UNICODE=Unicode strings for
1640 * lpCount [O] Destination for number of properties returned
1641 * lppProps [O] Destination for returned property values
1644 * Success: S_OK. *lppProps and *lpCount are updated.
1645 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
1646 * MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails, or
1647 * MAPI_W_ERRORS_RETURNED if not all properties were retrieved
1650 * - If MAPI_W_ERRORS_RETURNED is returned, any properties that could not be
1651 * retrieved from iface are present in lppProps with their type
1652 * changed to PT_ERROR and Id unchanged.
1654 static HRESULT WINAPI
IPropData_fnGetProps(LPPROPDATA iface
, LPSPropTagArray lpTags
, ULONG ulFlags
,
1655 ULONG
*lpCount
, LPSPropValue
*lppProps
)
1657 IPropDataImpl
*This
= impl_from_IPropData(iface
);
1659 HRESULT hRet
= S_OK
;
1661 TRACE("(%p,%p,0x%08lx,%p,%p) stub\n", iface
, lpTags
, ulFlags
,
1664 if (!iface
|| ulFlags
& ~MAPI_UNICODE
|| !lpTags
|| *lpCount
|| !lppProps
)
1665 return MAPI_E_INVALID_PARAMETER
;
1667 FIXME("semi-stub, flags not supported\n");
1669 *lpCount
= lpTags
->cValues
;
1674 hRet
= MAPIAllocateBuffer(*lpCount
* sizeof(SPropValue
), (LPVOID
*)lppProps
);
1678 IMAPIPROP_Lock(This
);
1680 for (i
= 0; i
< lpTags
->cValues
; i
++)
1682 HRESULT hRetTmp
= E_INVALIDARG
;
1683 LPIPropDataItem item
;
1685 item
= IMAPIPROP_GetValue(This
, lpTags
->aulPropTag
[i
]);
1688 hRetTmp
= PropCopyMore(&(*lppProps
)[i
], item
->value
,
1689 This
->lpMore
, *lppProps
);
1690 if (FAILED(hRetTmp
))
1692 hRet
= MAPI_W_ERRORS_RETURNED
;
1693 (*lppProps
)[i
].ulPropTag
=
1694 CHANGE_PROP_TYPE(lpTags
->aulPropTag
[i
], PT_ERROR
);
1698 IMAPIPROP_Unlock(This
);
1703 /**************************************************************************
1704 * MAPIProp_GetPropList {MAPI32}
1706 * Get the list of property tags for all values in an IMAPIProp object.
1709 * iface [I] IMAPIProp object to get the property tag list from
1710 * ulFlags [I] Return 0=Ascii MAPI_UNICODE=Unicode strings for
1712 * lppTags [O] Destination for the retrieved property tag list
1715 * Success: S_OK. *lppTags contains the tags for all available properties.
1716 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
1717 * MAPI_E_BAD_CHARWIDTH, if Ascii or Unicode strings are requested
1718 * and that type of string is not supported.
1720 static HRESULT WINAPI
IPropData_fnGetPropList(LPPROPDATA iface
, ULONG ulFlags
,
1721 LPSPropTagArray
*lppTags
)
1723 IPropDataImpl
*This
= impl_from_IPropData(iface
);
1727 TRACE("(%p,0x%08lx,%p) stub\n", iface
, ulFlags
, lppTags
);
1729 if (!iface
|| ulFlags
& ~MAPI_UNICODE
|| !lppTags
)
1730 return MAPI_E_INVALID_PARAMETER
;
1732 FIXME("semi-stub, flags not supported\n");
1736 IMAPIPROP_Lock(This
);
1738 hRet
= MAPIAllocateBuffer(CbNewSPropTagArray(This
->ulNumValues
),
1740 if (SUCCEEDED(hRet
))
1742 struct list
*cursor
;
1745 LIST_FOR_EACH(cursor
, &This
->values
)
1747 LPIPropDataItem current
= LIST_ENTRY(cursor
, IPropDataItem
, entry
);
1748 (*lppTags
)->aulPropTag
[i
] = current
->value
->ulPropTag
;
1751 (*lppTags
)->cValues
= This
->ulNumValues
;
1754 IMAPIPROP_Unlock(This
);
1758 /**************************************************************************
1759 * IPropData_OpenProperty {MAPI32}
1761 * Not documented at this time.
1764 * An HRESULT success/failure code.
1766 static HRESULT WINAPI
IPropData_fnOpenProperty(LPPROPDATA iface
, ULONG ulPropTag
, LPCIID iid
,
1767 ULONG ulOpts
, ULONG ulFlags
, LPUNKNOWN
*lpUnk
)
1769 FIXME("(%p,%lu,%s,%lu,0x%08lx,%p) stub\n", iface
, ulPropTag
,
1770 debugstr_guid(iid
), ulOpts
, ulFlags
, lpUnk
);
1771 return MAPI_E_NO_SUPPORT
;
1775 /**************************************************************************
1776 * IPropData_SetProps {MAPI32}
1778 * Add or edit the property values in an IMAPIProp object.
1781 * iface [I] IMAPIProp object to get the property tag list from
1782 * ulValues [I] Number of properties in lpProps
1783 * lpProps [I] Property values to set
1784 * lppProbs [O] Optional destination for any problems that occurred
1787 * Success: S_OK. The properties in lpProps are added to iface if they don't
1788 * exist, or changed to the values in lpProps if they do
1789 * Failure: An HRESULT error code describing the error
1791 static HRESULT WINAPI
IPropData_fnSetProps(LPPROPDATA iface
, ULONG ulValues
, LPSPropValue lpProps
,
1792 LPSPropProblemArray
*lppProbs
)
1794 IPropDataImpl
*This
= impl_from_IPropData(iface
);
1795 HRESULT hRet
= S_OK
;
1798 TRACE("(%p,%lu,%p,%p)\n", iface
, ulValues
, lpProps
, lppProbs
);
1800 if (!iface
|| !lpProps
)
1801 return MAPI_E_INVALID_PARAMETER
;
1803 for (i
= 0; i
< ulValues
; i
++)
1805 if (FBadProp(&lpProps
[i
]) ||
1806 PROP_TYPE(lpProps
[i
].ulPropTag
) == PT_OBJECT
||
1807 PROP_TYPE(lpProps
[i
].ulPropTag
) == PT_NULL
)
1808 return MAPI_E_INVALID_PARAMETER
;
1811 IMAPIPROP_Lock(This
);
1813 /* FIXME: Under what circumstances is lpProbs created? */
1814 for (i
= 0; i
< ulValues
; i
++)
1816 LPIPropDataItem item
= IMAPIPROP_GetValue(This
, lpProps
[i
].ulPropTag
);
1821 LPVOID lpMem
= NULL
;
1823 /* Found, so update the existing value */
1824 if (item
->value
->ulPropTag
!= lpProps
[i
].ulPropTag
)
1825 FIXME("semi-stub, overwriting type (not coercing)\n");
1827 hRetTmp
= This
->lpAlloc(sizeof(SPropValue
), &lpMem
);
1828 if (SUCCEEDED(hRetTmp
))
1830 hRetTmp
= PropCopyMore(lpMem
, &lpProps
[i
], This
->lpMore
, lpMem
);
1831 if (SUCCEEDED(hRetTmp
))
1833 This
->lpFree(item
->value
);
1834 item
->value
= lpMem
;
1837 This
->lpFree(lpMem
);
1844 if (!IMAPIPROP_AddValue(This
, &lpProps
[i
]))
1845 hRet
= MAPI_E_NOT_ENOUGH_MEMORY
;
1849 IMAPIPROP_Unlock(This
);
1853 /**************************************************************************
1854 * IPropData_DeleteProps {MAPI32}
1856 * Delete one or more property values from an IMAPIProp object.
1859 * iface [I] IMAPIProp object to remove property values from.
1860 * lpTags [I] Collection of property Id's to remove from iface.
1861 * lppProbs [O] Destination for problems encountered, if any.
1864 * Success: S_OK. Any properties in iface matching property Id's in lpTags have
1865 * been deleted. If lppProbs is non-NULL it contains details of any
1866 * errors that occurred.
1867 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
1868 * E_ACCESSDENIED, if this object was created using CreateIProp() and
1869 * a subsequent call to IPropData_SetObjAccess() was made specifying
1870 * IPROP_READONLY as the access type.
1873 * - lppProbs will not be populated for cases where a property Id is present
1874 * in lpTags but not in iface.
1875 * - lppProbs should be deleted with MAPIFreeBuffer() if returned.
1877 static HRESULT WINAPI
IPropData_fnDeleteProps(LPPROPDATA iface
, LPSPropTagArray lpTags
,
1878 LPSPropProblemArray
*lppProbs
)
1880 IPropDataImpl
*This
= impl_from_IPropData(iface
);
1881 ULONG i
, numProbs
= 0;
1882 HRESULT hRet
= S_OK
;
1884 TRACE("(%p,%p,%p)\n", iface
, lpTags
, lppProbs
);
1886 if (!iface
|| !lpTags
)
1887 return MAPI_E_INVALID_PARAMETER
;
1892 for (i
= 0; i
< lpTags
->cValues
; i
++)
1894 if (FBadPropTag(lpTags
->aulPropTag
[i
]) ||
1895 PROP_TYPE(lpTags
->aulPropTag
[i
]) == PT_OBJECT
||
1896 PROP_TYPE(lpTags
->aulPropTag
[i
]) == PT_NULL
)
1897 return MAPI_E_INVALID_PARAMETER
;
1900 IMAPIPROP_Lock(This
);
1902 if (This
->ulObjAccess
!= IPROP_READWRITE
)
1904 IMAPIPROP_Unlock(This
);
1905 return E_ACCESSDENIED
;
1908 for (i
= 0; i
< lpTags
->cValues
; i
++)
1910 LPIPropDataItem item
= IMAPIPROP_GetValue(This
, lpTags
->aulPropTag
[i
]);
1914 if (item
->ulAccess
& IPROP_READWRITE
)
1916 /* Everything hunky-dory, remove the item */
1917 list_remove(&item
->entry
);
1918 This
->lpFree(item
->value
); /* Also frees value pointers */
1920 This
->ulNumValues
--;
1924 /* Can't write the value. Create/populate problems array */
1927 /* Create problems array */
1928 ULONG ulSize
= CbNewSPropProblemArray(lpTags
->cValues
- i
);
1929 HRESULT hRetTmp
= MAPIAllocateBuffer(ulSize
, (LPVOID
*)lppProbs
);
1930 if (FAILED(hRetTmp
))
1935 LPSPropProblem lpProb
= &(*lppProbs
)->aProblem
[numProbs
];
1936 lpProb
->ulIndex
= i
;
1937 lpProb
->ulPropTag
= lpTags
->aulPropTag
[i
];
1938 lpProb
->scode
= E_ACCESSDENIED
;
1944 if (lppProbs
&& *lppProbs
)
1945 (*lppProbs
)->cProblem
= numProbs
;
1947 IMAPIPROP_Unlock(This
);
1952 /**************************************************************************
1953 * IPropData_CopyTo {MAPI32}
1955 * Not documented at this time.
1958 * An HRESULT success/failure code.
1960 static HRESULT WINAPI
IPropData_fnCopyTo(LPPROPDATA iface
, ULONG niids
, LPCIID lpiidExcl
,
1961 LPSPropTagArray lpPropsExcl
, ULONG ulParam
,
1962 LPMAPIPROGRESS lpIProgress
, LPCIID lpIfaceIid
,
1963 LPVOID lpDstObj
, ULONG ulFlags
,
1964 LPSPropProblemArray
*lppProbs
)
1966 FIXME("(%p,%lu,%p,%p,%lx,%p,%s,%p,0x%08lX,%p) stub\n", iface
, niids
,
1967 lpiidExcl
, lpPropsExcl
, ulParam
, lpIProgress
,
1968 debugstr_guid(lpIfaceIid
), lpDstObj
, ulFlags
, lppProbs
);
1969 return MAPI_E_NO_SUPPORT
;
1972 /**************************************************************************
1973 * IPropData_CopyProps {MAPI32}
1975 * Not documented at this time.
1978 * An HRESULT success/failure code.
1980 static HRESULT WINAPI
IPropData_fnCopyProps(LPPROPDATA iface
, LPSPropTagArray lpInclProps
,
1981 ULONG ulParam
, LPMAPIPROGRESS lpIProgress
,
1982 LPCIID lpIface
, LPVOID lpDstObj
, ULONG ulFlags
,
1983 LPSPropProblemArray
*lppProbs
)
1985 FIXME("(%p,%p,%lx,%p,%s,%p,0x%08lX,%p) stub\n", iface
, lpInclProps
,
1986 ulParam
, lpIProgress
, debugstr_guid(lpIface
), lpDstObj
, ulFlags
,
1988 return MAPI_E_NO_SUPPORT
;
1991 /**************************************************************************
1992 * IPropData_GetNamesFromIDs {MAPI32}
1994 * Get the names of properties from their identifiers.
1997 * iface [I] IMAPIProp object to operate on
1998 * lppPropTags [I/O] Property identifiers to get the names for, or NULL to
2000 * iid [I] Property set identifier, or NULL
2001 * ulFlags [I] MAPI_NO_IDS=Don't return numeric named properties,
2002 * or MAPI_NO_STRINGS=Don't return strings
2003 * lpCount [O] Destination for number of properties returned
2004 * lpppNames [O] Destination for returned names
2007 * Success: S_OK. *lppPropTags and lpppNames contain the returned
2009 * Failure: MAPI_E_NO_SUPPORT, if the object does not support named properties,
2010 * MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails, or
2011 * MAPI_W_ERRORS_RETURNED if not all properties were retrieved
2014 static HRESULT WINAPI
IPropData_fnGetNamesFromIDs(LPPROPDATA iface
, LPSPropTagArray
*lppPropTags
,
2015 LPGUID iid
, ULONG ulFlags
, ULONG
*lpCount
,
2016 LPMAPINAMEID
**lpppNames
)
2018 FIXME("(%p,%p,%s,0x%08lX,%p,%p) stub\n", iface
, lppPropTags
,
2019 debugstr_guid(iid
), ulFlags
, lpCount
, lpppNames
);
2020 return MAPI_E_NO_SUPPORT
;
2023 /**************************************************************************
2024 * IPropData_GetIDsFromNames {MAPI32}
2026 * Get property identifiers associated with one or more named properties.
2029 * iface [I] IMAPIProp object to operate on
2030 * ulNames [I] Number of names in lppNames
2031 * lppNames [I] Names to query or create, or NULL to query all names
2032 * ulFlags [I] Pass MAPI_CREATE to create new named properties
2033 * lppPropTags [O] Destination for queried or created property identifiers
2036 * Success: S_OK. *lppPropTags contains the property tags created or requested.
2037 * Failure: MAPI_E_NO_SUPPORT, if the object does not support named properties,
2038 * MAPI_E_TOO_BIG, if the object cannot process the number of
2039 * properties involved.
2040 * MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails, or
2041 * MAPI_W_ERRORS_RETURNED if not all properties were retrieved
2044 static HRESULT WINAPI
IPropData_fnGetIDsFromNames(LPPROPDATA iface
, ULONG ulNames
,
2045 LPMAPINAMEID
*lppNames
, ULONG ulFlags
,
2046 LPSPropTagArray
*lppPropTags
)
2048 FIXME("(%p,%ld,%p,0x%08lX,%p) stub\n",
2049 iface
, ulNames
, lppNames
, ulFlags
, lppPropTags
);
2050 return MAPI_E_NO_SUPPORT
;
2053 /**************************************************************************
2054 * IPropData_HrSetObjAccess {MAPI32}
2056 * Set the access level of an IPropData object.
2059 * iface [I] IPropData object to set the access on
2060 * ulAccess [I] Either IPROP_READONLY or IPROP_READWRITE for read or
2061 * read/write access respectively.
2064 * Success: S_OK. The objects access level is changed.
2065 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
2067 static HRESULT WINAPI
2068 IPropData_fnHrSetObjAccess(LPPROPDATA iface
, ULONG ulAccess
)
2070 IPropDataImpl
*This
= impl_from_IPropData(iface
);
2072 TRACE("(%p,%lx)\n", iface
, ulAccess
);
2074 if (!iface
|| ulAccess
< IPROP_READONLY
|| ulAccess
> IPROP_READWRITE
)
2075 return MAPI_E_INVALID_PARAMETER
;
2077 IMAPIPROP_Lock(This
);
2079 This
->ulObjAccess
= ulAccess
;
2081 IMAPIPROP_Unlock(This
);
2085 /* Internal - determine if an access value is bad */
2086 static inline BOOL
PROP_IsBadAccess(ULONG ulAccess
)
2090 case IPROP_READONLY
|IPROP_CLEAN
:
2091 case IPROP_READONLY
|IPROP_DIRTY
:
2092 case IPROP_READWRITE
|IPROP_CLEAN
:
2093 case IPROP_READWRITE
|IPROP_DIRTY
:
2099 /**************************************************************************
2100 * IPropData_HrSetPropAccess {MAPI32}
2102 * Set the access levels for a group of property values in an IPropData object.
2105 * iface [I] IPropData object to set access levels in.
2106 * lpTags [I] List of property Id's to set access for.
2107 * lpAccess [O] Access level for each property in lpTags.
2110 * Success: S_OK. The access level of each property value in lpTags that is
2111 * present in iface is changed.
2112 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
2115 * - Each access level in lpAccess must contain at least one of IPROP_READONLY
2116 * or IPROP_READWRITE, but not both, and also IPROP_CLEAN or IPROP_DIRTY,
2117 * but not both. No other bits should be set.
2118 * - If a property Id in lpTags is not present in iface, it is ignored.
2120 static HRESULT WINAPI
2121 IPropData_fnHrSetPropAccess(LPPROPDATA iface
, LPSPropTagArray lpTags
,
2124 IPropDataImpl
*This
= impl_from_IPropData(iface
);
2127 TRACE("(%p,%p,%p)\n", iface
, lpTags
, lpAccess
);
2129 if (!iface
|| !lpTags
|| !lpAccess
)
2130 return MAPI_E_INVALID_PARAMETER
;
2132 for (i
= 0; i
< lpTags
->cValues
; i
++)
2134 if (FBadPropTag(lpTags
->aulPropTag
[i
]) || PROP_IsBadAccess(lpAccess
[i
]))
2135 return MAPI_E_INVALID_PARAMETER
;
2138 IMAPIPROP_Lock(This
);
2140 for (i
= 0; i
< lpTags
->cValues
; i
++)
2142 LPIPropDataItem item
= IMAPIPROP_GetValue(This
, lpTags
->aulPropTag
[i
]);
2145 item
->ulAccess
= lpAccess
[i
];
2148 IMAPIPROP_Unlock(This
);
2152 /**************************************************************************
2153 * IPropData_HrGetPropAccess {MAPI32}
2155 * Get the access levels for a group of property values in an IPropData object.
2158 * iface [I] IPropData object to get access levels from.
2159 * lppTags [O] Destination for the list of property Id's in iface.
2160 * lppAccess [O] Destination for access level for each property in lppTags.
2163 * Success: S_OK. lppTags and lppAccess contain the property Id's and the
2164 * Access level of each property value in iface.
2165 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid, or
2166 * MAPI_E_NOT_ENOUGH_MEMORY if memory allocation fails.
2169 * - *lppTags and *lppAccess should be freed with MAPIFreeBuffer() by the caller.
2171 static HRESULT WINAPI
2172 IPropData_fnHrGetPropAccess(LPPROPDATA iface
, LPSPropTagArray
*lppTags
,
2175 IPropDataImpl
*This
= impl_from_IPropData(iface
);
2180 TRACE("(%p,%p,%p) stub\n", iface
, lppTags
, lppAccess
);
2182 if (!iface
|| !lppTags
|| !lppAccess
)
2183 return MAPI_E_INVALID_PARAMETER
;
2188 IMAPIPROP_Lock(This
);
2190 hRet
= This
->lpAlloc(CbNewSPropTagArray(This
->ulNumValues
), &lpMem
);
2191 if (SUCCEEDED(hRet
))
2195 hRet
= This
->lpAlloc(This
->ulNumValues
* sizeof(ULONG
), &lpMem
);
2196 if (SUCCEEDED(hRet
))
2198 struct list
*cursor
;
2201 (*lppTags
)->cValues
= This
->ulNumValues
;
2204 LIST_FOR_EACH(cursor
, &This
->values
)
2206 LPIPropDataItem item
= LIST_ENTRY(cursor
, IPropDataItem
, entry
);
2207 (*lppTags
)->aulPropTag
[i
] = item
->value
->ulPropTag
;
2208 (*lppAccess
)[i
] = item
->ulAccess
;
2211 IMAPIPROP_Unlock(This
);
2214 This
->lpFree(*lppTags
);
2217 IMAPIPROP_Unlock(This
);
2218 return MAPI_E_NOT_ENOUGH_MEMORY
;
2221 /**************************************************************************
2222 * IPropData_HrAddObjProps {MAPI32}
2224 * Not documented at this time.
2227 * An HRESULT success/failure code.
2229 static HRESULT WINAPI
2230 IPropData_fnHrAddObjProps(LPPROPDATA iface
, LPSPropTagArray lpTags
,
2231 LPSPropProblemArray
*lppProbs
)
2236 LPSPropValue lpValues
;
2239 FIXME("(%p,%p,%p) stub\n", iface
, lpTags
, lppProbs
);
2241 if (!iface
|| !lpTags
)
2242 return MAPI_E_INVALID_PARAMETER
;
2244 /* FIXME: Below is the obvious implementation, adding all the properties
2245 * in lpTags to the object. However, it doesn't appear that this
2246 * is what this function does.
2250 if (!lpTags
->cValues
)
2253 lpValues
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
2254 lpTags
->cValues
* sizeof(SPropValue
));
2256 return MAPI_E_NOT_ENOUGH_MEMORY
;
2258 for (i
= 0; i
< lpTags
->cValues
; i
++)
2259 lpValues
[i
].ulPropTag
= lpTags
->aulPropTag
[i
];
2261 hRet
= IPropData_SetProps(iface
, lpTags
->cValues
, lpValues
, lppProbs
);
2262 HeapFree(GetProcessHeap(), 0, lpValues
);
2267 static const IPropDataVtbl IPropDataImpl_vtbl
=
2269 IPropData_fnQueryInterface
,
2271 IPropData_fnRelease
,
2272 IPropData_fnGetLastError
,
2273 IPropData_fnSaveChanges
,
2274 IPropData_fnGetProps
,
2275 IPropData_fnGetPropList
,
2276 IPropData_fnOpenProperty
,
2277 IPropData_fnSetProps
,
2278 IPropData_fnDeleteProps
,
2280 IPropData_fnCopyProps
,
2281 IPropData_fnGetNamesFromIDs
,
2282 IPropData_fnGetIDsFromNames
,
2283 IPropData_fnHrSetObjAccess
,
2284 IPropData_fnHrSetPropAccess
,
2285 IPropData_fnHrGetPropAccess
,
2286 IPropData_fnHrAddObjProps
2289 /*************************************************************************
2290 * CreateIProp@24 (MAPI32.60)
2292 * Create an IPropData object.
2295 * iid [I] GUID of the object to create. Use &IID_IMAPIPropData or NULL
2296 * lpAlloc [I] Memory allocation function. Use MAPIAllocateBuffer()
2297 * lpMore [I] Linked memory allocation function. Use MAPIAllocateMore()
2298 * lpFree [I] Memory free function. Use MAPIFreeBuffer()
2299 * lpReserved [I] Reserved, set to NULL
2300 * lppPropData [O] Destination for created IPropData object
2303 * Success: S_OK. *lppPropData contains the newly created object.
2304 * Failure: MAPI_E_INTERFACE_NOT_SUPPORTED, if iid is non-NULL and not supported,
2305 * MAPI_E_INVALID_PARAMETER, if any parameter is invalid
2307 SCODE WINAPI
CreateIProp(LPCIID iid
, ALLOCATEBUFFER
*lpAlloc
,
2308 ALLOCATEMORE
*lpMore
, FREEBUFFER
*lpFree
,
2309 LPVOID lpReserved
, LPPROPDATA
*lppPropData
)
2311 IPropDataImpl
*lpPropData
;
2314 TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_guid(iid
), lpAlloc
, lpMore
, lpFree
,
2315 lpReserved
, lppPropData
);
2318 *lppPropData
= NULL
;
2320 if (iid
&& !IsEqualGUID(iid
, &IID_IMAPIPropData
))
2321 return MAPI_E_INTERFACE_NOT_SUPPORTED
;
2323 if (!lpAlloc
|| !lpMore
|| !lpFree
|| lpReserved
|| !lppPropData
)
2324 return MAPI_E_INVALID_PARAMETER
;
2326 scode
= lpAlloc(sizeof(IPropDataImpl
), (LPVOID
*)&lpPropData
);
2328 if (SUCCEEDED(scode
))
2330 lpPropData
->IPropData_iface
.lpVtbl
= &IPropDataImpl_vtbl
;
2331 lpPropData
->lRef
= 1;
2332 lpPropData
->lpAlloc
= lpAlloc
;
2333 lpPropData
->lpMore
= lpMore
;
2334 lpPropData
->lpFree
= lpFree
;
2335 lpPropData
->ulObjAccess
= IPROP_READWRITE
;
2336 lpPropData
->ulNumValues
= 0;
2337 list_init(&lpPropData
->values
);
2338 InitializeCriticalSection(&lpPropData
->cs
);
2339 lpPropData
->cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": IPropDataImpl.cs");
2340 *lppPropData
= &lpPropData
->IPropData_iface
;