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