Sync with trunk for console graphics palettes.
[reactos.git] / dll / win32 / mapi32 / prop.c
1 /*
2 * Property functions
3 *
4 * Copyright 2004 Jon Griffiths
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #define WIN32_NO_STATUS
22 #define _INC_WINDOWS
23 #define COM_NO_WINDOWS_H
24
25 #include <stdarg.h>
26 #define NONAMELESSUNION
27 #define NONAMELESSSTRUCT
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winreg.h"
31 //#include "winerror.h"
32 //#include "winternl.h"
33 //#include "objbase.h"
34 #include <shlwapi.h>
35 #include <wine/list.h>
36 #include <wine/debug.h>
37 #include <wine/unicode.h>
38 #include <mapival.h>
39
40 WINE_DEFAULT_DEBUG_CHANNEL(mapi);
41
42 BOOL WINAPI FBadRglpszA(LPSTR*,ULONG);
43
44 /* Internal: Check if a property value array is invalid */
45 static inline ULONG PROP_BadArray(LPSPropValue lpProp, size_t elemSize)
46 {
47 return IsBadReadPtr(lpProp->Value.MVi.lpi, lpProp->Value.MVi.cValues * elemSize);
48 }
49
50 /*************************************************************************
51 * PropCopyMore@16 (MAPI32.76)
52 *
53 * Copy a property value.
54 *
55 * PARAMS
56 * lpDest [O] Destination for the copied value
57 * lpSrc [I] Property value to copy to lpDest
58 * lpMore [I] Linked memory allocation function (pass MAPIAllocateMore())
59 * lpOrig [I] Original allocation to which memory will be linked
60 *
61 * RETURNS
62 * Success: S_OK. lpDest contains a deep copy of lpSrc.
63 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid,
64 * MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails.
65 *
66 * NOTES
67 * Any elements within the property returned should not be individually
68 * freed, as they will be freed when lpOrig is.
69 */
70 SCODE WINAPI PropCopyMore(LPSPropValue lpDest, LPSPropValue lpSrc,
71 ALLOCATEMORE *lpMore, LPVOID lpOrig)
72 {
73 ULONG ulLen, i;
74 SCODE scode = S_OK;
75
76 TRACE("(%p,%p,%p,%p)\n", lpDest, lpSrc, lpMore, lpOrig);
77
78 if (!lpDest || IsBadWritePtr(lpDest, sizeof(SPropValue)) ||
79 FBadProp(lpSrc) || !lpMore)
80 return MAPI_E_INVALID_PARAMETER;
81
82 /* Shallow copy first, this is sufficient for properties without pointers */
83 *lpDest = *lpSrc;
84
85 switch (PROP_TYPE(lpSrc->ulPropTag))
86 {
87 case PT_CLSID:
88 scode = lpMore(sizeof(GUID), lpOrig, (LPVOID*)&lpDest->Value.lpguid);
89 if (SUCCEEDED(scode))
90 *lpDest->Value.lpguid = *lpSrc->Value.lpguid;
91 break;
92 case PT_STRING8:
93 ulLen = lstrlenA(lpSrc->Value.lpszA) + 1u;
94 scode = lpMore(ulLen, lpOrig, (LPVOID*)&lpDest->Value.lpszA);
95 if (SUCCEEDED(scode))
96 memcpy(lpDest->Value.lpszA, lpSrc->Value.lpszA, ulLen);
97 break;
98 case PT_UNICODE:
99 ulLen = (strlenW(lpSrc->Value.lpszW) + 1u) * sizeof(WCHAR);
100 scode = lpMore(ulLen, lpOrig, (LPVOID*)&lpDest->Value.lpszW);
101 if (SUCCEEDED(scode))
102 memcpy(lpDest->Value.lpszW, lpSrc->Value.lpszW, ulLen);
103 break;
104 case PT_BINARY:
105 scode = lpMore(lpSrc->Value.bin.cb, lpOrig, (LPVOID*)&lpDest->Value.bin.lpb);
106 if (SUCCEEDED(scode))
107 memcpy(lpDest->Value.bin.lpb, lpSrc->Value.bin.lpb, lpSrc->Value.bin.cb);
108 break;
109 default:
110 if (lpSrc->ulPropTag & MV_FLAG)
111 {
112 ulLen = UlPropSize(lpSrc);
113
114 if (PROP_TYPE(lpSrc->ulPropTag) == PT_MV_STRING8 ||
115 PROP_TYPE(lpSrc->ulPropTag) == PT_MV_UNICODE)
116 {
117 /* UlPropSize doesn't account for the string pointers */
118 ulLen += lpSrc->Value.MVszA.cValues * sizeof(char*);
119 }
120 else if (PROP_TYPE(lpSrc->ulPropTag) == PT_MV_BINARY)
121 {
122 /* UlPropSize doesn't account for the SBinary structs */
123 ulLen += lpSrc->Value.MVbin.cValues * sizeof(SBinary);
124 }
125
126 lpDest->Value.MVi.cValues = lpSrc->Value.MVi.cValues;
127 scode = lpMore(ulLen, lpOrig, (LPVOID*)&lpDest->Value.MVi.lpi);
128 if (FAILED(scode))
129 break;
130
131 /* Note that we could allocate the memory for each value in a
132 * multi-value property separately, however if an allocation failed
133 * we would be left with a bunch of allocated memory, which (while
134 * not really leaked) is unusable until lpOrig is freed. So for
135 * strings and binary arrays we make a single allocation for all
136 * of the data. This is consistent since individual elements can't
137 * be freed anyway.
138 */
139
140 switch (PROP_TYPE(lpSrc->ulPropTag))
141 {
142 case PT_MV_STRING8:
143 {
144 char *lpNextStr = (char*)(lpDest->Value.MVszA.lppszA +
145 lpDest->Value.MVszA.cValues);
146
147 for (i = 0; i < lpSrc->Value.MVszA.cValues; i++)
148 {
149 ULONG ulStrLen = lstrlenA(lpSrc->Value.MVszA.lppszA[i]) + 1u;
150
151 lpDest->Value.MVszA.lppszA[i] = lpNextStr;
152 memcpy(lpNextStr, lpSrc->Value.MVszA.lppszA[i], ulStrLen);
153 lpNextStr += ulStrLen;
154 }
155 break;
156 }
157 case PT_MV_UNICODE:
158 {
159 WCHAR *lpNextStr = (WCHAR*)(lpDest->Value.MVszW.lppszW +
160 lpDest->Value.MVszW.cValues);
161
162 for (i = 0; i < lpSrc->Value.MVszW.cValues; i++)
163 {
164 ULONG ulStrLen = strlenW(lpSrc->Value.MVszW.lppszW[i]) + 1u;
165
166 lpDest->Value.MVszW.lppszW[i] = lpNextStr;
167 memcpy(lpNextStr, lpSrc->Value.MVszW.lppszW[i], ulStrLen * sizeof(WCHAR));
168 lpNextStr += ulStrLen;
169 }
170 break;
171 }
172 case PT_MV_BINARY:
173 {
174 LPBYTE lpNext = (LPBYTE)(lpDest->Value.MVbin.lpbin +
175 lpDest->Value.MVbin.cValues);
176
177 for (i = 0; i < lpSrc->Value.MVszW.cValues; i++)
178 {
179 lpDest->Value.MVbin.lpbin[i].cb = lpSrc->Value.MVbin.lpbin[i].cb;
180 lpDest->Value.MVbin.lpbin[i].lpb = lpNext;
181 memcpy(lpNext, lpSrc->Value.MVbin.lpbin[i].lpb, lpDest->Value.MVbin.lpbin[i].cb);
182 lpNext += lpDest->Value.MVbin.lpbin[i].cb;
183 }
184 break;
185 }
186 default:
187 /* No embedded pointers, just copy the data over */
188 memcpy(lpDest->Value.MVi.lpi, lpSrc->Value.MVi.lpi, ulLen);
189 break;
190 }
191 break;
192 }
193 }
194 return scode;
195 }
196
197 /*************************************************************************
198 * UlPropSize@4 (MAPI32.77)
199 *
200 * Determine the size of a property in bytes.
201 *
202 * PARAMS
203 * lpProp [I] Property to determine the size of
204 *
205 * RETURNS
206 * Success: The size of the value in lpProp.
207 * Failure: 0, if a multi-value (array) property is invalid or the type of lpProp
208 * is unknown.
209 *
210 * NOTES
211 * - The size returned does not include the size of the SPropValue struct
212 * or the size of the array of pointers for multi-valued properties that
213 * contain pointers (such as PT_MV_STRING8 or PT-MV_UNICODE).
214 * - MSDN incorrectly states that this function returns MAPI_E_CALL_FAILED if
215 * lpProp is invalid. In reality no checking is performed and this function
216 * will crash if passed an invalid property, or return 0 if the property
217 * type is PT_OBJECT or is unknown.
218 */
219 ULONG WINAPI UlPropSize(LPSPropValue lpProp)
220 {
221 ULONG ulRet = 1u, i;
222
223 TRACE("(%p)\n", lpProp);
224
225 switch (PROP_TYPE(lpProp->ulPropTag))
226 {
227 case PT_MV_I2: ulRet = lpProp->Value.MVi.cValues;
228 /* fall through */
229 case PT_BOOLEAN:
230 case PT_I2: ulRet *= sizeof(USHORT);
231 break;
232 case PT_MV_I4: ulRet = lpProp->Value.MVl.cValues;
233 /* fall through */
234 case PT_ERROR:
235 case PT_I4: ulRet *= sizeof(LONG);
236 break;
237 case PT_MV_I8: ulRet = lpProp->Value.MVli.cValues;
238 /* fall through */
239 case PT_I8: ulRet *= sizeof(LONG64);
240 break;
241 case PT_MV_R4: ulRet = lpProp->Value.MVflt.cValues;
242 /* fall through */
243 case PT_R4: ulRet *= sizeof(float);
244 break;
245 case PT_MV_APPTIME:
246 case PT_MV_R8: ulRet = lpProp->Value.MVdbl.cValues;
247 /* fall through */
248 case PT_APPTIME:
249 case PT_R8: ulRet *= sizeof(double);
250 break;
251 case PT_MV_CURRENCY: ulRet = lpProp->Value.MVcur.cValues;
252 /* fall through */
253 case PT_CURRENCY: ulRet *= sizeof(CY);
254 break;
255 case PT_MV_SYSTIME: ulRet = lpProp->Value.MVft.cValues;
256 /* fall through */
257 case PT_SYSTIME: ulRet *= sizeof(FILETIME);
258 break;
259 case PT_MV_CLSID: ulRet = lpProp->Value.MVguid.cValues;
260 /* fall through */
261 case PT_CLSID: ulRet *= sizeof(GUID);
262 break;
263 case PT_MV_STRING8: ulRet = 0u;
264 for (i = 0; i < lpProp->Value.MVszA.cValues; i++)
265 ulRet += (lstrlenA(lpProp->Value.MVszA.lppszA[i]) + 1u);
266 break;
267 case PT_STRING8: ulRet = lstrlenA(lpProp->Value.lpszA) + 1u;
268 break;
269 case PT_MV_UNICODE: ulRet = 0u;
270 for (i = 0; i < lpProp->Value.MVszW.cValues; i++)
271 ulRet += (strlenW(lpProp->Value.MVszW.lppszW[i]) + 1u);
272 ulRet *= sizeof(WCHAR);
273 break;
274 case PT_UNICODE: ulRet = (lstrlenW(lpProp->Value.lpszW) + 1u) * sizeof(WCHAR);
275 break;
276 case PT_MV_BINARY: ulRet = 0u;
277 for (i = 0; i < lpProp->Value.MVbin.cValues; i++)
278 ulRet += lpProp->Value.MVbin.lpbin[i].cb;
279 break;
280 case PT_BINARY: ulRet = lpProp->Value.bin.cb;
281 break;
282 case PT_OBJECT:
283 default: ulRet = 0u;
284 break;
285 }
286
287 return ulRet;
288 }
289
290 /*************************************************************************
291 * FPropContainsProp@12 (MAPI32.78)
292 *
293 * Find a property with a given property tag in a property array.
294 *
295 * PARAMS
296 * lpHaystack [I] Property to match to
297 * lpNeedle [I] Property to find in lpHaystack
298 * ulFuzzy [I] Flags controlling match type and strictness (FL_* flags from "mapidefs.h")
299 *
300 * RETURNS
301 * TRUE, if lpNeedle matches lpHaystack according to the criteria of ulFuzzy.
302 *
303 * NOTES
304 * Only property types of PT_STRING8 and PT_BINARY are handled by this function.
305 */
306 BOOL WINAPI FPropContainsProp(LPSPropValue lpHaystack, LPSPropValue lpNeedle, ULONG ulFuzzy)
307 {
308 TRACE("(%p,%p,0x%08x)\n", lpHaystack, lpNeedle, ulFuzzy);
309
310 if (FBadProp(lpHaystack) || FBadProp(lpNeedle) ||
311 PROP_TYPE(lpHaystack->ulPropTag) != PROP_TYPE(lpNeedle->ulPropTag))
312 return FALSE;
313
314 /* FIXME: Do later versions support Unicode as well? */
315
316 if (PROP_TYPE(lpHaystack->ulPropTag) == PT_STRING8)
317 {
318 DWORD dwFlags = 0, dwNeedleLen, dwHaystackLen;
319
320 if (ulFuzzy & FL_IGNORECASE)
321 dwFlags |= NORM_IGNORECASE;
322 if (ulFuzzy & FL_IGNORENONSPACE)
323 dwFlags |= NORM_IGNORENONSPACE;
324 if (ulFuzzy & FL_LOOSE)
325 dwFlags |= (NORM_IGNORECASE|NORM_IGNORENONSPACE|NORM_IGNORESYMBOLS);
326
327 dwNeedleLen = lstrlenA(lpNeedle->Value.lpszA);
328 dwHaystackLen = lstrlenA(lpHaystack->Value.lpszA);
329
330 if ((ulFuzzy & (FL_SUBSTRING|FL_PREFIX)) == FL_PREFIX)
331 {
332 if (dwNeedleLen <= dwHaystackLen &&
333 CompareStringA(LOCALE_USER_DEFAULT, dwFlags,
334 lpHaystack->Value.lpszA, dwNeedleLen,
335 lpNeedle->Value.lpszA, dwNeedleLen) == CSTR_EQUAL)
336 return TRUE; /* needle is a prefix of haystack */
337 }
338 else if ((ulFuzzy & (FL_SUBSTRING|FL_PREFIX)) == FL_SUBSTRING)
339 {
340 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD) = StrChrA;
341 LPSTR lpStr = lpHaystack->Value.lpszA;
342
343 if (dwFlags & NORM_IGNORECASE)
344 pStrChrFn = StrChrIA;
345
346 while ((lpStr = pStrChrFn(lpStr, *lpNeedle->Value.lpszA)) != NULL)
347 {
348 dwHaystackLen -= (lpStr - lpHaystack->Value.lpszA);
349 if (dwNeedleLen <= dwHaystackLen &&
350 CompareStringA(LOCALE_USER_DEFAULT, dwFlags,
351 lpStr, dwNeedleLen,
352 lpNeedle->Value.lpszA, dwNeedleLen) == CSTR_EQUAL)
353 return TRUE; /* needle is a substring of haystack */
354 lpStr++;
355 }
356 }
357 else if (CompareStringA(LOCALE_USER_DEFAULT, dwFlags,
358 lpHaystack->Value.lpszA, dwHaystackLen,
359 lpNeedle->Value.lpszA, dwNeedleLen) == CSTR_EQUAL)
360 return TRUE; /* full string match */
361 }
362 else if (PROP_TYPE(lpHaystack->ulPropTag) == PT_BINARY)
363 {
364 if ((ulFuzzy & (FL_SUBSTRING|FL_PREFIX)) == FL_PREFIX)
365 {
366 if (lpNeedle->Value.bin.cb <= lpHaystack->Value.bin.cb &&
367 !memcmp(lpNeedle->Value.bin.lpb, lpHaystack->Value.bin.lpb,
368 lpNeedle->Value.bin.cb))
369 return TRUE; /* needle is a prefix of haystack */
370 }
371 else if ((ulFuzzy & (FL_SUBSTRING|FL_PREFIX)) == FL_SUBSTRING)
372 {
373 ULONG ulLen = lpHaystack->Value.bin.cb;
374 LPBYTE lpb = lpHaystack->Value.bin.lpb;
375
376 while ((lpb = memchr(lpb, *lpNeedle->Value.bin.lpb, ulLen)) != NULL)
377 {
378 ulLen = lpHaystack->Value.bin.cb - (lpb - lpHaystack->Value.bin.lpb);
379 if (lpNeedle->Value.bin.cb <= ulLen &&
380 !memcmp(lpNeedle->Value.bin.lpb, lpb, lpNeedle->Value.bin.cb))
381 return TRUE; /* needle is a substring of haystack */
382 lpb++;
383 }
384 }
385 else if (!LPropCompareProp(lpHaystack, lpNeedle))
386 return TRUE; /* needle is an exact match with haystack */
387
388 }
389 return FALSE;
390 }
391
392 /*************************************************************************
393 * FPropCompareProp@12 (MAPI32.79)
394 *
395 * Compare two properties.
396 *
397 * PARAMS
398 * lpPropLeft [I] Left hand property to compare to lpPropRight
399 * ulOp [I] Comparison operator (RELOP_* enum from "mapidefs.h")
400 * lpPropRight [I] Right hand property to compare to lpPropLeft
401 *
402 * RETURNS
403 * TRUE, if the comparison is true, FALSE otherwise.
404 */
405 BOOL WINAPI FPropCompareProp(LPSPropValue lpPropLeft, ULONG ulOp, LPSPropValue lpPropRight)
406 {
407 LONG iCmp;
408
409 TRACE("(%p,%d,%p)\n", lpPropLeft, ulOp, lpPropRight);
410
411 if (ulOp > RELOP_RE || FBadProp(lpPropLeft) || FBadProp(lpPropRight))
412 return FALSE;
413
414 if (ulOp == RELOP_RE)
415 {
416 FIXME("Comparison operator RELOP_RE not yet implemented!\n");
417 return FALSE;
418 }
419
420 iCmp = LPropCompareProp(lpPropLeft, lpPropRight);
421
422 switch (ulOp)
423 {
424 case RELOP_LT: return iCmp < 0;
425 case RELOP_LE: return iCmp <= 0;
426 case RELOP_GT: return iCmp > 0;
427 case RELOP_GE: return iCmp >= 0;
428 case RELOP_EQ: return iCmp == 0;
429 case RELOP_NE: return iCmp != 0;
430 }
431 return FALSE;
432 }
433
434 /*************************************************************************
435 * LPropCompareProp@8 (MAPI32.80)
436 *
437 * Compare two properties.
438 *
439 * PARAMS
440 * lpPropLeft [I] Left hand property to compare to lpPropRight
441 * lpPropRight [I] Right hand property to compare to lpPropLeft
442 *
443 * RETURNS
444 * An integer less than, equal to or greater than 0, indicating that
445 * lpszStr is less than, the same, or greater than lpszComp.
446 */
447 LONG WINAPI LPropCompareProp(LPSPropValue lpPropLeft, LPSPropValue lpPropRight)
448 {
449 LONG iRet;
450
451 TRACE("(%p->0x%08x,%p->0x%08x)\n", lpPropLeft, lpPropLeft->ulPropTag,
452 lpPropRight, lpPropRight->ulPropTag);
453
454 /* If the properties are not the same, sort by property type */
455 if (PROP_TYPE(lpPropLeft->ulPropTag) != PROP_TYPE(lpPropRight->ulPropTag))
456 return (LONG)PROP_TYPE(lpPropLeft->ulPropTag) - (LONG)PROP_TYPE(lpPropRight->ulPropTag);
457
458 switch (PROP_TYPE(lpPropLeft->ulPropTag))
459 {
460 case PT_UNSPECIFIED:
461 case PT_NULL:
462 return 0; /* NULLs are equal */
463 case PT_I2:
464 return lpPropLeft->Value.i - lpPropRight->Value.i;
465 case PT_I4:
466 return lpPropLeft->Value.l - lpPropRight->Value.l;
467 case PT_I8:
468 if (lpPropLeft->Value.li.QuadPart > lpPropRight->Value.li.QuadPart)
469 return 1;
470 if (lpPropLeft->Value.li.QuadPart == lpPropRight->Value.li.QuadPart)
471 return 0;
472 return -1;
473 case PT_R4:
474 if (lpPropLeft->Value.flt > lpPropRight->Value.flt)
475 return 1;
476 if (lpPropLeft->Value.flt == lpPropRight->Value.flt)
477 return 0;
478 return -1;
479 case PT_APPTIME:
480 case PT_R8:
481 if (lpPropLeft->Value.dbl > lpPropRight->Value.dbl)
482 return 1;
483 if (lpPropLeft->Value.dbl == lpPropRight->Value.dbl)
484 return 0;
485 return -1;
486 case PT_CURRENCY:
487 if (lpPropLeft->Value.cur.int64 > lpPropRight->Value.cur.int64)
488 return 1;
489 if (lpPropLeft->Value.cur.int64 == lpPropRight->Value.cur.int64)
490 return 0;
491 return -1;
492 case PT_SYSTIME:
493 return CompareFileTime(&lpPropLeft->Value.ft, &lpPropRight->Value.ft);
494 case PT_BOOLEAN:
495 return (lpPropLeft->Value.b ? 1 : 0) - (lpPropRight->Value.b ? 1 : 0);
496 case PT_BINARY:
497 if (lpPropLeft->Value.bin.cb == lpPropRight->Value.bin.cb)
498 iRet = memcmp(lpPropLeft->Value.bin.lpb, lpPropRight->Value.bin.lpb,
499 lpPropLeft->Value.bin.cb);
500 else
501 {
502 iRet = memcmp(lpPropLeft->Value.bin.lpb, lpPropRight->Value.bin.lpb,
503 min(lpPropLeft->Value.bin.cb, lpPropRight->Value.bin.cb));
504
505 if (!iRet)
506 iRet = lpPropLeft->Value.bin.cb - lpPropRight->Value.bin.cb;
507 }
508 return iRet;
509 case PT_STRING8:
510 return lstrcmpA(lpPropLeft->Value.lpszA, lpPropRight->Value.lpszA);
511 case PT_UNICODE:
512 return strcmpW(lpPropLeft->Value.lpszW, lpPropRight->Value.lpszW);
513 case PT_ERROR:
514 if (lpPropLeft->Value.err > lpPropRight->Value.err)
515 return 1;
516 if (lpPropLeft->Value.err == lpPropRight->Value.err)
517 return 0;
518 return -1;
519 case PT_CLSID:
520 return memcmp(lpPropLeft->Value.lpguid, lpPropRight->Value.lpguid,
521 sizeof(GUID));
522 }
523 FIXME("Unhandled property type %d\n", PROP_TYPE(lpPropLeft->ulPropTag));
524 return 0;
525 }
526
527 /*************************************************************************
528 * HrGetOneProp@8 (MAPI32.135)
529 *
530 * Get a property value from an IMAPIProp object.
531 *
532 * PARAMS
533 * lpIProp [I] IMAPIProp object to get the property value in
534 * ulPropTag [I] Property tag of the property to get
535 * lppProp [O] Destination for the returned property
536 *
537 * RETURNS
538 * Success: S_OK. *lppProp contains the property value requested.
539 * Failure: MAPI_E_NOT_FOUND, if no property value has the tag given by ulPropTag.
540 */
541 HRESULT WINAPI HrGetOneProp(LPMAPIPROP lpIProp, ULONG ulPropTag, LPSPropValue *lppProp)
542 {
543 SPropTagArray pta;
544 ULONG ulCount;
545 HRESULT hRet;
546
547 TRACE("(%p,%d,%p)\n", lpIProp, ulPropTag, lppProp);
548
549 pta.cValues = 1u;
550 pta.aulPropTag[0] = ulPropTag;
551 hRet = IMAPIProp_GetProps(lpIProp, &pta, 0u, &ulCount, lppProp);
552 if (hRet == MAPI_W_ERRORS_RETURNED)
553 {
554 MAPIFreeBuffer(*lppProp);
555 *lppProp = NULL;
556 hRet = MAPI_E_NOT_FOUND;
557 }
558 return hRet;
559 }
560
561 /*************************************************************************
562 * HrSetOneProp@8 (MAPI32.136)
563 *
564 * Set a property value in an IMAPIProp object.
565 *
566 * PARAMS
567 * lpIProp [I] IMAPIProp object to set the property value in
568 * lpProp [I] Property value to set
569 *
570 * RETURNS
571 * Success: S_OK. The value in lpProp is set in lpIProp.
572 * Failure: An error result from IMAPIProp_SetProps().
573 */
574 HRESULT WINAPI HrSetOneProp(LPMAPIPROP lpIProp, LPSPropValue lpProp)
575 {
576 TRACE("(%p,%p)\n", lpIProp, lpProp);
577
578 return IMAPIProp_SetProps(lpIProp, 1u, lpProp, NULL);
579 }
580
581 /*************************************************************************
582 * FPropExists@8 (MAPI32.137)
583 *
584 * Find a property with a given property tag in an IMAPIProp object.
585 *
586 * PARAMS
587 * lpIProp [I] IMAPIProp object to find the property tag in
588 * ulPropTag [I] Property tag to find
589 *
590 * RETURNS
591 * TRUE, if ulPropTag matches a property held in lpIProp,
592 * FALSE, otherwise.
593 *
594 * NOTES
595 * if ulPropTag has a property type of PT_UNSPECIFIED, then only the property
596 * Ids need to match for a successful match to occur.
597 */
598 BOOL WINAPI FPropExists(LPMAPIPROP lpIProp, ULONG ulPropTag)
599 {
600 BOOL bRet = FALSE;
601
602 TRACE("(%p,%d)\n", lpIProp, ulPropTag);
603
604 if (lpIProp)
605 {
606 LPSPropTagArray lpTags;
607 ULONG i;
608
609 if (FAILED(IMAPIProp_GetPropList(lpIProp, 0u, &lpTags)))
610 return FALSE;
611
612 for (i = 0; i < lpTags->cValues; i++)
613 {
614 if (!FBadPropTag(lpTags->aulPropTag[i]) &&
615 (lpTags->aulPropTag[i] == ulPropTag ||
616 (PROP_TYPE(ulPropTag) == PT_UNSPECIFIED &&
617 PROP_ID(lpTags->aulPropTag[i]) == lpTags->aulPropTag[i])))
618 {
619 bRet = TRUE;
620 break;
621 }
622 }
623 MAPIFreeBuffer(lpTags);
624 }
625 return bRet;
626 }
627
628 /*************************************************************************
629 * PpropFindProp@12 (MAPI32.138)
630 *
631 * Find a property with a given property tag in a property array.
632 *
633 * PARAMS
634 * lpProps [I] Property array to search
635 * cValues [I] Number of properties in lpProps
636 * ulPropTag [I] Property tag to find
637 *
638 * RETURNS
639 * A pointer to the matching property, or NULL if none was found.
640 *
641 * NOTES
642 * if ulPropTag has a property type of PT_UNSPECIFIED, then only the property
643 * Ids need to match for a successful match to occur.
644 */
645 LPSPropValue WINAPI PpropFindProp(LPSPropValue lpProps, ULONG cValues, ULONG ulPropTag)
646 {
647 TRACE("(%p,%d,%d)\n", lpProps, cValues, ulPropTag);
648
649 if (lpProps && cValues)
650 {
651 ULONG i;
652 for (i = 0; i < cValues; i++)
653 {
654 if (!FBadPropTag(lpProps[i].ulPropTag) &&
655 (lpProps[i].ulPropTag == ulPropTag ||
656 (PROP_TYPE(ulPropTag) == PT_UNSPECIFIED &&
657 PROP_ID(lpProps[i].ulPropTag) == PROP_ID(ulPropTag))))
658 return &lpProps[i];
659 }
660 }
661 return NULL;
662 }
663
664 /*************************************************************************
665 * FreePadrlist@4 (MAPI32.139)
666 *
667 * Free the memory used by an address book list.
668 *
669 * PARAMS
670 * lpAddrs [I] Address book list to free
671 *
672 * RETURNS
673 * Nothing.
674 */
675 VOID WINAPI FreePadrlist(LPADRLIST lpAddrs)
676 {
677 TRACE("(%p)\n", lpAddrs);
678
679 /* Structures are binary compatible; use the same implementation */
680 FreeProws((LPSRowSet)lpAddrs);
681 }
682
683 /*************************************************************************
684 * FreeProws@4 (MAPI32.140)
685 *
686 * Free the memory used by a row set.
687 *
688 * PARAMS
689 * lpRowSet [I] Row set to free
690 *
691 * RETURNS
692 * Nothing.
693 */
694 VOID WINAPI FreeProws(LPSRowSet lpRowSet)
695 {
696 TRACE("(%p)\n", lpRowSet);
697
698 if (lpRowSet)
699 {
700 ULONG i;
701
702 for (i = 0; i < lpRowSet->cRows; i++)
703 MAPIFreeBuffer(lpRowSet->aRow[i].lpProps);
704
705 MAPIFreeBuffer(lpRowSet);
706 }
707 }
708
709 /*************************************************************************
710 * ScCountProps@12 (MAPI32.170)
711 *
712 * Validate and determine the length of an array of properties.
713 *
714 * PARAMS
715 * iCount [I] Length of the lpProps array
716 * lpProps [I] Array of properties to validate/size
717 * pcBytes [O] If non-NULL, destination for the size of the property array
718 *
719 * RETURNS
720 * Success: S_OK. If pcBytes is non-NULL, it contains the size of the
721 * properties array.
722 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid or validation
723 * of the property array fails.
724 */
725 SCODE WINAPI ScCountProps(INT iCount, LPSPropValue lpProps, ULONG *pcBytes)
726 {
727 ULONG i, ulCount = iCount, ulBytes = 0;
728
729 TRACE("(%d,%p,%p)\n", iCount, lpProps, pcBytes);
730
731 if (iCount <= 0 || !lpProps ||
732 IsBadReadPtr(lpProps, iCount * sizeof(SPropValue)))
733 return MAPI_E_INVALID_PARAMETER;
734
735 for (i = 0; i < ulCount; i++)
736 {
737 ULONG ulPropSize = 0;
738
739 if (FBadProp(&lpProps[i]) || lpProps[i].ulPropTag == PROP_ID_NULL ||
740 lpProps[i].ulPropTag == PROP_ID_INVALID)
741 return MAPI_E_INVALID_PARAMETER;
742
743 if (PROP_TYPE(lpProps[i].ulPropTag) != PT_OBJECT)
744 {
745 ulPropSize = UlPropSize(&lpProps[i]);
746 if (!ulPropSize)
747 return MAPI_E_INVALID_PARAMETER;
748 }
749
750 switch (PROP_TYPE(lpProps[i].ulPropTag))
751 {
752 case PT_STRING8:
753 case PT_UNICODE:
754 case PT_CLSID:
755 case PT_BINARY:
756 case PT_MV_I2:
757 case PT_MV_I4:
758 case PT_MV_I8:
759 case PT_MV_R4:
760 case PT_MV_R8:
761 case PT_MV_CURRENCY:
762 case PT_MV_SYSTIME:
763 case PT_MV_APPTIME:
764 ulPropSize += sizeof(SPropValue);
765 break;
766 case PT_MV_CLSID:
767 ulPropSize += lpProps[i].Value.MVszA.cValues * sizeof(char*) + sizeof(SPropValue);
768 break;
769 case PT_MV_STRING8:
770 case PT_MV_UNICODE:
771 ulPropSize += lpProps[i].Value.MVszA.cValues * sizeof(char*) + sizeof(SPropValue);
772 break;
773 case PT_MV_BINARY:
774 ulPropSize += lpProps[i].Value.MVbin.cValues * sizeof(SBinary) + sizeof(SPropValue);
775 break;
776 default:
777 ulPropSize = sizeof(SPropValue);
778 break;
779 }
780 ulBytes += ulPropSize;
781 }
782 if (pcBytes)
783 *pcBytes = ulBytes;
784
785 return S_OK;
786 }
787
788 /*************************************************************************
789 * ScCopyProps@16 (MAPI32.171)
790 *
791 * Copy an array of property values into a buffer suited for serialisation.
792 *
793 * PARAMS
794 * cValues [I] Number of properties in lpProps
795 * lpProps [I] Property array to copy
796 * lpDst [O] Destination for the serialised data
797 * lpCount [O] If non-NULL, destination for the number of bytes of data written to lpDst
798 *
799 * RETURNS
800 * Success: S_OK. lpDst contains the serialised data from lpProps.
801 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
802 *
803 * NOTES
804 * The resulting property value array is stored in a contiguous block starting at lpDst.
805 */
806 SCODE WINAPI ScCopyProps(int cValues, LPSPropValue lpProps, LPVOID lpDst, ULONG *lpCount)
807 {
808 LPSPropValue lpDest = (LPSPropValue)lpDst;
809 char *lpDataDest = (char *)(lpDest + cValues);
810 ULONG ulLen, i;
811 int iter;
812
813 TRACE("(%d,%p,%p,%p)\n", cValues, lpProps, lpDst, lpCount);
814
815 if (!lpProps || cValues < 0 || !lpDest)
816 return MAPI_E_INVALID_PARAMETER;
817
818 memcpy(lpDst, lpProps, cValues * sizeof(SPropValue));
819
820 for (iter = 0; iter < cValues; iter++)
821 {
822 switch (PROP_TYPE(lpProps->ulPropTag))
823 {
824 case PT_CLSID:
825 lpDest->Value.lpguid = (LPGUID)lpDataDest;
826 *lpDest->Value.lpguid = *lpProps->Value.lpguid;
827 lpDataDest += sizeof(GUID);
828 break;
829 case PT_STRING8:
830 ulLen = lstrlenA(lpProps->Value.lpszA) + 1u;
831 lpDest->Value.lpszA = lpDataDest;
832 memcpy(lpDest->Value.lpszA, lpProps->Value.lpszA, ulLen);
833 lpDataDest += ulLen;
834 break;
835 case PT_UNICODE:
836 ulLen = (strlenW(lpProps->Value.lpszW) + 1u) * sizeof(WCHAR);
837 lpDest->Value.lpszW = (LPWSTR)lpDataDest;
838 memcpy(lpDest->Value.lpszW, lpProps->Value.lpszW, ulLen);
839 lpDataDest += ulLen;
840 break;
841 case PT_BINARY:
842 lpDest->Value.bin.lpb = (LPBYTE)lpDataDest;
843 memcpy(lpDest->Value.bin.lpb, lpProps->Value.bin.lpb, lpProps->Value.bin.cb);
844 lpDataDest += lpProps->Value.bin.cb;
845 break;
846 default:
847 if (lpProps->ulPropTag & MV_FLAG)
848 {
849 lpDest->Value.MVi.cValues = lpProps->Value.MVi.cValues;
850 /* Note: Assignment uses lppszA but covers all cases by union aliasing */
851 lpDest->Value.MVszA.lppszA = (char**)lpDataDest;
852
853 switch (PROP_TYPE(lpProps->ulPropTag))
854 {
855 case PT_MV_STRING8:
856 {
857 lpDataDest += lpProps->Value.MVszA.cValues * sizeof(char *);
858
859 for (i = 0; i < lpProps->Value.MVszA.cValues; i++)
860 {
861 ULONG ulStrLen = lstrlenA(lpProps->Value.MVszA.lppszA[i]) + 1u;
862
863 lpDest->Value.MVszA.lppszA[i] = lpDataDest;
864 memcpy(lpDataDest, lpProps->Value.MVszA.lppszA[i], ulStrLen);
865 lpDataDest += ulStrLen;
866 }
867 break;
868 }
869 case PT_MV_UNICODE:
870 {
871 lpDataDest += lpProps->Value.MVszW.cValues * sizeof(WCHAR *);
872
873 for (i = 0; i < lpProps->Value.MVszW.cValues; i++)
874 {
875 ULONG ulStrLen = (strlenW(lpProps->Value.MVszW.lppszW[i]) + 1u) * sizeof(WCHAR);
876
877 lpDest->Value.MVszW.lppszW[i] = (LPWSTR)lpDataDest;
878 memcpy(lpDataDest, lpProps->Value.MVszW.lppszW[i], ulStrLen);
879 lpDataDest += ulStrLen;
880 }
881 break;
882 }
883 case PT_MV_BINARY:
884 {
885 lpDataDest += lpProps->Value.MVszW.cValues * sizeof(SBinary);
886
887 for (i = 0; i < lpProps->Value.MVszW.cValues; i++)
888 {
889 lpDest->Value.MVbin.lpbin[i].cb = lpProps->Value.MVbin.lpbin[i].cb;
890 lpDest->Value.MVbin.lpbin[i].lpb = (LPBYTE)lpDataDest;
891 memcpy(lpDataDest, lpProps->Value.MVbin.lpbin[i].lpb, lpDest->Value.MVbin.lpbin[i].cb);
892 lpDataDest += lpDest->Value.MVbin.lpbin[i].cb;
893 }
894 break;
895 }
896 default:
897 /* No embedded pointers, just copy the data over */
898 ulLen = UlPropSize(lpProps);
899 memcpy(lpDest->Value.MVi.lpi, lpProps->Value.MVi.lpi, ulLen);
900 lpDataDest += ulLen;
901 break;
902 }
903 break;
904 }
905 }
906 lpDest++;
907 lpProps++;
908 }
909 if (lpCount)
910 *lpCount = lpDataDest - (char *)lpDst;
911
912 return S_OK;
913 }
914
915 /*************************************************************************
916 * ScRelocProps@20 (MAPI32.172)
917 *
918 * Relocate the pointers in an array of property values after it has been copied.
919 *
920 * PARAMS
921 * cValues [I] Number of properties in lpProps
922 * lpProps [O] Property array to relocate the pointers in.
923 * lpOld [I] Position where the data was copied from
924 * lpNew [I] Position where the data was copied to
925 * lpCount [O] If non-NULL, destination for the number of bytes of data at lpDst
926 *
927 * RETURNS
928 * Success: S_OK. Any pointers in lpProps are relocated.
929 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
930 *
931 * NOTES
932 * MSDN states that this function can be used for serialisation by passing
933 * NULL as either lpOld or lpNew, thus converting any pointers in lpProps
934 * between offsets and pointers. This does not work in native (it crashes),
935 * and cannot be made to work in Wine because the original interface design
936 * is deficient. The only use left for this function is to remap pointers
937 * in a contiguous property array that has been copied with memcpy() to
938 * another memory location.
939 */
940 SCODE WINAPI ScRelocProps(int cValues, LPSPropValue lpProps, LPVOID lpOld,
941 LPVOID lpNew, ULONG *lpCount)
942 {
943 static const BOOL bBadPtr = TRUE; /* Windows bug - Assumes source is bad */
944 LPSPropValue lpDest = lpProps;
945 ULONG ulCount = cValues * sizeof(SPropValue);
946 ULONG ulLen, i;
947 int iter;
948
949 TRACE("(%d,%p,%p,%p,%p)\n", cValues, lpProps, lpOld, lpNew, lpCount);
950
951 if (!lpProps || cValues < 0 || !lpOld || !lpNew)
952 return MAPI_E_INVALID_PARAMETER;
953
954 /* The reason native doesn't work as MSDN states is that it assumes that
955 * the lpProps pointer contains valid pointers. This is obviously not
956 * true if the array is being read back from serialisation (the pointers
957 * are just offsets). Native can't actually work converting the pointers to
958 * offsets either, because it converts any array pointers to offsets then
959 * _dereferences the offset_ in order to convert the array elements!
960 *
961 * The code below would handle both cases except that the design of this
962 * function makes it impossible to know when the pointers in lpProps are
963 * valid. If both lpOld and lpNew are non-NULL, native reads the pointers
964 * after converting them, so we must do the same. It seems this
965 * functionality was never tested by MS.
966 */
967
968 #define RELOC_PTR(p) (((char*)(p)) - (char*)lpOld + (char*)lpNew)
969
970 for (iter = 0; iter < cValues; iter++)
971 {
972 switch (PROP_TYPE(lpDest->ulPropTag))
973 {
974 case PT_CLSID:
975 lpDest->Value.lpguid = (LPGUID)RELOC_PTR(lpDest->Value.lpguid);
976 ulCount += sizeof(GUID);
977 break;
978 case PT_STRING8:
979 ulLen = bBadPtr ? 0 : lstrlenA(lpDest->Value.lpszA) + 1u;
980 lpDest->Value.lpszA = RELOC_PTR(lpDest->Value.lpszA);
981 if (bBadPtr)
982 ulLen = lstrlenA(lpDest->Value.lpszA) + 1u;
983 ulCount += ulLen;
984 break;
985 case PT_UNICODE:
986 ulLen = bBadPtr ? 0 : (lstrlenW(lpDest->Value.lpszW) + 1u) * sizeof(WCHAR);
987 lpDest->Value.lpszW = (LPWSTR)RELOC_PTR(lpDest->Value.lpszW);
988 if (bBadPtr)
989 ulLen = (strlenW(lpDest->Value.lpszW) + 1u) * sizeof(WCHAR);
990 ulCount += ulLen;
991 break;
992 case PT_BINARY:
993 lpDest->Value.bin.lpb = (LPBYTE)RELOC_PTR(lpDest->Value.bin.lpb);
994 ulCount += lpDest->Value.bin.cb;
995 break;
996 default:
997 if (lpDest->ulPropTag & MV_FLAG)
998 {
999 /* Since we have to access the array elements, don't map the
1000 * array unless it is invalid (otherwise, map it at the end)
1001 */
1002 if (bBadPtr)
1003 lpDest->Value.MVszA.lppszA = (LPSTR*)RELOC_PTR(lpDest->Value.MVszA.lppszA);
1004
1005 switch (PROP_TYPE(lpProps->ulPropTag))
1006 {
1007 case PT_MV_STRING8:
1008 {
1009 ulCount += lpDest->Value.MVszA.cValues * sizeof(char *);
1010
1011 for (i = 0; i < lpDest->Value.MVszA.cValues; i++)
1012 {
1013 ULONG ulStrLen = bBadPtr ? 0 : lstrlenA(lpDest->Value.MVszA.lppszA[i]) + 1u;
1014
1015 lpDest->Value.MVszA.lppszA[i] = RELOC_PTR(lpDest->Value.MVszA.lppszA[i]);
1016 if (bBadPtr)
1017 ulStrLen = lstrlenA(lpDest->Value.MVszA.lppszA[i]) + 1u;
1018 ulCount += ulStrLen;
1019 }
1020 break;
1021 }
1022 case PT_MV_UNICODE:
1023 {
1024 ulCount += lpDest->Value.MVszW.cValues * sizeof(WCHAR *);
1025
1026 for (i = 0; i < lpDest->Value.MVszW.cValues; i++)
1027 {
1028 ULONG ulStrLen = bBadPtr ? 0 : (strlenW(lpDest->Value.MVszW.lppszW[i]) + 1u) * sizeof(WCHAR);
1029
1030 lpDest->Value.MVszW.lppszW[i] = (LPWSTR)RELOC_PTR(lpDest->Value.MVszW.lppszW[i]);
1031 if (bBadPtr)
1032 ulStrLen = (strlenW(lpDest->Value.MVszW.lppszW[i]) + 1u) * sizeof(WCHAR);
1033 ulCount += ulStrLen;
1034 }
1035 break;
1036 }
1037 case PT_MV_BINARY:
1038 {
1039 ulCount += lpDest->Value.MVszW.cValues * sizeof(SBinary);
1040
1041 for (i = 0; i < lpDest->Value.MVszW.cValues; i++)
1042 {
1043 lpDest->Value.MVbin.lpbin[i].lpb = (LPBYTE)RELOC_PTR(lpDest->Value.MVbin.lpbin[i].lpb);
1044 ulCount += lpDest->Value.MVbin.lpbin[i].cb;
1045 }
1046 break;
1047 }
1048 default:
1049 ulCount += UlPropSize(lpDest);
1050 break;
1051 }
1052 if (!bBadPtr)
1053 lpDest->Value.MVszA.lppszA = (LPSTR*)RELOC_PTR(lpDest->Value.MVszA.lppszA);
1054 break;
1055 }
1056 }
1057 lpDest++;
1058 }
1059 if (lpCount)
1060 *lpCount = ulCount;
1061
1062 return S_OK;
1063 }
1064
1065 /*************************************************************************
1066 * LpValFindProp@12 (MAPI32.173)
1067 *
1068 * Find a property with a given property id in a property array.
1069 *
1070 * PARAMS
1071 * ulPropTag [I] Property tag containing property id to find
1072 * cValues [I] Number of properties in lpProps
1073 * lpProps [I] Property array to search
1074 *
1075 * RETURNS
1076 * A pointer to the matching property, or NULL if none was found.
1077 *
1078 * NOTES
1079 * This function matches only on the property id and does not care if the
1080 * property types differ.
1081 */
1082 LPSPropValue WINAPI LpValFindProp(ULONG ulPropTag, ULONG cValues, LPSPropValue lpProps)
1083 {
1084 TRACE("(%d,%d,%p)\n", ulPropTag, cValues, lpProps);
1085
1086 if (lpProps && cValues)
1087 {
1088 ULONG i;
1089 for (i = 0; i < cValues; i++)
1090 {
1091 if (PROP_ID(ulPropTag) == PROP_ID(lpProps[i].ulPropTag))
1092 return &lpProps[i];
1093 }
1094 }
1095 return NULL;
1096 }
1097
1098 /*************************************************************************
1099 * ScDupPropset@16 (MAPI32.174)
1100 *
1101 * Duplicate a property value array into a contiguous block of memory.
1102 *
1103 * PARAMS
1104 * cValues [I] Number of properties in lpProps
1105 * lpProps [I] Property array to duplicate
1106 * lpAlloc [I] Memory allocation function, use MAPIAllocateBuffer()
1107 * lpNewProp [O] Destination for the newly duplicated property value array
1108 *
1109 * RETURNS
1110 * Success: S_OK. *lpNewProp contains the duplicated array.
1111 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid,
1112 * MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails.
1113 */
1114 SCODE WINAPI ScDupPropset(int cValues, LPSPropValue lpProps,
1115 LPALLOCATEBUFFER lpAlloc, LPSPropValue *lpNewProp)
1116 {
1117 ULONG ulCount;
1118 SCODE sc;
1119
1120 TRACE("(%d,%p,%p,%p)\n", cValues, lpProps, lpAlloc, lpNewProp);
1121
1122 sc = ScCountProps(cValues, lpProps, &ulCount);
1123 if (SUCCEEDED(sc))
1124 {
1125 sc = lpAlloc(ulCount, (LPVOID*)lpNewProp);
1126 if (SUCCEEDED(sc))
1127 sc = ScCopyProps(cValues, lpProps, *lpNewProp, &ulCount);
1128 }
1129 return sc;
1130 }
1131
1132 /*************************************************************************
1133 * FBadRglpszA@8 (MAPI32.175)
1134 *
1135 * Determine if an array of strings is invalid
1136 *
1137 * PARAMS
1138 * lppszStrs [I] Array of strings to check
1139 * ulCount [I] Number of strings in lppszStrs
1140 *
1141 * RETURNS
1142 * TRUE, if lppszStrs is invalid, FALSE otherwise.
1143 */
1144 BOOL WINAPI FBadRglpszA(LPSTR *lppszStrs, ULONG ulCount)
1145 {
1146 ULONG i;
1147
1148 TRACE("(%p,%d)\n", lppszStrs, ulCount);
1149
1150 if (!ulCount)
1151 return FALSE;
1152
1153 if (!lppszStrs || IsBadReadPtr(lppszStrs, ulCount * sizeof(LPWSTR)))
1154 return TRUE;
1155
1156 for (i = 0; i < ulCount; i++)
1157 {
1158 if (!lppszStrs[i] || IsBadStringPtrA(lppszStrs[i], -1))
1159 return TRUE;
1160 }
1161 return FALSE;
1162 }
1163
1164 /*************************************************************************
1165 * FBadRglpszW@8 (MAPI32.176)
1166 *
1167 * See FBadRglpszA.
1168 */
1169 BOOL WINAPI FBadRglpszW(LPWSTR *lppszStrs, ULONG ulCount)
1170 {
1171 ULONG i;
1172
1173 TRACE("(%p,%d)\n", lppszStrs, ulCount);
1174
1175 if (!ulCount)
1176 return FALSE;
1177
1178 if (!lppszStrs || IsBadReadPtr(lppszStrs, ulCount * sizeof(LPWSTR)))
1179 return TRUE;
1180
1181 for (i = 0; i < ulCount; i++)
1182 {
1183 if (!lppszStrs[i] || IsBadStringPtrW(lppszStrs[i], -1))
1184 return TRUE;
1185 }
1186 return FALSE;
1187 }
1188
1189 /*************************************************************************
1190 * FBadRowSet@4 (MAPI32.177)
1191 *
1192 * Determine if a row is invalid
1193 *
1194 * PARAMS
1195 * lpRow [I] Row to check
1196 *
1197 * RETURNS
1198 * TRUE, if lpRow is invalid, FALSE otherwise.
1199 */
1200 BOOL WINAPI FBadRowSet(LPSRowSet lpRowSet)
1201 {
1202 ULONG i;
1203 TRACE("(%p)\n", lpRowSet);
1204
1205 if (!lpRowSet || IsBadReadPtr(lpRowSet, CbSRowSet(lpRowSet)))
1206 return TRUE;
1207
1208 for (i = 0; i < lpRowSet->cRows; i++)
1209 {
1210 if (FBadRow(&lpRowSet->aRow[i]))
1211 return TRUE;
1212 }
1213 return FALSE;
1214 }
1215
1216 /*************************************************************************
1217 * FBadPropTag@4 (MAPI32.179)
1218 *
1219 * Determine if a property tag is invalid
1220 *
1221 * PARAMS
1222 * ulPropTag [I] Property tag to check
1223 *
1224 * RETURNS
1225 * TRUE, if ulPropTag is invalid, FALSE otherwise.
1226 */
1227 ULONG WINAPI FBadPropTag(ULONG ulPropTag)
1228 {
1229 TRACE("(0x%08x)\n", ulPropTag);
1230
1231 switch (ulPropTag & (~MV_FLAG & PROP_TYPE_MASK))
1232 {
1233 case PT_UNSPECIFIED:
1234 case PT_NULL:
1235 case PT_I2:
1236 case PT_LONG:
1237 case PT_R4:
1238 case PT_DOUBLE:
1239 case PT_CURRENCY:
1240 case PT_APPTIME:
1241 case PT_ERROR:
1242 case PT_BOOLEAN:
1243 case PT_OBJECT:
1244 case PT_I8:
1245 case PT_STRING8:
1246 case PT_UNICODE:
1247 case PT_SYSTIME:
1248 case PT_CLSID:
1249 case PT_BINARY:
1250 return FALSE;
1251 }
1252 return TRUE;
1253 }
1254
1255 /*************************************************************************
1256 * FBadRow@4 (MAPI32.180)
1257 *
1258 * Determine if a row is invalid
1259 *
1260 * PARAMS
1261 * lpRow [I] Row to check
1262 *
1263 * RETURNS
1264 * TRUE, if lpRow is invalid, FALSE otherwise.
1265 */
1266 ULONG WINAPI FBadRow(LPSRow lpRow)
1267 {
1268 ULONG i;
1269 TRACE("(%p)\n", lpRow);
1270
1271 if (!lpRow || IsBadReadPtr(lpRow, sizeof(SRow)) || !lpRow->lpProps ||
1272 IsBadReadPtr(lpRow->lpProps, lpRow->cValues * sizeof(SPropValue)))
1273 return TRUE;
1274
1275 for (i = 0; i < lpRow->cValues; i++)
1276 {
1277 if (FBadProp(&lpRow->lpProps[i]))
1278 return TRUE;
1279 }
1280 return FALSE;
1281 }
1282
1283 /*************************************************************************
1284 * FBadProp@4 (MAPI32.181)
1285 *
1286 * Determine if a property is invalid
1287 *
1288 * PARAMS
1289 * lpProp [I] Property to check
1290 *
1291 * RETURNS
1292 * TRUE, if lpProp is invalid, FALSE otherwise.
1293 */
1294 ULONG WINAPI FBadProp(LPSPropValue lpProp)
1295 {
1296 if (!lpProp || IsBadReadPtr(lpProp, sizeof(SPropValue)) ||
1297 FBadPropTag(lpProp->ulPropTag))
1298 return TRUE;
1299
1300 switch (PROP_TYPE(lpProp->ulPropTag))
1301 {
1302 /* Single value properties containing pointers */
1303 case PT_STRING8:
1304 if (!lpProp->Value.lpszA || IsBadStringPtrA(lpProp->Value.lpszA, -1))
1305 return TRUE;
1306 break;
1307 case PT_UNICODE:
1308 if (!lpProp->Value.lpszW || IsBadStringPtrW(lpProp->Value.lpszW, -1))
1309 return TRUE;
1310 break;
1311 case PT_BINARY:
1312 if (IsBadReadPtr(lpProp->Value.bin.lpb, lpProp->Value.bin.cb))
1313 return TRUE;
1314 break;
1315 case PT_CLSID:
1316 if (IsBadReadPtr(lpProp->Value.lpguid, sizeof(GUID)))
1317 return TRUE;
1318 break;
1319
1320 /* Multiple value properties (arrays) containing no pointers */
1321 case PT_MV_I2:
1322 return PROP_BadArray(lpProp, sizeof(SHORT));
1323 case PT_MV_LONG:
1324 return PROP_BadArray(lpProp, sizeof(LONG));
1325 case PT_MV_LONGLONG:
1326 return PROP_BadArray(lpProp, sizeof(LONG64));
1327 case PT_MV_FLOAT:
1328 return PROP_BadArray(lpProp, sizeof(float));
1329 case PT_MV_SYSTIME:
1330 return PROP_BadArray(lpProp, sizeof(FILETIME));
1331 case PT_MV_APPTIME:
1332 case PT_MV_DOUBLE:
1333 return PROP_BadArray(lpProp, sizeof(double));
1334 case PT_MV_CURRENCY:
1335 return PROP_BadArray(lpProp, sizeof(CY));
1336 case PT_MV_CLSID:
1337 return PROP_BadArray(lpProp, sizeof(GUID));
1338
1339 /* Multiple value properties containing pointers */
1340 case PT_MV_STRING8:
1341 return FBadRglpszA(lpProp->Value.MVszA.lppszA,
1342 lpProp->Value.MVszA.cValues);
1343 case PT_MV_UNICODE:
1344 return FBadRglpszW(lpProp->Value.MVszW.lppszW,
1345 lpProp->Value.MVszW.cValues);
1346 case PT_MV_BINARY:
1347 return FBadEntryList(&lpProp->Value.MVbin);
1348 }
1349 return FALSE;
1350 }
1351
1352 /*************************************************************************
1353 * FBadColumnSet@4 (MAPI32.182)
1354 *
1355 * Determine if an array of property tags is invalid
1356 *
1357 * PARAMS
1358 * lpCols [I] Property tag array to check
1359 *
1360 * RETURNS
1361 * TRUE, if lpCols is invalid, FALSE otherwise.
1362 */
1363 ULONG WINAPI FBadColumnSet(LPSPropTagArray lpCols)
1364 {
1365 ULONG ulRet = FALSE, i;
1366
1367 TRACE("(%p)\n", lpCols);
1368
1369 if (!lpCols || IsBadReadPtr(lpCols, CbSPropTagArray(lpCols)))
1370 ulRet = TRUE;
1371 else
1372 {
1373 for (i = 0; i < lpCols->cValues; i++)
1374 {
1375 if ((lpCols->aulPropTag[i] & PROP_TYPE_MASK) == PT_ERROR ||
1376 FBadPropTag(lpCols->aulPropTag[i]))
1377 {
1378 ulRet = TRUE;
1379 break;
1380 }
1381 }
1382 }
1383 TRACE("Returning %s\n", ulRet ? "TRUE" : "FALSE");
1384 return ulRet;
1385 }
1386
1387
1388 /**************************************************************************
1389 * IPropData {MAPI32}
1390 *
1391 * A default Mapi interface to provide manipulation of object properties.
1392 *
1393 * DESCRIPTION
1394 * This object provides a default interface suitable in some cases as an
1395 * implementation of the IMAPIProp interface (which has no default
1396 * implementation). In addition to the IMAPIProp() methods inherited, this
1397 * interface allows read/write control over access to the object and its
1398 * individual properties.
1399 *
1400 * To obtain the default implementation of this interface from Mapi, call
1401 * CreateIProp().
1402 *
1403 * METHODS
1404 */
1405
1406 /* A single property in a property data collection */
1407 typedef struct
1408 {
1409 struct list entry;
1410 ULONG ulAccess; /* The property value access level */
1411 LPSPropValue value; /* The property value */
1412 } IPropDataItem, *LPIPropDataItem;
1413
1414 /* The main property data collection structure */
1415 typedef struct
1416 {
1417 IPropData IPropData_iface;
1418 LONG lRef; /* Reference count */
1419 ALLOCATEBUFFER *lpAlloc; /* Memory allocation routine */
1420 ALLOCATEMORE *lpMore; /* Linked memory allocation routine */
1421 FREEBUFFER *lpFree; /* Memory free routine */
1422 ULONG ulObjAccess; /* Object access level */
1423 ULONG ulNumValues; /* Number of items in values list */
1424 struct list values; /* List of property values */
1425 CRITICAL_SECTION cs; /* Lock for thread safety */
1426 } IPropDataImpl;
1427
1428 static inline IPropDataImpl *impl_from_IPropData(IPropData *iface)
1429 {
1430 return CONTAINING_RECORD(iface, IPropDataImpl, IPropData_iface);
1431 }
1432
1433 /* Internal - Get a property value, assumes lock is held */
1434 static IPropDataItem *IMAPIPROP_GetValue(IPropDataImpl *This, ULONG ulPropTag)
1435 {
1436 struct list *cursor;
1437
1438 LIST_FOR_EACH(cursor, &This->values)
1439 {
1440 LPIPropDataItem current = LIST_ENTRY(cursor, IPropDataItem, entry);
1441 /* Note that property types don't have to match, just Id's */
1442 if (PROP_ID(current->value->ulPropTag) == PROP_ID(ulPropTag))
1443 return current;
1444 }
1445 return NULL;
1446 }
1447
1448 /* Internal - Add a new property value, assumes lock is held */
1449 static IPropDataItem *IMAPIPROP_AddValue(IPropDataImpl *This,
1450 LPSPropValue lpProp)
1451 {
1452 LPVOID lpMem;
1453 LPIPropDataItem lpNew;
1454 HRESULT hRet;
1455
1456 hRet = This->lpAlloc(sizeof(IPropDataItem), &lpMem);
1457
1458 if (SUCCEEDED(hRet))
1459 {
1460 lpNew = lpMem;
1461 lpNew->ulAccess = IPROP_READWRITE;
1462
1463 /* Allocate the value separately so we can update it easily */
1464 lpMem = NULL;
1465 hRet = This->lpAlloc(sizeof(SPropValue), &lpMem);
1466 if (SUCCEEDED(hRet))
1467 {
1468 lpNew->value = lpMem;
1469
1470 hRet = PropCopyMore(lpNew->value, lpProp, This->lpMore, lpMem);
1471 if (SUCCEEDED(hRet))
1472 {
1473 list_add_tail(&This->values, &lpNew->entry);
1474 This->ulNumValues++;
1475 return lpNew;
1476 }
1477 This->lpFree(lpNew->value);
1478 }
1479 This->lpFree(lpNew);
1480 }
1481 return NULL;
1482 }
1483
1484 /* Internal - Lock an IPropData object */
1485 static inline void IMAPIPROP_Lock(IPropDataImpl *This)
1486 {
1487 EnterCriticalSection(&This->cs);
1488 }
1489
1490 /* Internal - Unlock an IPropData object */
1491 static inline void IMAPIPROP_Unlock(IPropDataImpl *This)
1492 {
1493 LeaveCriticalSection(&This->cs);
1494 }
1495
1496 /* This one seems to be missing from mapidefs.h */
1497 #define CbNewSPropProblemArray(c) \
1498 (offsetof(SPropProblemArray,aProblem)+(c)*sizeof(SPropProblem))
1499
1500 /**************************************************************************
1501 * IPropData_QueryInterface {MAPI32}
1502 *
1503 * Inherited method from the IUnknown Interface.
1504 * See IUnknown_QueryInterface.
1505 */
1506 static HRESULT WINAPI IPropData_fnQueryInterface(LPPROPDATA iface, REFIID riid, LPVOID *ppvObj)
1507 {
1508 IPropDataImpl *This = impl_from_IPropData(iface);
1509
1510 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppvObj);
1511
1512 if (!ppvObj || !riid)
1513 return MAPI_E_INVALID_PARAMETER;
1514
1515 *ppvObj = NULL;
1516
1517 if(IsEqualIID(riid, &IID_IUnknown) ||
1518 IsEqualIID(riid, &IID_IMAPIProp) ||
1519 IsEqualIID(riid, &IID_IMAPIPropData))
1520 {
1521 *ppvObj = This;
1522 IPropData_AddRef(iface);
1523 TRACE("returning %p\n", *ppvObj);
1524 return S_OK;
1525 }
1526
1527 TRACE("returning E_NOINTERFACE\n");
1528 return MAPI_E_INTERFACE_NOT_SUPPORTED;
1529 }
1530
1531 /**************************************************************************
1532 * IPropData_AddRef {MAPI32}
1533 *
1534 * Inherited method from the IUnknown Interface.
1535 * See IUnknown_AddRef.
1536 */
1537 static ULONG WINAPI IPropData_fnAddRef(LPPROPDATA iface)
1538 {
1539 IPropDataImpl *This = impl_from_IPropData(iface);
1540
1541 TRACE("(%p)->(count before=%u)\n", This, This->lRef);
1542
1543 return InterlockedIncrement(&This->lRef);
1544 }
1545
1546 /**************************************************************************
1547 * IPropData_Release {MAPI32}
1548 *
1549 * Inherited method from the IUnknown Interface.
1550 * See IUnknown_Release.
1551 */
1552 static ULONG WINAPI IPropData_fnRelease(LPPROPDATA iface)
1553 {
1554 IPropDataImpl *This = impl_from_IPropData(iface);
1555 LONG lRef;
1556
1557 TRACE("(%p)->(count before=%u)\n", This, This->lRef);
1558
1559 lRef = InterlockedDecrement(&This->lRef);
1560 if (!lRef)
1561 {
1562 TRACE("Destroying IPropData (%p)\n",This);
1563
1564 /* Note: No need to lock, since no other thread is referencing iface */
1565 while (!list_empty(&This->values))
1566 {
1567 struct list *head = list_head(&This->values);
1568 LPIPropDataItem current = LIST_ENTRY(head, IPropDataItem, entry);
1569 list_remove(head);
1570 This->lpFree(current->value);
1571 This->lpFree(current);
1572 }
1573 This->cs.DebugInfo->Spare[0] = 0;
1574 DeleteCriticalSection(&This->cs);
1575 This->lpFree(This);
1576 }
1577 return (ULONG)lRef;
1578 }
1579
1580 /**************************************************************************
1581 * IPropData_GetLastError {MAPI32}
1582 *
1583 * Get information about the last error that occurred in an IMAPIProp object.
1584 *
1585 * PARAMS
1586 * iface [I] IMAPIProp object that experienced the error
1587 * hRes [I] Result of the call that returned an error
1588 * ulFlags [I] 0=return Ascii strings, MAPI_UNICODE=return Unicode strings
1589 * lppError [O] Destination for detailed error information
1590 *
1591 * RETURNS
1592 * Success: S_OK. *lppError contains details about the last error.
1593 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid,
1594 * MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails.
1595 *
1596 * NOTES
1597 * - If this function succeeds, the returned information in *lppError must be
1598 * freed using MAPIFreeBuffer() once the caller is finished with it.
1599 * - It is possible for this function to succeed and set *lppError to NULL,
1600 * if there is no further information to report about hRes.
1601 */
1602 static HRESULT WINAPI IPropData_fnGetLastError(LPPROPDATA iface, HRESULT hRes, ULONG ulFlags,
1603 LPMAPIERROR *lppError)
1604 {
1605 TRACE("(%p,0x%08X,0x%08X,%p)\n", iface, hRes, ulFlags, lppError);
1606
1607 if (!lppError || SUCCEEDED(hRes) || (ulFlags & ~MAPI_UNICODE))
1608 return MAPI_E_INVALID_PARAMETER;
1609
1610 *lppError = NULL;
1611 return S_OK;
1612 }
1613
1614 /**************************************************************************
1615 * IPropData_SaveChanges {MAPI32}
1616 *
1617 * Update any changes made to a transactional IMAPIProp object.
1618 *
1619 * PARAMS
1620 * iface [I] IMAPIProp object to update
1621 * ulFlags [I] Flags controlling the update.
1622 *
1623 * RETURNS
1624 * Success: S_OK. Any outstanding changes are committed to the object.
1625 * Failure: An HRESULT error code describing the error.
1626 */
1627 static HRESULT WINAPI IPropData_fnSaveChanges(LPPROPDATA iface, ULONG ulFlags)
1628 {
1629 TRACE("(%p,0x%08X)\n", iface, ulFlags);
1630
1631 /* Since this object is not transacted we do not need to implement this */
1632 /* FIXME: Should we set the access levels to clean? */
1633 return S_OK;
1634 }
1635
1636 /**************************************************************************
1637 * IPropData_GetProps {MAPI32}
1638 *
1639 * Get property values from an IMAPIProp object.
1640 *
1641 * PARAMS
1642 * iface [I] IMAPIProp object to get the property values from
1643 * lpTags [I] Property tage of property values to be retrieved
1644 * ulFlags [I] Return 0=Ascii MAPI_UNICODE=Unicode strings for
1645 * unspecified types
1646 * lpCount [O] Destination for number of properties returned
1647 * lppProps [O] Destination for returned property values
1648 *
1649 * RETURNS
1650 * Success: S_OK. *lppProps and *lpCount are updated.
1651 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
1652 * MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails, or
1653 * MAPI_W_ERRORS_RETURNED if not all properties were retrieved
1654 * successfully.
1655 * NOTES
1656 * - If MAPI_W_ERRORS_RETURNED is returned, any properties that could not be
1657 * retrieved from iface are present in lppProps with their type
1658 * changed to PT_ERROR and Id unchanged.
1659 */
1660 static HRESULT WINAPI IPropData_fnGetProps(LPPROPDATA iface, LPSPropTagArray lpTags, ULONG ulFlags,
1661 ULONG *lpCount, LPSPropValue *lppProps)
1662 {
1663 IPropDataImpl *This = impl_from_IPropData(iface);
1664 ULONG i;
1665 HRESULT hRet = S_OK;
1666
1667 TRACE("(%p,%p,0x%08x,%p,%p) stub\n", iface, lpTags, ulFlags,
1668 lpCount, lppProps);
1669
1670 if (!iface || ulFlags & ~MAPI_UNICODE || !lpTags || *lpCount || !lppProps)
1671 return MAPI_E_INVALID_PARAMETER;
1672
1673 FIXME("semi-stub, flags not supported\n");
1674
1675 *lpCount = lpTags->cValues;
1676 *lppProps = NULL;
1677
1678 if (*lpCount)
1679 {
1680 hRet = MAPIAllocateBuffer(*lpCount * sizeof(SPropValue), (LPVOID*)lppProps);
1681 if (FAILED(hRet))
1682 return hRet;
1683
1684 IMAPIPROP_Lock(This);
1685
1686 for (i = 0; i < lpTags->cValues; i++)
1687 {
1688 HRESULT hRetTmp = E_INVALIDARG;
1689 LPIPropDataItem item;
1690
1691 item = IMAPIPROP_GetValue(This, lpTags->aulPropTag[i]);
1692
1693 if (item)
1694 hRetTmp = PropCopyMore(&(*lppProps)[i], item->value,
1695 This->lpMore, *lppProps);
1696 if (FAILED(hRetTmp))
1697 {
1698 hRet = MAPI_W_ERRORS_RETURNED;
1699 (*lppProps)[i].ulPropTag =
1700 CHANGE_PROP_TYPE(lpTags->aulPropTag[i], PT_ERROR);
1701 }
1702 }
1703
1704 IMAPIPROP_Unlock(This);
1705 }
1706 return hRet;
1707 }
1708
1709 /**************************************************************************
1710 * MAPIProp_GetPropList {MAPI32}
1711 *
1712 * Get the list of property tags for all values in an IMAPIProp object.
1713 *
1714 * PARAMS
1715 * iface [I] IMAPIProp object to get the property tag list from
1716 * ulFlags [I] Return 0=Ascii MAPI_UNICODE=Unicode strings for
1717 * unspecified types
1718 * lppTags [O] Destination for the retrieved property tag list
1719 *
1720 * RETURNS
1721 * Success: S_OK. *lppTags contains the tags for all available properties.
1722 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
1723 * MAPI_E_BAD_CHARWIDTH, if Ascii or Unicode strings are requested
1724 * and that type of string is not supported.
1725 */
1726 static HRESULT WINAPI IPropData_fnGetPropList(LPPROPDATA iface, ULONG ulFlags,
1727 LPSPropTagArray *lppTags)
1728 {
1729 IPropDataImpl *This = impl_from_IPropData(iface);
1730 ULONG i;
1731 HRESULT hRet;
1732
1733 TRACE("(%p,0x%08x,%p) stub\n", iface, ulFlags, lppTags);
1734
1735 if (!iface || ulFlags & ~MAPI_UNICODE || !lppTags)
1736 return MAPI_E_INVALID_PARAMETER;
1737
1738 FIXME("semi-stub, flags not supported\n");
1739
1740 *lppTags = NULL;
1741
1742 IMAPIPROP_Lock(This);
1743
1744 hRet = MAPIAllocateBuffer(CbNewSPropTagArray(This->ulNumValues),
1745 (LPVOID*)lppTags);
1746 if (SUCCEEDED(hRet))
1747 {
1748 struct list *cursor;
1749
1750 i = 0;
1751 LIST_FOR_EACH(cursor, &This->values)
1752 {
1753 LPIPropDataItem current = LIST_ENTRY(cursor, IPropDataItem, entry);
1754 (*lppTags)->aulPropTag[i] = current->value->ulPropTag;
1755 i++;
1756 }
1757 (*lppTags)->cValues = This->ulNumValues;
1758 }
1759
1760 IMAPIPROP_Unlock(This);
1761 return hRet;
1762 }
1763
1764 /**************************************************************************
1765 * IPropData_OpenProperty {MAPI32}
1766 *
1767 * Not documented at this time.
1768 *
1769 * RETURNS
1770 * An HRESULT success/failure code.
1771 */
1772 static HRESULT WINAPI IPropData_fnOpenProperty(LPPROPDATA iface, ULONG ulPropTag, LPCIID iid,
1773 ULONG ulOpts, ULONG ulFlags, LPUNKNOWN *lpUnk)
1774 {
1775 FIXME("(%p,%u,%s,%u,0x%08x,%p) stub\n", iface, ulPropTag,
1776 debugstr_guid(iid), ulOpts, ulFlags, lpUnk);
1777 return MAPI_E_NO_SUPPORT;
1778 }
1779
1780
1781 /**************************************************************************
1782 * IPropData_SetProps {MAPI32}
1783 *
1784 * Add or edit the property values in an IMAPIProp object.
1785 *
1786 * PARAMS
1787 * iface [I] IMAPIProp object to get the property tag list from
1788 * ulValues [I] Number of properties in lpProps
1789 * lpProps [I] Property values to set
1790 * lppProbs [O] Optional destination for any problems that occurred
1791 *
1792 * RETURNS
1793 * Success: S_OK. The properties in lpProps are added to iface if they don't
1794 * exist, or changed to the values in lpProps if they do
1795 * Failure: An HRESULT error code describing the error
1796 */
1797 static HRESULT WINAPI IPropData_fnSetProps(LPPROPDATA iface, ULONG ulValues, LPSPropValue lpProps,
1798 LPSPropProblemArray *lppProbs)
1799 {
1800 IPropDataImpl *This = impl_from_IPropData(iface);
1801 HRESULT hRet = S_OK;
1802 ULONG i;
1803
1804 TRACE("(%p,%u,%p,%p)\n", iface, ulValues, lpProps, lppProbs);
1805
1806 if (!iface || !lpProps)
1807 return MAPI_E_INVALID_PARAMETER;
1808
1809 for (i = 0; i < ulValues; i++)
1810 {
1811 if (FBadProp(&lpProps[i]) ||
1812 PROP_TYPE(lpProps[i].ulPropTag) == PT_OBJECT ||
1813 PROP_TYPE(lpProps[i].ulPropTag) == PT_NULL)
1814 return MAPI_E_INVALID_PARAMETER;
1815 }
1816
1817 IMAPIPROP_Lock(This);
1818
1819 /* FIXME: Under what circumstances is lpProbs created? */
1820 for (i = 0; i < ulValues; i++)
1821 {
1822 LPIPropDataItem item = IMAPIPROP_GetValue(This, lpProps[i].ulPropTag);
1823
1824 if (item)
1825 {
1826 HRESULT hRetTmp;
1827 LPVOID lpMem = NULL;
1828
1829 /* Found, so update the existing value */
1830 if (item->value->ulPropTag != lpProps[i].ulPropTag)
1831 FIXME("semi-stub, overwriting type (not coercing)\n");
1832
1833 hRetTmp = This->lpAlloc(sizeof(SPropValue), &lpMem);
1834 if (SUCCEEDED(hRetTmp))
1835 {
1836 hRetTmp = PropCopyMore(lpMem, &lpProps[i], This->lpMore, lpMem);
1837 if (SUCCEEDED(hRetTmp))
1838 {
1839 This->lpFree(item->value);
1840 item->value = lpMem;
1841 continue;
1842 }
1843 This->lpFree(lpMem);
1844 }
1845 hRet = hRetTmp;
1846 }
1847 else
1848 {
1849 /* Add new value */
1850 if (!IMAPIPROP_AddValue(This, &lpProps[i]))
1851 hRet = MAPI_E_NOT_ENOUGH_MEMORY;
1852 }
1853 }
1854
1855 IMAPIPROP_Unlock(This);
1856 return hRet;
1857 }
1858
1859 /**************************************************************************
1860 * IPropData_DeleteProps {MAPI32}
1861 *
1862 * Delete one or more property values from an IMAPIProp object.
1863 *
1864 * PARAMS
1865 * iface [I] IMAPIProp object to remove property values from.
1866 * lpTags [I] Collection of property Id's to remove from iface.
1867 * lppProbs [O] Destination for problems encountered, if any.
1868 *
1869 * RETURNS
1870 * Success: S_OK. Any properties in iface matching property Id's in lpTags have
1871 * been deleted. If lppProbs is non-NULL it contains details of any
1872 * errors that occurred.
1873 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
1874 * E_ACCESSDENIED, if this object was created using CreateIProp() and
1875 * a subsequent call to IPropData_SetObjAccess() was made specifying
1876 * IPROP_READONLY as the access type.
1877 *
1878 * NOTES
1879 * - lppProbs will not be populated for cases where a property Id is present
1880 * in lpTags but not in iface.
1881 * - lppProbs should be deleted with MAPIFreeBuffer() if returned.
1882 */
1883 static HRESULT WINAPI IPropData_fnDeleteProps(LPPROPDATA iface, LPSPropTagArray lpTags,
1884 LPSPropProblemArray *lppProbs)
1885 {
1886 IPropDataImpl *This = impl_from_IPropData(iface);
1887 ULONG i, numProbs = 0;
1888 HRESULT hRet = S_OK;
1889
1890 TRACE("(%p,%p,%p)\n", iface, lpTags, lppProbs);
1891
1892 if (!iface || !lpTags)
1893 return MAPI_E_INVALID_PARAMETER;
1894
1895 if (lppProbs)
1896 *lppProbs = NULL;
1897
1898 for (i = 0; i < lpTags->cValues; i++)
1899 {
1900 if (FBadPropTag(lpTags->aulPropTag[i]) ||
1901 PROP_TYPE(lpTags->aulPropTag[i]) == PT_OBJECT ||
1902 PROP_TYPE(lpTags->aulPropTag[i]) == PT_NULL)
1903 return MAPI_E_INVALID_PARAMETER;
1904 }
1905
1906 IMAPIPROP_Lock(This);
1907
1908 if (This->ulObjAccess != IPROP_READWRITE)
1909 {
1910 IMAPIPROP_Unlock(This);
1911 return E_ACCESSDENIED;
1912 }
1913
1914 for (i = 0; i < lpTags->cValues; i++)
1915 {
1916 LPIPropDataItem item = IMAPIPROP_GetValue(This, lpTags->aulPropTag[i]);
1917
1918 if (item)
1919 {
1920 if (item->ulAccess & IPROP_READWRITE)
1921 {
1922 /* Everything hunky-dory, remove the item */
1923 list_remove(&item->entry);
1924 This->lpFree(item->value); /* Also frees value pointers */
1925 This->lpFree(item);
1926 This->ulNumValues--;
1927 }
1928 else if (lppProbs)
1929 {
1930 /* Can't write the value. Create/populate problems array */
1931 if (!*lppProbs)
1932 {
1933 /* Create problems array */
1934 ULONG ulSize = CbNewSPropProblemArray(lpTags->cValues - i);
1935 HRESULT hRetTmp = MAPIAllocateBuffer(ulSize, (LPVOID*)lppProbs);
1936 if (FAILED(hRetTmp))
1937 hRet = hRetTmp;
1938 }
1939 if (*lppProbs)
1940 {
1941 LPSPropProblem lpProb = &(*lppProbs)->aProblem[numProbs];
1942 lpProb->ulIndex = i;
1943 lpProb->ulPropTag = lpTags->aulPropTag[i];
1944 lpProb->scode = E_ACCESSDENIED;
1945 numProbs++;
1946 }
1947 }
1948 }
1949 }
1950 if (lppProbs && *lppProbs)
1951 (*lppProbs)->cProblem = numProbs;
1952
1953 IMAPIPROP_Unlock(This);
1954 return hRet;
1955 }
1956
1957
1958 /**************************************************************************
1959 * IPropData_CopyTo {MAPI32}
1960 *
1961 * Not documented at this time.
1962 *
1963 * RETURNS
1964 * An HRESULT success/failure code.
1965 */
1966 static HRESULT WINAPI IPropData_fnCopyTo(LPPROPDATA iface, ULONG niids, LPCIID lpiidExcl,
1967 LPSPropTagArray lpPropsExcl, ULONG ulParam,
1968 LPMAPIPROGRESS lpIProgress, LPCIID lpIfaceIid,
1969 LPVOID lpDstObj, ULONG ulFlags,
1970 LPSPropProblemArray *lppProbs)
1971 {
1972 FIXME("(%p,%u,%p,%p,%x,%p,%s,%p,0x%08X,%p) stub\n", iface, niids,
1973 lpiidExcl, lpPropsExcl, ulParam, lpIProgress,
1974 debugstr_guid(lpIfaceIid), lpDstObj, ulFlags, lppProbs);
1975 return MAPI_E_NO_SUPPORT;
1976 }
1977
1978 /**************************************************************************
1979 * IPropData_CopyProps {MAPI32}
1980 *
1981 * Not documented at this time.
1982 *
1983 * RETURNS
1984 * An HRESULT success/failure code.
1985 */
1986 static HRESULT WINAPI IPropData_fnCopyProps(LPPROPDATA iface, LPSPropTagArray lpInclProps,
1987 ULONG ulParam, LPMAPIPROGRESS lpIProgress,
1988 LPCIID lpIface, LPVOID lpDstObj, ULONG ulFlags,
1989 LPSPropProblemArray *lppProbs)
1990 {
1991 FIXME("(%p,%p,%x,%p,%s,%p,0x%08X,%p) stub\n", iface, lpInclProps,
1992 ulParam, lpIProgress, debugstr_guid(lpIface), lpDstObj, ulFlags,
1993 lppProbs);
1994 return MAPI_E_NO_SUPPORT;
1995 }
1996
1997 /**************************************************************************
1998 * IPropData_GetNamesFromIDs {MAPI32}
1999 *
2000 * Get the names of properties from their identifiers.
2001 *
2002 * PARAMS
2003 * iface [I] IMAPIProp object to operate on
2004 * lppPropTags [I/O] Property identifiers to get the names for, or NULL to
2005 * get all names
2006 * iid [I] Property set identifier, or NULL
2007 * ulFlags [I] MAPI_NO_IDS=Don't return numeric named properties,
2008 * or MAPI_NO_STRINGS=Don't return strings
2009 * lpCount [O] Destination for number of properties returned
2010 * lpppNames [O] Destination for returned names
2011 *
2012 * RETURNS
2013 * Success: S_OK. *lppPropTags and lpppNames contain the returned
2014 * name/identifiers.
2015 * Failure: MAPI_E_NO_SUPPORT, if the object does not support named properties,
2016 * MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails, or
2017 * MAPI_W_ERRORS_RETURNED if not all properties were retrieved
2018 * successfully.
2019 */
2020 static HRESULT WINAPI IPropData_fnGetNamesFromIDs(LPPROPDATA iface, LPSPropTagArray *lppPropTags,
2021 LPGUID iid, ULONG ulFlags, ULONG *lpCount,
2022 LPMAPINAMEID **lpppNames)
2023 {
2024 FIXME("(%p,%p,%s,0x%08X,%p,%p) stub\n", iface, lppPropTags,
2025 debugstr_guid(iid), ulFlags, lpCount, lpppNames);
2026 return MAPI_E_NO_SUPPORT;
2027 }
2028
2029 /**************************************************************************
2030 * IPropData_GetIDsFromNames {MAPI32}
2031 *
2032 * Get property identifiers associated with one or more named properties.
2033 *
2034 * PARAMS
2035 * iface [I] IMAPIProp object to operate on
2036 * ulNames [I] Number of names in lppNames
2037 * lppNames [I] Names to query or create, or NULL to query all names
2038 * ulFlags [I] Pass MAPI_CREATE to create new named properties
2039 * lppPropTags [O] Destination for queried or created property identifiers
2040 *
2041 * RETURNS
2042 * Success: S_OK. *lppPropTags contains the property tags created or requested.
2043 * Failure: MAPI_E_NO_SUPPORT, if the object does not support named properties,
2044 * MAPI_E_TOO_BIG, if the object cannot process the number of
2045 * properties involved.
2046 * MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails, or
2047 * MAPI_W_ERRORS_RETURNED if not all properties were retrieved
2048 * successfully.
2049 */
2050 static HRESULT WINAPI IPropData_fnGetIDsFromNames(LPPROPDATA iface, ULONG ulNames,
2051 LPMAPINAMEID *lppNames, ULONG ulFlags,
2052 LPSPropTagArray *lppPropTags)
2053 {
2054 FIXME("(%p,%d,%p,0x%08X,%p) stub\n",
2055 iface, ulNames, lppNames, ulFlags, lppPropTags);
2056 return MAPI_E_NO_SUPPORT;
2057 }
2058
2059 /**************************************************************************
2060 * IPropData_HrSetObjAccess {MAPI32}
2061 *
2062 * Set the access level of an IPropData object.
2063 *
2064 * PARAMS
2065 * iface [I] IPropData object to set the access on
2066 * ulAccess [I] Either IPROP_READONLY or IPROP_READWRITE for read or
2067 * read/write access respectively.
2068 *
2069 * RETURNS
2070 * Success: S_OK. The objects access level is changed.
2071 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
2072 */
2073 static HRESULT WINAPI
2074 IPropData_fnHrSetObjAccess(LPPROPDATA iface, ULONG ulAccess)
2075 {
2076 IPropDataImpl *This = impl_from_IPropData(iface);
2077
2078 TRACE("(%p,%x)\n", iface, ulAccess);
2079
2080 if (!iface || ulAccess < IPROP_READONLY || ulAccess > IPROP_READWRITE)
2081 return MAPI_E_INVALID_PARAMETER;
2082
2083 IMAPIPROP_Lock(This);
2084
2085 This->ulObjAccess = ulAccess;
2086
2087 IMAPIPROP_Unlock(This);
2088 return S_OK;
2089 }
2090
2091 /* Internal - determine if an access value is bad */
2092 static inline BOOL PROP_IsBadAccess(ULONG ulAccess)
2093 {
2094 switch (ulAccess)
2095 {
2096 case IPROP_READONLY|IPROP_CLEAN:
2097 case IPROP_READONLY|IPROP_DIRTY:
2098 case IPROP_READWRITE|IPROP_CLEAN:
2099 case IPROP_READWRITE|IPROP_DIRTY:
2100 return FALSE;
2101 }
2102 return TRUE;
2103 }
2104
2105 /**************************************************************************
2106 * IPropData_HrSetPropAccess {MAPI32}
2107 *
2108 * Set the access levels for a group of property values in an IPropData object.
2109 *
2110 * PARAMS
2111 * iface [I] IPropData object to set access levels in.
2112 * lpTags [I] List of property Id's to set access for.
2113 * lpAccess [O] Access level for each property in lpTags.
2114 *
2115 * RETURNS
2116 * Success: S_OK. The access level of each property value in lpTags that is
2117 * present in iface is changed.
2118 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
2119 *
2120 * NOTES
2121 * - Each access level in lpAccess must contain at least one of IPROP_READONLY
2122 * or IPROP_READWRITE, but not both, and also IPROP_CLEAN or IPROP_DIRTY,
2123 * but not both. No other bits should be set.
2124 * - If a property Id in lpTags is not present in iface, it is ignored.
2125 */
2126 static HRESULT WINAPI
2127 IPropData_fnHrSetPropAccess(LPPROPDATA iface, LPSPropTagArray lpTags,
2128 ULONG *lpAccess)
2129 {
2130 IPropDataImpl *This = impl_from_IPropData(iface);
2131 ULONG i;
2132
2133 TRACE("(%p,%p,%p)\n", iface, lpTags, lpAccess);
2134
2135 if (!iface || !lpTags || !lpAccess)
2136 return MAPI_E_INVALID_PARAMETER;
2137
2138 for (i = 0; i < lpTags->cValues; i++)
2139 {
2140 if (FBadPropTag(lpTags->aulPropTag[i]) || PROP_IsBadAccess(lpAccess[i]))
2141 return MAPI_E_INVALID_PARAMETER;
2142 }
2143
2144 IMAPIPROP_Lock(This);
2145
2146 for (i = 0; i < lpTags->cValues; i++)
2147 {
2148 LPIPropDataItem item = IMAPIPROP_GetValue(This, lpTags->aulPropTag[i]);
2149
2150 if (item)
2151 item->ulAccess = lpAccess[i];
2152 }
2153
2154 IMAPIPROP_Unlock(This);
2155 return S_OK;
2156 }
2157
2158 /**************************************************************************
2159 * IPropData_HrGetPropAccess {MAPI32}
2160 *
2161 * Get the access levels for a group of property values in an IPropData object.
2162 *
2163 * PARAMS
2164 * iface [I] IPropData object to get access levels from.
2165 * lppTags [O] Destination for the list of property Id's in iface.
2166 * lppAccess [O] Destination for access level for each property in lppTags.
2167 *
2168 * RETURNS
2169 * Success: S_OK. lppTags and lppAccess contain the property Id's and the
2170 * Access level of each property value in iface.
2171 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid, or
2172 * MAPI_E_NOT_ENOUGH_MEMORY if memory allocation fails.
2173 *
2174 * NOTES
2175 * - *lppTags and *lppAccess should be freed with MAPIFreeBuffer() by the caller.
2176 */
2177 static HRESULT WINAPI
2178 IPropData_fnHrGetPropAccess(LPPROPDATA iface, LPSPropTagArray *lppTags,
2179 ULONG **lppAccess)
2180 {
2181 IPropDataImpl *This = impl_from_IPropData(iface);
2182 LPVOID lpMem;
2183 HRESULT hRet;
2184 ULONG i;
2185
2186 TRACE("(%p,%p,%p) stub\n", iface, lppTags, lppAccess);
2187
2188 if (!iface || !lppTags || !lppAccess)
2189 return MAPI_E_INVALID_PARAMETER;
2190
2191 *lppTags = NULL;
2192 *lppAccess = NULL;
2193
2194 IMAPIPROP_Lock(This);
2195
2196 hRet = This->lpAlloc(CbNewSPropTagArray(This->ulNumValues), &lpMem);
2197 if (SUCCEEDED(hRet))
2198 {
2199 *lppTags = lpMem;
2200
2201 hRet = This->lpAlloc(This->ulNumValues * sizeof(ULONG), &lpMem);
2202 if (SUCCEEDED(hRet))
2203 {
2204 struct list *cursor;
2205
2206 *lppAccess = lpMem;
2207 (*lppTags)->cValues = This->ulNumValues;
2208
2209 i = 0;
2210 LIST_FOR_EACH(cursor, &This->values)
2211 {
2212 LPIPropDataItem item = LIST_ENTRY(cursor, IPropDataItem, entry);
2213 (*lppTags)->aulPropTag[i] = item->value->ulPropTag;
2214 (*lppAccess)[i] = item->ulAccess;
2215 i++;
2216 }
2217 IMAPIPROP_Unlock(This);
2218 return S_OK;
2219 }
2220 This->lpFree(*lppTags);
2221 *lppTags = 0;
2222 }
2223 IMAPIPROP_Unlock(This);
2224 return MAPI_E_NOT_ENOUGH_MEMORY;
2225 }
2226
2227 /**************************************************************************
2228 * IPropData_HrAddObjProps {MAPI32}
2229 *
2230 * Not documented at this time.
2231 *
2232 * RETURNS
2233 * An HRESULT success/failure code.
2234 */
2235 static HRESULT WINAPI
2236 IPropData_fnHrAddObjProps(LPPROPDATA iface, LPSPropTagArray lpTags,
2237 LPSPropProblemArray *lppProbs)
2238 {
2239 #if 0
2240 ULONG i;
2241 HRESULT hRet;
2242 LPSPropValue lpValues;
2243 #endif
2244
2245 FIXME("(%p,%p,%p) stub\n", iface, lpTags, lppProbs);
2246
2247 if (!iface || !lpTags)
2248 return MAPI_E_INVALID_PARAMETER;
2249
2250 /* FIXME: Below is the obvious implementation, adding all the properties
2251 * in lpTags to the object. However, it doesn't appear that this
2252 * is what this function does.
2253 */
2254 return S_OK;
2255 #if 0
2256 if (!lpTags->cValues)
2257 return S_OK;
2258
2259 lpValues = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2260 lpTags->cValues * sizeof(SPropValue));
2261 if (!lpValues)
2262 return MAPI_E_NOT_ENOUGH_MEMORY;
2263
2264 for (i = 0; i < lpTags->cValues; i++)
2265 lpValues[i].ulPropTag = lpTags->aulPropTag[i];
2266
2267 hRet = IPropData_SetProps(iface, lpTags->cValues, lpValues, lppProbs);
2268 HeapFree(GetProcessHeap(), 0, lpValues);
2269 return hRet;
2270 #endif
2271 }
2272
2273 static const IPropDataVtbl IPropDataImpl_vtbl =
2274 {
2275 IPropData_fnQueryInterface,
2276 IPropData_fnAddRef,
2277 IPropData_fnRelease,
2278 IPropData_fnGetLastError,
2279 IPropData_fnSaveChanges,
2280 IPropData_fnGetProps,
2281 IPropData_fnGetPropList,
2282 IPropData_fnOpenProperty,
2283 IPropData_fnSetProps,
2284 IPropData_fnDeleteProps,
2285 IPropData_fnCopyTo,
2286 IPropData_fnCopyProps,
2287 IPropData_fnGetNamesFromIDs,
2288 IPropData_fnGetIDsFromNames,
2289 IPropData_fnHrSetObjAccess,
2290 IPropData_fnHrSetPropAccess,
2291 IPropData_fnHrGetPropAccess,
2292 IPropData_fnHrAddObjProps
2293 };
2294
2295 /*************************************************************************
2296 * CreateIProp@24 (MAPI32.60)
2297 *
2298 * Create an IPropData object.
2299 *
2300 * PARAMS
2301 * iid [I] GUID of the object to create. Use &IID_IMAPIPropData or NULL
2302 * lpAlloc [I] Memory allocation function. Use MAPIAllocateBuffer()
2303 * lpMore [I] Linked memory allocation function. Use MAPIAllocateMore()
2304 * lpFree [I] Memory free function. Use MAPIFreeBuffer()
2305 * lpReserved [I] Reserved, set to NULL
2306 * lppPropData [O] Destination for created IPropData object
2307 *
2308 * RETURNS
2309 * Success: S_OK. *lppPropData contains the newly created object.
2310 * Failure: MAPI_E_INTERFACE_NOT_SUPPORTED, if iid is non-NULL and not supported,
2311 * MAPI_E_INVALID_PARAMETER, if any parameter is invalid
2312 */
2313 SCODE WINAPI CreateIProp(LPCIID iid, ALLOCATEBUFFER *lpAlloc,
2314 ALLOCATEMORE *lpMore, FREEBUFFER *lpFree,
2315 LPVOID lpReserved, LPPROPDATA *lppPropData)
2316 {
2317 IPropDataImpl *lpPropData;
2318 SCODE scode;
2319
2320 TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_guid(iid), lpAlloc, lpMore, lpFree,
2321 lpReserved, lppPropData);
2322
2323 if (lppPropData)
2324 *lppPropData = NULL;
2325
2326 if (iid && !IsEqualGUID(iid, &IID_IMAPIPropData))
2327 return MAPI_E_INTERFACE_NOT_SUPPORTED;
2328
2329 if (!lpAlloc || !lpMore || !lpFree || lpReserved || !lppPropData)
2330 return MAPI_E_INVALID_PARAMETER;
2331
2332 scode = lpAlloc(sizeof(IPropDataImpl), (LPVOID*)&lpPropData);
2333
2334 if (SUCCEEDED(scode))
2335 {
2336 lpPropData->IPropData_iface.lpVtbl = &IPropDataImpl_vtbl;
2337 lpPropData->lRef = 1;
2338 lpPropData->lpAlloc = lpAlloc;
2339 lpPropData->lpMore = lpMore;
2340 lpPropData->lpFree = lpFree;
2341 lpPropData->ulObjAccess = IPROP_READWRITE;
2342 lpPropData->ulNumValues = 0;
2343 list_init(&lpPropData->values);
2344 InitializeCriticalSection(&lpPropData->cs);
2345 lpPropData->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IPropDataImpl.cs");
2346 *lppPropData = &lpPropData->IPropData_iface;
2347 }
2348 return scode;
2349 }