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