ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

prop.c
Go to the documentation of this file.
00001 /*
00002  * Property functions
00003  *
00004  * Copyright 2004 Jon Griffiths
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00019  */
00020 
00021 #include <stdarg.h>
00022 #define NONAMELESSUNION
00023 #define NONAMELESSSTRUCT
00024 #include "windef.h"
00025 #include "winbase.h"
00026 #include "winreg.h"
00027 #include "winerror.h"
00028 #include "winternl.h"
00029 #include "objbase.h"
00030 #include "shlwapi.h"
00031 #include "wine/list.h"
00032 #include "wine/debug.h"
00033 #include "wine/unicode.h"
00034 #include "mapival.h"
00035 
00036 WINE_DEFAULT_DEBUG_CHANNEL(mapi);
00037 
00038 BOOL WINAPI FBadRglpszA(LPSTR*,ULONG);
00039 
00040 /* Internal: Check if a property value array is invalid */
00041 static inline ULONG PROP_BadArray(LPSPropValue lpProp, size_t elemSize)
00042 {
00043     return IsBadReadPtr(lpProp->Value.MVi.lpi, lpProp->Value.MVi.cValues * elemSize);
00044 }
00045 
00046 /*************************************************************************
00047  * PropCopyMore@16 (MAPI32.76)
00048  *
00049  * Copy a property value.
00050  *
00051  * PARAMS
00052  *  lpDest [O] Destination for the copied value
00053  *  lpSrc  [I] Property value to copy to lpDest
00054  *  lpMore [I] Linked memory allocation function (pass MAPIAllocateMore())
00055  *  lpOrig [I] Original allocation to which memory will be linked
00056  *
00057  * RETURNS
00058  *  Success: S_OK. lpDest contains a deep copy of lpSrc.
00059  *  Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid,
00060  *           MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails.
00061  *
00062  * NOTES
00063  *  Any elements within the property returned should not be individually
00064  *  freed, as they will be freed when lpOrig is.
00065  */
00066 SCODE WINAPI PropCopyMore(LPSPropValue lpDest, LPSPropValue lpSrc,
00067                           ALLOCATEMORE *lpMore, LPVOID lpOrig)
00068 {
00069     ULONG ulLen, i;
00070     SCODE scode = S_OK;
00071 
00072     TRACE("(%p,%p,%p,%p)\n", lpDest, lpSrc, lpMore, lpOrig);
00073 
00074     if (!lpDest || IsBadWritePtr(lpDest, sizeof(SPropValue)) ||
00075         FBadProp(lpSrc) || !lpMore)
00076         return MAPI_E_INVALID_PARAMETER;
00077 
00078     /* Shallow copy first, this is sufficient for properties without pointers */
00079     *lpDest = *lpSrc;
00080 
00081    switch (PROP_TYPE(lpSrc->ulPropTag))
00082     {
00083     case PT_CLSID:
00084         scode = lpMore(sizeof(GUID), lpOrig, (LPVOID*)&lpDest->Value.lpguid);
00085         if (SUCCEEDED(scode))
00086             *lpDest->Value.lpguid = *lpSrc->Value.lpguid;
00087         break;
00088     case PT_STRING8:
00089         ulLen = lstrlenA(lpSrc->Value.lpszA) + 1u;
00090         scode = lpMore(ulLen, lpOrig, (LPVOID*)&lpDest->Value.lpszA);
00091         if (SUCCEEDED(scode))
00092             memcpy(lpDest->Value.lpszA, lpSrc->Value.lpszA, ulLen);
00093         break;
00094     case PT_UNICODE:
00095         ulLen = (strlenW(lpSrc->Value.lpszW) + 1u) * sizeof(WCHAR);
00096         scode = lpMore(ulLen, lpOrig, (LPVOID*)&lpDest->Value.lpszW);
00097         if (SUCCEEDED(scode))
00098             memcpy(lpDest->Value.lpszW, lpSrc->Value.lpszW, ulLen);
00099         break;
00100     case PT_BINARY:
00101         scode = lpMore(lpSrc->Value.bin.cb, lpOrig, (LPVOID*)&lpDest->Value.bin.lpb);
00102         if (SUCCEEDED(scode))
00103             memcpy(lpDest->Value.bin.lpb, lpSrc->Value.bin.lpb, lpSrc->Value.bin.cb);
00104         break;
00105     default:
00106         if (lpSrc->ulPropTag & MV_FLAG)
00107         {
00108             ulLen = UlPropSize(lpSrc);
00109 
00110             if (PROP_TYPE(lpSrc->ulPropTag) == PT_MV_STRING8 ||
00111                 PROP_TYPE(lpSrc->ulPropTag) == PT_MV_UNICODE)
00112             {
00113                 /* UlPropSize doesn't account for the string pointers */
00114                 ulLen += lpSrc->Value.MVszA.cValues * sizeof(char*);
00115             }
00116             else if (PROP_TYPE(lpSrc->ulPropTag) == PT_MV_BINARY)
00117             {
00118                /* UlPropSize doesn't account for the SBinary structs */
00119                ulLen += lpSrc->Value.MVbin.cValues * sizeof(SBinary);
00120             }
00121 
00122             lpDest->Value.MVi.cValues = lpSrc->Value.MVi.cValues;
00123             scode = lpMore(ulLen, lpOrig, (LPVOID*)&lpDest->Value.MVi.lpi);
00124             if (FAILED(scode))
00125                 break;
00126 
00127             /* Note that we could allocate the memory for each value in a
00128              * multi-value property separately, however if an allocation failed
00129              * we would be left with a bunch of allocated memory, which (while
00130              * not really leaked) is unusable until lpOrig is freed. So for
00131              * strings and binary arrays we make a single allocation for all
00132              * of the data. This is consistent since individual elements can't
00133              * be freed anyway.
00134              */
00135 
00136             switch (PROP_TYPE(lpSrc->ulPropTag))
00137             {
00138             case PT_MV_STRING8:
00139             {
00140                 char *lpNextStr = (char*)(lpDest->Value.MVszA.lppszA +
00141                                           lpDest->Value.MVszA.cValues);
00142 
00143                 for (i = 0; i < lpSrc->Value.MVszA.cValues; i++)
00144                 {
00145                     ULONG ulStrLen = lstrlenA(lpSrc->Value.MVszA.lppszA[i]) + 1u;
00146 
00147                     lpDest->Value.MVszA.lppszA[i] = lpNextStr;
00148                     memcpy(lpNextStr, lpSrc->Value.MVszA.lppszA[i], ulStrLen);
00149                     lpNextStr += ulStrLen;
00150                 }
00151                 break;
00152             }
00153             case PT_MV_UNICODE:
00154             {
00155                 WCHAR *lpNextStr = (WCHAR*)(lpDest->Value.MVszW.lppszW +
00156                                             lpDest->Value.MVszW.cValues);
00157 
00158                 for (i = 0; i < lpSrc->Value.MVszW.cValues; i++)
00159                 {
00160                     ULONG ulStrLen = strlenW(lpSrc->Value.MVszW.lppszW[i]) + 1u;
00161 
00162                     lpDest->Value.MVszW.lppszW[i] = lpNextStr;
00163                     memcpy(lpNextStr, lpSrc->Value.MVszW.lppszW[i], ulStrLen * sizeof(WCHAR));
00164                     lpNextStr += ulStrLen;
00165                 }
00166                 break;
00167             }
00168             case PT_MV_BINARY:
00169             {
00170                 LPBYTE lpNext = (LPBYTE)(lpDest->Value.MVbin.lpbin +
00171                                          lpDest->Value.MVbin.cValues);
00172 
00173                 for (i = 0; i < lpSrc->Value.MVszW.cValues; i++)
00174                 {
00175                     lpDest->Value.MVbin.lpbin[i].cb = lpSrc->Value.MVbin.lpbin[i].cb;
00176                     lpDest->Value.MVbin.lpbin[i].lpb = lpNext;
00177                     memcpy(lpNext, lpSrc->Value.MVbin.lpbin[i].lpb, lpDest->Value.MVbin.lpbin[i].cb);
00178                     lpNext += lpDest->Value.MVbin.lpbin[i].cb;
00179                 }
00180                 break;
00181             }
00182             default:
00183                 /* No embedded pointers, just copy the data over */
00184                 memcpy(lpDest->Value.MVi.lpi, lpSrc->Value.MVi.lpi, ulLen);
00185                 break;
00186             }
00187             break;
00188         }
00189     }
00190     return scode;
00191 }
00192 
00193 /*************************************************************************
00194  * UlPropSize@4 (MAPI32.77)
00195  *
00196  * Determine the size of a property in bytes.
00197  *
00198  * PARAMS
00199  *  lpProp [I] Property to determine the size of
00200  *
00201  * RETURNS
00202  *  Success: The size of the value in lpProp.
00203  *  Failure: 0, if a multi-value (array) property is invalid or the type of lpProp
00204  *           is unknown.
00205  *
00206  * NOTES
00207  *  - The size returned does not include the size of the SPropValue struct
00208  *    or the size of the array of pointers for multi-valued properties that
00209  *    contain pointers (such as PT_MV_STRING8 or PT-MV_UNICODE).
00210  *  - MSDN incorrectly states that this function returns MAPI_E_CALL_FAILED if
00211  *    lpProp is invalid. In reality no checking is performed and this function
00212  *    will crash if passed an invalid property, or return 0 if the property
00213  *    type is PT_OBJECT or is unknown.
00214  */
00215 ULONG WINAPI UlPropSize(LPSPropValue lpProp)
00216 {
00217     ULONG ulRet = 1u, i;
00218 
00219     TRACE("(%p)\n", lpProp);
00220 
00221     switch (PROP_TYPE(lpProp->ulPropTag))
00222     {
00223     case PT_MV_I2:       ulRet = lpProp->Value.MVi.cValues;
00224     case PT_BOOLEAN:
00225     case PT_I2:          ulRet *= sizeof(USHORT);
00226                          break;
00227     case PT_MV_I4:       ulRet = lpProp->Value.MVl.cValues;
00228     case PT_ERROR:
00229     case PT_I4:          ulRet *= sizeof(LONG);
00230                          break;
00231     case PT_MV_I8:       ulRet = lpProp->Value.MVli.cValues;
00232     case PT_I8:          ulRet *= sizeof(LONG64);
00233                          break;
00234     case PT_MV_R4:       ulRet = lpProp->Value.MVflt.cValues;
00235     case PT_R4:          ulRet *= sizeof(float);
00236                          break;
00237     case PT_MV_APPTIME:
00238     case PT_MV_R8:       ulRet = lpProp->Value.MVdbl.cValues;
00239     case PT_APPTIME:
00240     case PT_R8:          ulRet *= sizeof(double);
00241                          break;
00242     case PT_MV_CURRENCY: ulRet = lpProp->Value.MVcur.cValues;
00243     case PT_CURRENCY:    ulRet *= sizeof(CY);
00244                          break;
00245     case PT_MV_SYSTIME:  ulRet = lpProp->Value.MVft.cValues;
00246     case PT_SYSTIME:     ulRet *= sizeof(FILETIME);
00247                          break;
00248     case PT_MV_CLSID:    ulRet = lpProp->Value.MVguid.cValues;
00249     case PT_CLSID:       ulRet *= sizeof(GUID);
00250                          break;
00251     case PT_MV_STRING8:  ulRet = 0u;
00252                          for (i = 0; i < lpProp->Value.MVszA.cValues; i++)
00253                              ulRet += (lstrlenA(lpProp->Value.MVszA.lppszA[i]) + 1u);
00254                          break;
00255     case PT_STRING8:     ulRet = lstrlenA(lpProp->Value.lpszA) + 1u;
00256                          break;
00257     case PT_MV_UNICODE:  ulRet = 0u;
00258                          for (i = 0; i < lpProp->Value.MVszW.cValues; i++)
00259                              ulRet += (strlenW(lpProp->Value.MVszW.lppszW[i]) + 1u);
00260                          ulRet *= sizeof(WCHAR);
00261                          break;
00262     case PT_UNICODE:     ulRet = (lstrlenW(lpProp->Value.lpszW) + 1u) * sizeof(WCHAR);
00263                          break;
00264     case PT_MV_BINARY:   ulRet = 0u;
00265                          for (i = 0; i < lpProp->Value.MVbin.cValues; i++)
00266                              ulRet += lpProp->Value.MVbin.lpbin[i].cb;
00267                          break;
00268     case PT_BINARY:      ulRet = lpProp->Value.bin.cb;
00269                          break;
00270     case PT_OBJECT:
00271     default:             ulRet = 0u;
00272                          break;
00273     }
00274 
00275     return ulRet;
00276 }
00277 
00278 /*************************************************************************
00279  * FPropContainsProp@12 (MAPI32.78)
00280  *
00281  * Find a property with a given property tag in a property array.
00282  *
00283  * PARAMS
00284  *  lpHaystack [I] Property to match to
00285  *  lpNeedle   [I] Property to find in lpHaystack
00286  *  ulFuzzy    [I] Flags controlling match type and strictness (FL_* flags from "mapidefs.h")
00287  *
00288  * RETURNS
00289  *  TRUE, if lpNeedle matches lpHaystack according to the criteria of ulFuzzy.
00290  *
00291  * NOTES
00292  *  Only property types of PT_STRING8 and PT_BINARY are handled by this function.
00293  */
00294 BOOL WINAPI FPropContainsProp(LPSPropValue lpHaystack, LPSPropValue lpNeedle, ULONG ulFuzzy)
00295 {
00296     TRACE("(%p,%p,0x%08x)\n", lpHaystack, lpNeedle, ulFuzzy);
00297 
00298     if (FBadProp(lpHaystack) || FBadProp(lpNeedle) ||
00299         PROP_TYPE(lpHaystack->ulPropTag) != PROP_TYPE(lpNeedle->ulPropTag))
00300         return FALSE;
00301 
00302     /* FIXME: Do later versions support Unicode as well? */
00303 
00304     if (PROP_TYPE(lpHaystack->ulPropTag) == PT_STRING8)
00305     {
00306         DWORD dwFlags = 0, dwNeedleLen, dwHaystackLen;
00307 
00308         if (ulFuzzy & FL_IGNORECASE)
00309             dwFlags |= NORM_IGNORECASE;
00310         if (ulFuzzy & FL_IGNORENONSPACE)
00311             dwFlags |= NORM_IGNORENONSPACE;
00312         if (ulFuzzy & FL_LOOSE)
00313             dwFlags |= (NORM_IGNORECASE|NORM_IGNORENONSPACE|NORM_IGNORESYMBOLS);
00314 
00315         dwNeedleLen = lstrlenA(lpNeedle->Value.lpszA);
00316         dwHaystackLen = lstrlenA(lpHaystack->Value.lpszA);
00317 
00318         if ((ulFuzzy & (FL_SUBSTRING|FL_PREFIX)) == FL_PREFIX)
00319         {
00320             if (dwNeedleLen <= dwHaystackLen &&
00321                 CompareStringA(LOCALE_USER_DEFAULT, dwFlags,
00322                                lpHaystack->Value.lpszA, dwNeedleLen,
00323                                lpNeedle->Value.lpszA, dwNeedleLen) == CSTR_EQUAL)
00324                 return TRUE; /* needle is a prefix of haystack */
00325         }
00326         else if ((ulFuzzy & (FL_SUBSTRING|FL_PREFIX)) == FL_SUBSTRING)
00327         {
00328             LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD) = StrChrA;
00329             LPSTR lpStr = lpHaystack->Value.lpszA;
00330 
00331             if (dwFlags & NORM_IGNORECASE)
00332                 pStrChrFn = StrChrIA;
00333 
00334             while ((lpStr = pStrChrFn(lpStr, *lpNeedle->Value.lpszA)) != NULL)
00335             {
00336                 dwHaystackLen -= (lpStr - lpHaystack->Value.lpszA);
00337                 if (dwNeedleLen <= dwHaystackLen &&
00338                     CompareStringA(LOCALE_USER_DEFAULT, dwFlags,
00339                                lpStr, dwNeedleLen,
00340                                lpNeedle->Value.lpszA, dwNeedleLen) == CSTR_EQUAL)
00341                     return TRUE; /* needle is a substring of haystack */
00342                 lpStr++;
00343             }
00344         }
00345         else if (CompareStringA(LOCALE_USER_DEFAULT, dwFlags,
00346                                 lpHaystack->Value.lpszA, dwHaystackLen,
00347                                 lpNeedle->Value.lpszA, dwNeedleLen) == CSTR_EQUAL)
00348             return TRUE; /* full string match */
00349     }
00350     else if (PROP_TYPE(lpHaystack->ulPropTag) == PT_BINARY)
00351     {
00352         if ((ulFuzzy & (FL_SUBSTRING|FL_PREFIX)) == FL_PREFIX)
00353         {
00354             if (lpNeedle->Value.bin.cb <= lpHaystack->Value.bin.cb &&
00355                 !memcmp(lpNeedle->Value.bin.lpb, lpHaystack->Value.bin.lpb,
00356                         lpNeedle->Value.bin.cb))
00357                 return TRUE; /* needle is a prefix of haystack */
00358         }
00359         else if ((ulFuzzy & (FL_SUBSTRING|FL_PREFIX)) == FL_SUBSTRING)
00360         {
00361             ULONG ulLen = lpHaystack->Value.bin.cb;
00362             LPBYTE lpb = lpHaystack->Value.bin.lpb;
00363 
00364             while ((lpb = memchr(lpb, *lpNeedle->Value.bin.lpb, ulLen)) != NULL)
00365             {
00366                 ulLen = lpHaystack->Value.bin.cb - (lpb - lpHaystack->Value.bin.lpb);
00367                 if (lpNeedle->Value.bin.cb <= ulLen &&
00368                     !memcmp(lpNeedle->Value.bin.lpb, lpb, lpNeedle->Value.bin.cb))
00369                     return TRUE; /* needle is a substring of haystack */
00370                 lpb++;
00371             }
00372         }
00373         else if (!LPropCompareProp(lpHaystack, lpNeedle))
00374             return TRUE; /* needle is an exact match with haystack */
00375 
00376     }
00377     return FALSE;
00378 }
00379 
00380 /*************************************************************************
00381  * FPropCompareProp@12 (MAPI32.79)
00382  *
00383  * Compare two properties.
00384  *
00385  * PARAMS
00386  *  lpPropLeft  [I] Left hand property to compare to lpPropRight
00387  *  ulOp        [I] Comparison operator (RELOP_* enum from "mapidefs.h")
00388  *  lpPropRight [I] Right hand property to compare to lpPropLeft
00389  *
00390  * RETURNS
00391  *  TRUE, if the comparison is true, FALSE otherwise.
00392  */
00393 BOOL WINAPI FPropCompareProp(LPSPropValue lpPropLeft, ULONG ulOp, LPSPropValue lpPropRight)
00394 {
00395     LONG iCmp;
00396 
00397     TRACE("(%p,%d,%p)\n", lpPropLeft, ulOp, lpPropRight);
00398 
00399     if (ulOp > RELOP_RE || FBadProp(lpPropLeft) || FBadProp(lpPropRight))
00400         return FALSE;
00401 
00402     if (ulOp == RELOP_RE)
00403     {
00404         FIXME("Comparison operator RELOP_RE not yet implemented!\n");
00405         return FALSE;
00406     }
00407 
00408     iCmp = LPropCompareProp(lpPropLeft, lpPropRight);
00409 
00410     switch (ulOp)
00411     {
00412     case RELOP_LT: return iCmp <  0 ? TRUE : FALSE;
00413     case RELOP_LE: return iCmp <= 0 ? TRUE : FALSE;
00414     case RELOP_GT: return iCmp >  0 ? TRUE : FALSE;
00415     case RELOP_GE: return iCmp >= 0 ? TRUE : FALSE;
00416     case RELOP_EQ: return iCmp == 0 ? TRUE : FALSE;
00417     case RELOP_NE: return iCmp != 0 ? TRUE : FALSE;
00418     }
00419     return FALSE;
00420 }
00421 
00422 /*************************************************************************
00423  * LPropCompareProp@8 (MAPI32.80)
00424  *
00425  * Compare two properties.
00426  *
00427  * PARAMS
00428  *  lpPropLeft  [I] Left hand property to compare to lpPropRight
00429  *  lpPropRight [I] Right hand property to compare to lpPropLeft
00430  *
00431  * RETURNS
00432  *  An integer less than, equal to or greater than 0, indicating that
00433  *  lpszStr is less than, the same, or greater than lpszComp.
00434  */
00435 LONG WINAPI LPropCompareProp(LPSPropValue lpPropLeft, LPSPropValue lpPropRight)
00436 {
00437     LONG iRet;
00438 
00439     TRACE("(%p->0x%08x,%p->0x%08x)\n", lpPropLeft, lpPropLeft->ulPropTag,
00440           lpPropRight, lpPropRight->ulPropTag);
00441 
00442     /* If the properties are not the same, sort by property type */
00443     if (PROP_TYPE(lpPropLeft->ulPropTag) != PROP_TYPE(lpPropRight->ulPropTag))
00444         return (LONG)PROP_TYPE(lpPropLeft->ulPropTag) - (LONG)PROP_TYPE(lpPropRight->ulPropTag);
00445 
00446     switch (PROP_TYPE(lpPropLeft->ulPropTag))
00447     {
00448     case PT_UNSPECIFIED:
00449     case PT_NULL:
00450         return 0; /* NULLs are equal */
00451     case PT_I2:
00452         return lpPropLeft->Value.i - lpPropRight->Value.i;
00453     case PT_I4:
00454         return lpPropLeft->Value.l - lpPropRight->Value.l;
00455     case PT_I8:
00456         if (lpPropLeft->Value.li.QuadPart > lpPropRight->Value.li.QuadPart)
00457             return 1;
00458         if (lpPropLeft->Value.li.QuadPart == lpPropRight->Value.li.QuadPart)
00459             return 0;
00460         return -1;
00461     case PT_R4:
00462         if (lpPropLeft->Value.flt > lpPropRight->Value.flt)
00463             return 1;
00464         if (lpPropLeft->Value.flt == lpPropRight->Value.flt)
00465             return 0;
00466         return -1;
00467     case PT_APPTIME:
00468     case PT_R8:
00469         if (lpPropLeft->Value.dbl > lpPropRight->Value.dbl)
00470             return 1;
00471         if (lpPropLeft->Value.dbl == lpPropRight->Value.dbl)
00472             return 0;
00473         return -1;
00474     case PT_CURRENCY:
00475         if (lpPropLeft->Value.cur.int64 > lpPropRight->Value.cur.int64)
00476             return 1;
00477         if (lpPropLeft->Value.cur.int64 == lpPropRight->Value.cur.int64)
00478             return 0;
00479         return -1;
00480     case PT_SYSTIME:
00481         return CompareFileTime(&lpPropLeft->Value.ft, &lpPropRight->Value.ft);
00482     case PT_BOOLEAN:
00483         return (lpPropLeft->Value.b ? 1 : 0) - (lpPropRight->Value.b ? 1 : 0);
00484     case PT_BINARY:
00485         if (lpPropLeft->Value.bin.cb == lpPropRight->Value.bin.cb)
00486             iRet = memcmp(lpPropLeft->Value.bin.lpb, lpPropRight->Value.bin.lpb,
00487                           lpPropLeft->Value.bin.cb);
00488         else
00489         {
00490             iRet = memcmp(lpPropLeft->Value.bin.lpb, lpPropRight->Value.bin.lpb,
00491                           min(lpPropLeft->Value.bin.cb, lpPropRight->Value.bin.cb));
00492 
00493             if (!iRet)
00494                 iRet = lpPropLeft->Value.bin.cb - lpPropRight->Value.bin.cb;
00495         }
00496         return iRet;
00497     case PT_STRING8:
00498         return lstrcmpA(lpPropLeft->Value.lpszA, lpPropRight->Value.lpszA);
00499     case PT_UNICODE:
00500         return strcmpW(lpPropLeft->Value.lpszW, lpPropRight->Value.lpszW);
00501     case PT_ERROR:
00502         if (lpPropLeft->Value.err > lpPropRight->Value.err)
00503             return 1;
00504         if (lpPropLeft->Value.err == lpPropRight->Value.err)
00505             return 0;
00506         return -1;
00507     case PT_CLSID:
00508         return memcmp(lpPropLeft->Value.lpguid, lpPropRight->Value.lpguid,
00509                       sizeof(GUID));
00510     }
00511     FIXME("Unhandled property type %d\n", PROP_TYPE(lpPropLeft->ulPropTag));
00512     return 0;
00513 }
00514 
00515 /*************************************************************************
00516  * HrGetOneProp@8 (MAPI32.135)
00517  *
00518  * Get a property value from an IMAPIProp object.
00519  *
00520  * PARAMS
00521  *  lpIProp   [I] IMAPIProp object to get the property value in
00522  *  ulPropTag [I] Property tag of the property to get
00523  *  lppProp   [O] Destination for the returned property
00524  *
00525  * RETURNS
00526  *  Success: S_OK. *lppProp contains the property value requested.
00527  *  Failure: MAPI_E_NOT_FOUND, if no property value has the tag given by ulPropTag.
00528  */
00529 HRESULT WINAPI HrGetOneProp(LPMAPIPROP lpIProp, ULONG ulPropTag, LPSPropValue *lppProp)
00530 {
00531     SPropTagArray pta;
00532     ULONG ulCount;
00533     HRESULT hRet;
00534 
00535     TRACE("(%p,%d,%p)\n", lpIProp, ulPropTag, lppProp);
00536 
00537     pta.cValues = 1u;
00538     pta.aulPropTag[0] = ulPropTag;
00539     hRet = IMAPIProp_GetProps(lpIProp, &pta, 0u, &ulCount, lppProp);
00540     if (hRet == MAPI_W_ERRORS_RETURNED)
00541     {
00542         MAPIFreeBuffer(*lppProp);
00543         *lppProp = NULL;
00544         hRet = MAPI_E_NOT_FOUND;
00545     }
00546     return hRet;
00547 }
00548 
00549 /*************************************************************************
00550  * HrSetOneProp@8 (MAPI32.136)
00551  *
00552  * Set a property value in an IMAPIProp object.
00553  *
00554  * PARAMS
00555  *  lpIProp [I] IMAPIProp object to set the property value in
00556  *  lpProp  [I] Property value to set
00557  *
00558  * RETURNS
00559  *  Success: S_OK. The value in lpProp is set in lpIProp.
00560  *  Failure: An error result from IMAPIProp_SetProps().
00561  */
00562 HRESULT WINAPI HrSetOneProp(LPMAPIPROP lpIProp, LPSPropValue lpProp)
00563 {
00564     TRACE("(%p,%p)\n", lpIProp, lpProp);
00565 
00566     return IMAPIProp_SetProps(lpIProp, 1u, lpProp, NULL);
00567 }
00568 
00569 /*************************************************************************
00570  * FPropExists@8 (MAPI32.137)
00571  *
00572  * Find a property with a given property tag in an IMAPIProp object.
00573  *
00574  * PARAMS
00575  *  lpIProp   [I] IMAPIProp object to find the property tag in
00576  *  ulPropTag [I] Property tag to find
00577  *
00578  * RETURNS
00579  *  TRUE, if ulPropTag matches a property held in lpIProp,
00580  *  FALSE, otherwise.
00581  *
00582  * NOTES
00583  *  if ulPropTag has a property type of PT_UNSPECIFIED, then only the property
00584  *  Ids need to match for a successful match to occur.
00585  */
00586  BOOL WINAPI FPropExists(LPMAPIPROP lpIProp, ULONG ulPropTag)
00587  {
00588     BOOL bRet = FALSE;
00589 
00590     TRACE("(%p,%d)\n", lpIProp, ulPropTag);
00591 
00592     if (lpIProp)
00593     {
00594         LPSPropTagArray lpTags;
00595         ULONG i;
00596 
00597         if (FAILED(IMAPIProp_GetPropList(lpIProp, 0u, &lpTags)))
00598             return FALSE;
00599 
00600         for (i = 0; i < lpTags->cValues; i++)
00601         {
00602             if (!FBadPropTag(lpTags->aulPropTag[i]) &&
00603                 (lpTags->aulPropTag[i] == ulPropTag ||
00604                  (PROP_TYPE(ulPropTag) == PT_UNSPECIFIED &&
00605                   PROP_ID(lpTags->aulPropTag[i]) == lpTags->aulPropTag[i])))
00606             {
00607                 bRet = TRUE;
00608                 break;
00609             }
00610         }
00611         MAPIFreeBuffer(lpTags);
00612     }
00613     return bRet;
00614 }
00615 
00616 /*************************************************************************
00617  * PpropFindProp@12 (MAPI32.138)
00618  *
00619  * Find a property with a given property tag in a property array.
00620  *
00621  * PARAMS
00622  *  lpProps   [I] Property array to search
00623  *  cValues   [I] Number of properties in lpProps
00624  *  ulPropTag [I] Property tag to find
00625  *
00626  * RETURNS
00627  *  A pointer to the matching property, or NULL if none was found.
00628  *
00629  * NOTES
00630  *  if ulPropTag has a property type of PT_UNSPECIFIED, then only the property
00631  *  Ids need to match for a successful match to occur.
00632  */
00633 LPSPropValue WINAPI PpropFindProp(LPSPropValue lpProps, ULONG cValues, ULONG ulPropTag)
00634 {
00635     TRACE("(%p,%d,%d)\n", lpProps, cValues, ulPropTag);
00636 
00637     if (lpProps && cValues)
00638     {
00639         ULONG i;
00640         for (i = 0; i < cValues; i++)
00641         {
00642             if (!FBadPropTag(lpProps[i].ulPropTag) &&
00643                 (lpProps[i].ulPropTag == ulPropTag ||
00644                  (PROP_TYPE(ulPropTag) == PT_UNSPECIFIED &&
00645                   PROP_ID(lpProps[i].ulPropTag) == PROP_ID(ulPropTag))))
00646                 return &lpProps[i];
00647         }
00648     }
00649     return NULL;
00650 }
00651 
00652 /*************************************************************************
00653  * FreePadrlist@4 (MAPI32.139)
00654  *
00655  * Free the memory used by an address book list.
00656  *
00657  * PARAMS
00658  *  lpAddrs [I] Address book list to free
00659  *
00660  * RETURNS
00661  *  Nothing.
00662  */
00663 VOID WINAPI FreePadrlist(LPADRLIST lpAddrs)
00664 {
00665     TRACE("(%p)\n", lpAddrs);
00666 
00667     /* Structures are binary compatible; use the same implementation */
00668     FreeProws((LPSRowSet)lpAddrs);
00669 }
00670 
00671 /*************************************************************************
00672  * FreeProws@4 (MAPI32.140)
00673  *
00674  * Free the memory used by a row set.
00675  *
00676  * PARAMS
00677  *  lpRowSet [I] Row set to free
00678  *
00679  * RETURNS
00680  *  Nothing.
00681  */
00682 VOID WINAPI FreeProws(LPSRowSet lpRowSet)
00683 {
00684     TRACE("(%p)\n", lpRowSet);
00685 
00686     if (lpRowSet)
00687     {
00688         ULONG i;
00689 
00690         for (i = 0; i < lpRowSet->cRows; i++)
00691             MAPIFreeBuffer(lpRowSet->aRow[i].lpProps);
00692 
00693         MAPIFreeBuffer(lpRowSet);
00694     }
00695 }
00696 
00697 /*************************************************************************
00698  * ScCountProps@12 (MAPI32.170)
00699  *
00700  * Validate and determine the length of an array of properties.
00701  *
00702  * PARAMS
00703  *  iCount  [I] Length of the lpProps array
00704  *  lpProps [I] Array of properties to validate/size
00705  *  pcBytes [O] If non-NULL, destination for the size of the property array
00706  *
00707  * RETURNS
00708  *  Success: S_OK. If pcBytes is non-NULL, it contains the size of the propery array.
00709  *  Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid or validation
00710  *           of the property array fails.
00711  */
00712 SCODE WINAPI ScCountProps(INT iCount, LPSPropValue lpProps, ULONG *pcBytes)
00713 {
00714     ULONG i, ulCount = iCount, ulBytes = 0;
00715 
00716     TRACE("(%d,%p,%p)\n", iCount, lpProps, pcBytes);
00717 
00718     if (iCount <= 0 || !lpProps ||
00719         IsBadReadPtr(lpProps, iCount * sizeof(SPropValue)))
00720         return MAPI_E_INVALID_PARAMETER;
00721 
00722     for (i = 0; i < ulCount; i++)
00723     {
00724         ULONG ulPropSize = 0;
00725 
00726         if (FBadProp(&lpProps[i]) || lpProps[i].ulPropTag == PROP_ID_NULL ||
00727             lpProps[i].ulPropTag == PROP_ID_INVALID)
00728             return MAPI_E_INVALID_PARAMETER;
00729 
00730             if (PROP_TYPE(lpProps[i].ulPropTag) != PT_OBJECT)
00731             {
00732                 ulPropSize = UlPropSize(&lpProps[i]);
00733                 if (!ulPropSize)
00734                     return MAPI_E_INVALID_PARAMETER;
00735             }
00736 
00737             switch (PROP_TYPE(lpProps[i].ulPropTag))
00738             {
00739             case PT_STRING8:
00740             case PT_UNICODE:
00741             case PT_CLSID:
00742             case PT_BINARY:
00743             case PT_MV_I2:
00744             case PT_MV_I4:
00745             case PT_MV_I8:
00746             case PT_MV_R4:
00747             case PT_MV_R8:
00748             case PT_MV_CURRENCY:
00749             case PT_MV_SYSTIME:
00750             case PT_MV_APPTIME:
00751                 ulPropSize += sizeof(SPropValue);
00752                 break;
00753             case PT_MV_CLSID:
00754                 ulPropSize += lpProps[i].Value.MVszA.cValues * sizeof(char*) + sizeof(SPropValue);
00755                 break;
00756             case PT_MV_STRING8:
00757             case PT_MV_UNICODE:
00758                 ulPropSize += lpProps[i].Value.MVszA.cValues * sizeof(char*) + sizeof(SPropValue);
00759                 break;
00760             case PT_MV_BINARY:
00761                 ulPropSize += lpProps[i].Value.MVbin.cValues * sizeof(SBinary) + sizeof(SPropValue);
00762                 break;
00763             default:
00764                 ulPropSize = sizeof(SPropValue);
00765                 break;
00766             }
00767             ulBytes += ulPropSize;
00768     }
00769     if (pcBytes)
00770         *pcBytes = ulBytes;
00771 
00772     return S_OK;
00773 }
00774 
00775 /*************************************************************************
00776  * ScCopyProps@16 (MAPI32.171)
00777  *
00778  * Copy an array of property values into a buffer suited for serialisation.
00779  *
00780  * PARAMS
00781  *  cValues   [I] Number of properties in lpProps
00782  *  lpProps   [I] Property array to copy
00783  *  lpDst     [O] Destination for the serialised data
00784  *  lpCount   [O] If non-NULL, destination for the number of bytes of data written to lpDst
00785  *
00786  * RETURNS
00787  *  Success: S_OK. lpDst contains the serialised data from lpProps.
00788  *  Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
00789  *
00790  * NOTES
00791  *  The resulting property value array is stored in a contiguous block starting at lpDst.
00792  */
00793 SCODE WINAPI ScCopyProps(int cValues, LPSPropValue lpProps, LPVOID lpDst, ULONG *lpCount)
00794 {
00795     LPSPropValue lpDest = (LPSPropValue)lpDst;
00796     char *lpDataDest = (char *)(lpDest + cValues);
00797     ULONG ulLen, i;
00798     int iter;
00799 
00800     TRACE("(%d,%p,%p,%p)\n", cValues, lpProps, lpDst, lpCount);
00801 
00802     if (!lpProps || cValues < 0 || !lpDest)
00803         return MAPI_E_INVALID_PARAMETER;
00804 
00805     memcpy(lpDst, lpProps, cValues * sizeof(SPropValue));
00806 
00807     for (iter = 0; iter < cValues; iter++)
00808     {
00809         switch (PROP_TYPE(lpProps->ulPropTag))
00810         {
00811         case PT_CLSID:
00812             lpDest->Value.lpguid = (LPGUID)lpDataDest;
00813             *lpDest->Value.lpguid = *lpProps->Value.lpguid;
00814             lpDataDest += sizeof(GUID);
00815             break;
00816         case PT_STRING8:
00817             ulLen = lstrlenA(lpProps->Value.lpszA) + 1u;
00818             lpDest->Value.lpszA = lpDataDest;
00819             memcpy(lpDest->Value.lpszA, lpProps->Value.lpszA, ulLen);
00820             lpDataDest += ulLen;
00821             break;
00822         case PT_UNICODE:
00823             ulLen = (strlenW(lpProps->Value.lpszW) + 1u) * sizeof(WCHAR);
00824             lpDest->Value.lpszW = (LPWSTR)lpDataDest;
00825             memcpy(lpDest->Value.lpszW, lpProps->Value.lpszW, ulLen);
00826             lpDataDest += ulLen;
00827             break;
00828         case PT_BINARY:
00829             lpDest->Value.bin.lpb = (LPBYTE)lpDataDest;
00830             memcpy(lpDest->Value.bin.lpb, lpProps->Value.bin.lpb, lpProps->Value.bin.cb);
00831             lpDataDest += lpProps->Value.bin.cb;
00832             break;
00833         default:
00834             if (lpProps->ulPropTag & MV_FLAG)
00835             {
00836                 lpDest->Value.MVi.cValues = lpProps->Value.MVi.cValues;
00837                 /* Note: Assignment uses lppszA but covers all cases by union aliasing */
00838                 lpDest->Value.MVszA.lppszA = (char**)lpDataDest;
00839 
00840                 switch (PROP_TYPE(lpProps->ulPropTag))
00841                 {
00842                 case PT_MV_STRING8:
00843                 {
00844                     lpDataDest += lpProps->Value.MVszA.cValues * sizeof(char *);
00845 
00846                     for (i = 0; i < lpProps->Value.MVszA.cValues; i++)
00847                     {
00848                         ULONG ulStrLen = lstrlenA(lpProps->Value.MVszA.lppszA[i]) + 1u;
00849 
00850                         lpDest->Value.MVszA.lppszA[i] = lpDataDest;
00851                         memcpy(lpDataDest, lpProps->Value.MVszA.lppszA[i], ulStrLen);
00852                         lpDataDest += ulStrLen;
00853                     }
00854                     break;
00855                 }
00856                 case PT_MV_UNICODE:
00857                 {
00858                     lpDataDest += lpProps->Value.MVszW.cValues * sizeof(WCHAR *);
00859 
00860                     for (i = 0; i < lpProps->Value.MVszW.cValues; i++)
00861                     {
00862                         ULONG ulStrLen = (strlenW(lpProps->Value.MVszW.lppszW[i]) + 1u) * sizeof(WCHAR);
00863 
00864                         lpDest->Value.MVszW.lppszW[i] = (LPWSTR)lpDataDest;
00865                         memcpy(lpDataDest, lpProps->Value.MVszW.lppszW[i], ulStrLen);
00866                         lpDataDest += ulStrLen;
00867                     }
00868                     break;
00869                 }
00870                 case PT_MV_BINARY:
00871                 {
00872                     lpDataDest += lpProps->Value.MVszW.cValues * sizeof(SBinary);
00873 
00874                     for (i = 0; i < lpProps->Value.MVszW.cValues; i++)
00875                     {
00876                         lpDest->Value.MVbin.lpbin[i].cb = lpProps->Value.MVbin.lpbin[i].cb;
00877                         lpDest->Value.MVbin.lpbin[i].lpb = (LPBYTE)lpDataDest;
00878                         memcpy(lpDataDest, lpProps->Value.MVbin.lpbin[i].lpb, lpDest->Value.MVbin.lpbin[i].cb);
00879                         lpDataDest += lpDest->Value.MVbin.lpbin[i].cb;
00880                     }
00881                     break;
00882                 }
00883                 default:
00884                     /* No embedded pointers, just copy the data over */
00885                     ulLen = UlPropSize(lpProps);
00886                     memcpy(lpDest->Value.MVi.lpi, lpProps->Value.MVi.lpi, ulLen);
00887                     lpDataDest += ulLen;
00888                     break;
00889                 }
00890                 break;
00891             }
00892         }
00893         lpDest++;
00894         lpProps++;
00895     }
00896     if (lpCount)
00897         *lpCount = lpDataDest - (char *)lpDst;
00898 
00899     return S_OK;
00900 }
00901 
00902 /*************************************************************************
00903  * ScRelocProps@20 (MAPI32.172)
00904  *
00905  * Relocate the pointers in an array of property values after it has been copied.
00906  *
00907  * PARAMS
00908  *  cValues   [I] Number of properties in lpProps
00909  *  lpProps   [O] Property array to relocate the pointers in.
00910  *  lpOld     [I] Position where the data was copied from
00911  *  lpNew     [I] Position where the data was copied to
00912  *  lpCount   [O] If non-NULL, destination for the number of bytes of data at lpDst
00913  *
00914  * RETURNS
00915  *  Success: S_OK. Any pointers in lpProps are relocated.
00916  *  Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
00917  *
00918  * NOTES
00919  *  MSDN states that this function can be used for serialisation by passing
00920  *  NULL as either lpOld or lpNew, thus converting any pointers in lpProps
00921  *  between offsets and pointers. This does not work in native (it crashes),
00922  *  and cannot be made to work in Wine because the original interface design
00923  *  is deficient. The only use left for this function is to remap pointers
00924  *  in a contiguous property array that has been copied with memcpy() to
00925  *  another memory location.
00926  */
00927 SCODE WINAPI ScRelocProps(int cValues, LPSPropValue lpProps, LPVOID lpOld,
00928                           LPVOID lpNew, ULONG *lpCount)
00929 {
00930     static const BOOL bBadPtr = TRUE; /* Windows bug - Assumes source is bad */
00931     LPSPropValue lpDest = lpProps;
00932     ULONG ulCount = cValues * sizeof(SPropValue);
00933     ULONG ulLen, i;
00934     int iter;
00935 
00936     TRACE("(%d,%p,%p,%p,%p)\n", cValues, lpProps, lpOld, lpNew, lpCount);
00937 
00938     if (!lpProps || cValues < 0 || !lpOld || !lpNew)
00939         return MAPI_E_INVALID_PARAMETER;
00940 
00941     /* The reason native doesn't work as MSDN states is that it assumes that
00942      * the lpProps pointer contains valid pointers. This is obviously not
00943      * true if the array is being read back from serialisation (the pointers
00944      * are just offsets). Native can't actually work converting the pointers to
00945      * offsets either, because it converts any array pointers to offsets then
00946      * _dereferences the offset_ in order to convert the array elements!
00947      *
00948      * The code below would handle both cases except that the design of this
00949      * function makes it impossible to know when the pointers in lpProps are
00950      * valid. If both lpOld and lpNew are non-NULL, native reads the pointers
00951      * after converting them, so we must do the same. It seems this
00952      * functionality was never tested by MS.
00953      */
00954 
00955 #define RELOC_PTR(p) (((char*)(p)) - (char*)lpOld + (char*)lpNew)
00956 
00957     for (iter = 0; iter < cValues; iter++)
00958     {
00959         switch (PROP_TYPE(lpDest->ulPropTag))
00960         {
00961         case PT_CLSID:
00962             lpDest->Value.lpguid = (LPGUID)RELOC_PTR(lpDest->Value.lpguid);
00963             ulCount += sizeof(GUID);
00964             break;
00965         case PT_STRING8:
00966             ulLen = bBadPtr ? 0 : lstrlenA(lpDest->Value.lpszA) + 1u;
00967             lpDest->Value.lpszA = RELOC_PTR(lpDest->Value.lpszA);
00968             if (bBadPtr)
00969                 ulLen = lstrlenA(lpDest->Value.lpszA) + 1u;
00970             ulCount += ulLen;
00971             break;
00972         case PT_UNICODE:
00973             ulLen = bBadPtr ? 0 : (lstrlenW(lpDest->Value.lpszW) + 1u) * sizeof(WCHAR);
00974             lpDest->Value.lpszW = (LPWSTR)RELOC_PTR(lpDest->Value.lpszW);
00975             if (bBadPtr)
00976                 ulLen = (strlenW(lpDest->Value.lpszW) + 1u) * sizeof(WCHAR);
00977             ulCount += ulLen;
00978             break;
00979         case PT_BINARY:
00980             lpDest->Value.bin.lpb = (LPBYTE)RELOC_PTR(lpDest->Value.bin.lpb);
00981             ulCount += lpDest->Value.bin.cb;
00982             break;
00983         default:
00984             if (lpDest->ulPropTag & MV_FLAG)
00985             {
00986                 /* Since we have to access the array elements, don't map the
00987                  * array unless it is invalid (otherwise, map it at the end)
00988                  */
00989                 if (bBadPtr)
00990                     lpDest->Value.MVszA.lppszA = (LPSTR*)RELOC_PTR(lpDest->Value.MVszA.lppszA);
00991 
00992                 switch (PROP_TYPE(lpProps->ulPropTag))
00993                 {
00994                 case PT_MV_STRING8:
00995                 {
00996                     ulCount += lpDest->Value.MVszA.cValues * sizeof(char *);
00997 
00998                     for (i = 0; i < lpDest->Value.MVszA.cValues; i++)
00999                     {
01000                         ULONG ulStrLen = bBadPtr ? 0 : lstrlenA(lpDest->Value.MVszA.lppszA[i]) + 1u;
01001 
01002                         lpDest->Value.MVszA.lppszA[i] = RELOC_PTR(lpDest->Value.MVszA.lppszA[i]);
01003                         if (bBadPtr)
01004                             ulStrLen = lstrlenA(lpDest->Value.MVszA.lppszA[i]) + 1u;
01005                         ulCount += ulStrLen;
01006                     }
01007                     break;
01008                 }
01009                 case PT_MV_UNICODE:
01010                 {
01011                     ulCount += lpDest->Value.MVszW.cValues * sizeof(WCHAR *);
01012 
01013                     for (i = 0; i < lpDest->Value.MVszW.cValues; i++)
01014                     {
01015                         ULONG ulStrLen = bBadPtr ? 0 : (strlenW(lpDest->Value.MVszW.lppszW[i]) + 1u) * sizeof(WCHAR);
01016 
01017                         lpDest->Value.MVszW.lppszW[i] = (LPWSTR)RELOC_PTR(lpDest->Value.MVszW.lppszW[i]);
01018                         if (bBadPtr)
01019                             ulStrLen = (strlenW(lpDest->Value.MVszW.lppszW[i]) + 1u) * sizeof(WCHAR);
01020                         ulCount += ulStrLen;
01021                     }
01022                     break;
01023                 }
01024                 case PT_MV_BINARY:
01025                 {
01026                     ulCount += lpDest->Value.MVszW.cValues * sizeof(SBinary);
01027 
01028                     for (i = 0; i < lpDest->Value.MVszW.cValues; i++)
01029                     {
01030                         lpDest->Value.MVbin.lpbin[i].lpb = (LPBYTE)RELOC_PTR(lpDest->Value.MVbin.lpbin[i].lpb);
01031                         ulCount += lpDest->Value.MVbin.lpbin[i].cb;
01032                     }
01033                     break;
01034                 }
01035                 default:
01036                     ulCount += UlPropSize(lpDest);
01037                     break;
01038                 }
01039                 if (!bBadPtr)
01040                     lpDest->Value.MVszA.lppszA = (LPSTR*)RELOC_PTR(lpDest->Value.MVszA.lppszA);
01041                 break;
01042             }
01043         }
01044         lpDest++;
01045     }
01046     if (lpCount)
01047         *lpCount = ulCount;
01048 
01049     return S_OK;
01050 }
01051 
01052 /*************************************************************************
01053  * LpValFindProp@12 (MAPI32.173)
01054  *
01055  * Find a property with a given property id in a property array.
01056  *
01057  * PARAMS
01058  *  ulPropTag [I] Property tag containing property id to find
01059  *  cValues   [I] Number of properties in lpProps
01060  *  lpProps   [I] Property array to search
01061  *
01062  * RETURNS
01063  *  A pointer to the matching property, or NULL if none was found.
01064  *
01065  * NOTES
01066  *  This function matches only on the property id and does not care if the
01067  *  property types differ.
01068  */
01069 LPSPropValue WINAPI LpValFindProp(ULONG ulPropTag, ULONG cValues, LPSPropValue lpProps)
01070 {
01071     TRACE("(%d,%d,%p)\n", ulPropTag, cValues, lpProps);
01072 
01073     if (lpProps && cValues)
01074     {
01075         ULONG i;
01076         for (i = 0; i < cValues; i++)
01077         {
01078             if (PROP_ID(ulPropTag) == PROP_ID(lpProps[i].ulPropTag))
01079                 return &lpProps[i];
01080         }
01081     }
01082     return NULL;
01083 }
01084 
01085 /*************************************************************************
01086  * ScDupPropset@16 (MAPI32.174)
01087  *
01088  * Duplicate a property value array into a contiguous block of memory.
01089  *
01090  * PARAMS
01091  *  cValues   [I] Number of properties in lpProps
01092  *  lpProps   [I] Property array to duplicate
01093  *  lpAlloc   [I] Memory allocation function, use MAPIAllocateBuffer()
01094  *  lpNewProp [O] Destination for the newly duplicated property value array
01095  *
01096  * RETURNS
01097  *  Success: S_OK. *lpNewProp contains the duplicated array.
01098  *  Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid,
01099  *           MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails.
01100  */
01101 SCODE WINAPI ScDupPropset(int cValues, LPSPropValue lpProps,
01102                           LPALLOCATEBUFFER lpAlloc, LPSPropValue *lpNewProp)
01103 {
01104     ULONG ulCount;
01105     SCODE sc;
01106 
01107     TRACE("(%d,%p,%p,%p)\n", cValues, lpProps, lpAlloc, lpNewProp);
01108 
01109     sc = ScCountProps(cValues, lpProps, &ulCount);
01110     if (SUCCEEDED(sc))
01111     {
01112         sc = lpAlloc(ulCount, (LPVOID*)lpNewProp);
01113         if (SUCCEEDED(sc))
01114             sc = ScCopyProps(cValues, lpProps, *lpNewProp, &ulCount);
01115     }
01116     return sc;
01117 }
01118 
01119 /*************************************************************************
01120  * FBadRglpszA@8 (MAPI32.175)
01121  *
01122  * Determine if an array of strings is invalid
01123  *
01124  * PARAMS
01125  *  lppszStrs [I] Array of strings to check
01126  *  ulCount   [I] Number of strings in lppszStrs
01127  *
01128  * RETURNS
01129  *  TRUE, if lppszStrs is invalid, FALSE otherwise.
01130  */
01131 BOOL WINAPI FBadRglpszA(LPSTR *lppszStrs, ULONG ulCount)
01132 {
01133     ULONG i;
01134 
01135     TRACE("(%p,%d)\n", lppszStrs, ulCount);
01136 
01137     if (!ulCount)
01138         return FALSE;
01139 
01140     if (!lppszStrs || IsBadReadPtr(lppszStrs, ulCount * sizeof(LPWSTR)))
01141         return TRUE;
01142 
01143     for (i = 0; i < ulCount; i++)
01144     {
01145         if (!lppszStrs[i] || IsBadStringPtrA(lppszStrs[i], -1))
01146             return TRUE;
01147     }
01148     return FALSE;
01149 }
01150 
01151 /*************************************************************************
01152  * FBadRglpszW@8 (MAPI32.176)
01153  *
01154  * See FBadRglpszA.
01155  */
01156 BOOL WINAPI FBadRglpszW(LPWSTR *lppszStrs, ULONG ulCount)
01157 {
01158     ULONG i;
01159 
01160     TRACE("(%p,%d)\n", lppszStrs, ulCount);
01161 
01162     if (!ulCount)
01163         return FALSE;
01164 
01165     if (!lppszStrs || IsBadReadPtr(lppszStrs, ulCount * sizeof(LPWSTR)))
01166         return TRUE;
01167 
01168     for (i = 0; i < ulCount; i++)
01169     {
01170         if (!lppszStrs[i] || IsBadStringPtrW(lppszStrs[i], -1))
01171             return TRUE;
01172     }
01173     return FALSE;
01174 }
01175 
01176 /*************************************************************************
01177  * FBadRowSet@4 (MAPI32.177)
01178  *
01179  * Determine if a row is invalid
01180  *
01181  * PARAMS
01182  *  lpRow [I] Row to check
01183  *
01184  * RETURNS
01185  *  TRUE, if lpRow is invalid, FALSE otherwise.
01186  */
01187 BOOL WINAPI FBadRowSet(LPSRowSet lpRowSet)
01188 {
01189     ULONG i;
01190     TRACE("(%p)\n", lpRowSet);
01191 
01192     if (!lpRowSet || IsBadReadPtr(lpRowSet, CbSRowSet(lpRowSet)))
01193         return TRUE;
01194 
01195     for (i = 0; i < lpRowSet->cRows; i++)
01196     {
01197         if (FBadRow(&lpRowSet->aRow[i]))
01198             return TRUE;
01199     }
01200     return FALSE;
01201 }
01202 
01203 /*************************************************************************
01204  * FBadPropTag@4 (MAPI32.179)
01205  *
01206  * Determine if a property tag is invalid
01207  *
01208  * PARAMS
01209  *  ulPropTag [I] Property tag to check
01210  *
01211  * RETURNS
01212  *  TRUE, if ulPropTag is invalid, FALSE otherwise.
01213  */
01214 ULONG WINAPI FBadPropTag(ULONG ulPropTag)
01215 {
01216     TRACE("(0x%08x)\n", ulPropTag);
01217 
01218     switch (ulPropTag & (~MV_FLAG & PROP_TYPE_MASK))
01219     {
01220     case PT_UNSPECIFIED:
01221     case PT_NULL:
01222     case PT_I2:
01223     case PT_LONG:
01224     case PT_R4:
01225     case PT_DOUBLE:
01226     case PT_CURRENCY:
01227     case PT_APPTIME:
01228     case PT_ERROR:
01229     case PT_BOOLEAN:
01230     case PT_OBJECT:
01231     case PT_I8:
01232     case PT_STRING8:
01233     case PT_UNICODE:
01234     case PT_SYSTIME:
01235     case PT_CLSID:
01236     case PT_BINARY:
01237         return FALSE;
01238     }
01239     return TRUE;
01240 }
01241 
01242 /*************************************************************************
01243  * FBadRow@4 (MAPI32.180)
01244  *
01245  * Determine if a row is invalid
01246  *
01247  * PARAMS
01248  *  lpRow [I] Row to check
01249  *
01250  * RETURNS
01251  *  TRUE, if lpRow is invalid, FALSE otherwise.
01252  */
01253 ULONG WINAPI FBadRow(LPSRow lpRow)
01254 {
01255     ULONG i;
01256     TRACE("(%p)\n", lpRow);
01257 
01258     if (!lpRow || IsBadReadPtr(lpRow, sizeof(SRow)) || !lpRow->lpProps ||
01259         IsBadReadPtr(lpRow->lpProps, lpRow->cValues * sizeof(SPropValue)))
01260         return TRUE;
01261 
01262     for (i = 0; i < lpRow->cValues; i++)
01263     {
01264         if (FBadProp(&lpRow->lpProps[i]))
01265             return TRUE;
01266     }
01267     return FALSE;
01268 }
01269 
01270 /*************************************************************************
01271  * FBadProp@4 (MAPI32.181)
01272  *
01273  * Determine if a property is invalid
01274  *
01275  * PARAMS
01276  *  lpProp [I] Property to check
01277  *
01278  * RETURNS
01279  *  TRUE, if lpProp is invalid, FALSE otherwise.
01280  */
01281 ULONG WINAPI FBadProp(LPSPropValue lpProp)
01282 {
01283     if (!lpProp || IsBadReadPtr(lpProp, sizeof(SPropValue)) ||
01284         FBadPropTag(lpProp->ulPropTag))
01285         return TRUE;
01286 
01287     switch (PROP_TYPE(lpProp->ulPropTag))
01288     {
01289     /* Single value properties containing pointers */
01290     case PT_STRING8:
01291         if (!lpProp->Value.lpszA || IsBadStringPtrA(lpProp->Value.lpszA, -1))
01292             return TRUE;
01293         break;
01294     case PT_UNICODE:
01295         if (!lpProp->Value.lpszW || IsBadStringPtrW(lpProp->Value.lpszW, -1))
01296             return TRUE;
01297         break;
01298     case PT_BINARY:
01299         if (IsBadReadPtr(lpProp->Value.bin.lpb, lpProp->Value.bin.cb))
01300             return TRUE;
01301         break;
01302     case PT_CLSID:
01303         if (IsBadReadPtr(lpProp->Value.lpguid, sizeof(GUID)))
01304             return TRUE;
01305         break;
01306 
01307     /* Multiple value properties (arrays) containing no pointers */
01308     case PT_MV_I2:
01309         return PROP_BadArray(lpProp, sizeof(SHORT));
01310     case PT_MV_LONG:
01311         return PROP_BadArray(lpProp, sizeof(LONG));
01312     case PT_MV_LONGLONG:
01313         return PROP_BadArray(lpProp, sizeof(LONG64));
01314     case PT_MV_FLOAT:
01315         return PROP_BadArray(lpProp, sizeof(float));
01316     case PT_MV_SYSTIME:
01317         return PROP_BadArray(lpProp, sizeof(FILETIME));
01318     case PT_MV_APPTIME:
01319     case PT_MV_DOUBLE:
01320         return PROP_BadArray(lpProp, sizeof(double));
01321     case PT_MV_CURRENCY:
01322         return PROP_BadArray(lpProp, sizeof(CY));
01323     case PT_MV_CLSID:
01324         return PROP_BadArray(lpProp, sizeof(GUID));
01325 
01326     /* Multiple value properties containing pointers */
01327     case PT_MV_STRING8:
01328         return FBadRglpszA(lpProp->Value.MVszA.lppszA,
01329                            lpProp->Value.MVszA.cValues);
01330     case PT_MV_UNICODE:
01331         return FBadRglpszW(lpProp->Value.MVszW.lppszW,
01332                            lpProp->Value.MVszW.cValues);
01333     case PT_MV_BINARY:
01334         return FBadEntryList(&lpProp->Value.MVbin);
01335     }
01336     return FALSE;
01337 }
01338 
01339 /*************************************************************************
01340  * FBadColumnSet@4 (MAPI32.182)
01341  *
01342  * Determine if an array of property tags is invalid
01343  *
01344  * PARAMS
01345  *  lpCols [I] Property tag array to check
01346  *
01347  * RETURNS
01348  *  TRUE, if lpCols is invalid, FALSE otherwise.
01349  */
01350 ULONG WINAPI FBadColumnSet(LPSPropTagArray lpCols)
01351 {
01352     ULONG ulRet = FALSE, i;
01353 
01354     TRACE("(%p)\n", lpCols);
01355 
01356     if (!lpCols || IsBadReadPtr(lpCols, CbSPropTagArray(lpCols)))
01357         ulRet = TRUE;
01358     else
01359     {
01360         for (i = 0; i < lpCols->cValues; i++)
01361         {
01362             if ((lpCols->aulPropTag[i] & PROP_TYPE_MASK) == PT_ERROR ||
01363                 FBadPropTag(lpCols->aulPropTag[i]))
01364             {
01365                 ulRet = TRUE;
01366                 break;
01367             }
01368         }
01369     }
01370     TRACE("Returning %s\n", ulRet ? "TRUE" : "FALSE");
01371     return ulRet;
01372 }
01373 
01374 
01375 /**************************************************************************
01376  *  IMAPIProp {MAPI32}
01377  *
01378  * The default Mapi interface for manipulating object properties.
01379  *
01380  * DESCRIPTION
01381  *  This object provides an interface to an objects properties. It is exposed
01382  *  by several types of Mapi objects in order to simplify the querying and
01383  *  modification of properties.
01384  *
01385  * METHODS
01386  */
01387 
01388 /* A single property in a property data collection */
01389 typedef struct
01390 {
01391   struct list  entry;
01392   ULONG        ulAccess; /* The property value access level */
01393   LPSPropValue value;    /* The property value */
01394 } IPropDataItem, *LPIPropDataItem;
01395 
01396  /* The main property data collection structure */
01397 typedef struct
01398 {
01399     const IPropDataVtbl   *lpVtbl;
01400     LONG             lRef;        /* Reference count */
01401     ALLOCATEBUFFER  *lpAlloc;     /* Memory allocation routine */
01402     ALLOCATEMORE    *lpMore;      /* Linked memory allocation routine */
01403     FREEBUFFER      *lpFree;      /* Memory free routine */
01404     ULONG            ulObjAccess; /* Object access level */
01405     ULONG            ulNumValues; /* Number of items in values list */
01406     struct list      values;      /* List of property values */
01407     CRITICAL_SECTION cs;          /* Lock for thread safety */
01408 } IPropDataImpl;
01409 
01410 /* Internal - Get a property value, assumes lock is held */
01411 static IPropDataItem *IMAPIPROP_GetValue(IPropDataImpl *This, ULONG ulPropTag)
01412 {
01413     struct list *cursor;
01414 
01415     LIST_FOR_EACH(cursor, &This->values)
01416     {
01417         LPIPropDataItem current = LIST_ENTRY(cursor, IPropDataItem, entry);
01418         /* Note that propery types don't have to match, just Id's */
01419         if (PROP_ID(current->value->ulPropTag) == PROP_ID(ulPropTag))
01420             return current;
01421     }
01422     return NULL;
01423 }
01424 
01425 /* Internal - Add a new property value, assumes lock is held */
01426 static IPropDataItem *IMAPIPROP_AddValue(IPropDataImpl *This,
01427                                          LPSPropValue lpProp)
01428 {
01429     LPVOID lpMem;
01430     LPIPropDataItem lpNew;
01431     HRESULT hRet;
01432 
01433     hRet = This->lpAlloc(sizeof(IPropDataItem), &lpMem);
01434 
01435     if (SUCCEEDED(hRet))
01436     {
01437         lpNew = lpMem;
01438         lpNew->ulAccess = IPROP_READWRITE;
01439 
01440         /* Allocate the value separately so we can update it easily */
01441         lpMem = NULL;
01442         hRet = This->lpAlloc(sizeof(SPropValue), &lpMem);
01443         if (SUCCEEDED(hRet))
01444         {
01445             lpNew->value = lpMem;
01446 
01447             hRet = PropCopyMore(lpNew->value, lpProp, This->lpMore, lpMem);
01448             if (SUCCEEDED(hRet))
01449             {
01450                 list_add_tail(&This->values, &lpNew->entry);
01451                 This->ulNumValues++;
01452                 return lpNew;
01453             }
01454             This->lpFree(lpNew->value);
01455         }
01456         This->lpFree(lpNew);
01457     }
01458     return NULL;
01459 }
01460 
01461 /* Internal - Lock an IPropData object */
01462 static inline void IMAPIPROP_Lock(IPropDataImpl *This)
01463 {
01464     EnterCriticalSection(&This->cs);
01465 }
01466 
01467 /* Internal - Unlock an IPropData object */
01468 static inline void IMAPIPROP_Unlock(IPropDataImpl *This)
01469 {
01470     LeaveCriticalSection(&This->cs);
01471 }
01472 
01473 /* This one seems to be missing from mapidefs.h */
01474 #define CbNewSPropProblemArray(c) \
01475     (offsetof(SPropProblemArray,aProblem)+(c)*sizeof(SPropProblem))
01476 
01477 /**************************************************************************
01478  *  IMAPIProp_QueryInterface {MAPI32}
01479  *
01480  * Inherited method from the IUnknown Interface.
01481  * See IUnknown_QueryInterface.
01482  *
01483  * NOTES
01484  * This object exposes the following interfaces:
01485  * - IUnknown() : The default interface for all COM-Objects.
01486  * - IMAPIProp() : The default Mapi interface for manipulating object properties.
01487  */
01488 static inline HRESULT IMAPIProp_fnQueryInterface(LPMAPIPROP iface, REFIID riid, LPVOID *ppvObj)
01489 {
01490     IPropDataImpl *This = (IPropDataImpl*)iface;
01491 
01492     TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppvObj);
01493 
01494     if (!ppvObj || !riid)
01495         return MAPI_E_INVALID_PARAMETER;
01496 
01497     *ppvObj = NULL;
01498 
01499     if(IsEqualIID(riid, &IID_IUnknown) ||
01500        IsEqualIID(riid, &IID_IMAPIProp) ||
01501        IsEqualIID(riid, &IID_IMAPIPropData))
01502     {
01503         *ppvObj = This;
01504         IPropData_AddRef(iface);
01505         TRACE("returning %p\n", *ppvObj);
01506         return S_OK;
01507     }
01508 
01509     TRACE("returning E_NOINTERFACE\n");
01510     return MAPI_E_INTERFACE_NOT_SUPPORTED;
01511 }
01512 
01513 /**************************************************************************
01514  *  IMAPIProp_AddRef {MAPI32}
01515  *
01516  * Inherited method from the IUnknown Interface.
01517  * See IUnknown_AddRef.
01518  */
01519 static inline ULONG IMAPIProp_fnAddRef(LPMAPIPROP iface)
01520 {
01521     IPropDataImpl *This = (IPropDataImpl*)iface;
01522 
01523     TRACE("(%p)->(count before=%u)\n", This, This->lRef);
01524 
01525     return InterlockedIncrement(&This->lRef);
01526 }
01527 
01528 /**************************************************************************
01529  *  IMAPIProp_Release {MAPI32}
01530  *
01531  * Inherited method from the IUnknown Interface.
01532  * See IUnknown_Release.
01533  */
01534 static inline ULONG IMAPIProp_fnRelease(LPMAPIPROP iface)
01535 {
01536     IPropDataImpl *This = (IPropDataImpl*)iface;
01537     LONG lRef;
01538 
01539     TRACE("(%p)->(count before=%u)\n", This, This->lRef);
01540 
01541     lRef = InterlockedDecrement(&This->lRef);
01542     if (!lRef)
01543     {
01544         TRACE("Destroying IPropData (%p)\n",This);
01545 
01546         /* Note: No need to lock, since no other thread is referencing iface */
01547         while (!list_empty(&This->values))
01548         {
01549             struct list *head = list_head(&This->values);
01550             LPIPropDataItem current = LIST_ENTRY(head, IPropDataItem, entry);
01551             list_remove(head);
01552             This->lpFree(current->value);
01553             This->lpFree(current);
01554         }
01555         This->cs.DebugInfo->Spare[0] = 0;
01556         DeleteCriticalSection(&This->cs);
01557         This->lpFree(This);
01558     }
01559     return (ULONG)lRef;
01560 }
01561 
01562 /**************************************************************************
01563  *  IMAPIProp_GetLastError {MAPI32}
01564  *
01565  * Get information about the last error that occurred in an IMAPIProp object.
01566  *
01567  * PARAMS
01568  *  iface    [I] IMAPIProp object that experienced the error
01569  *  hRes     [I] Result of the call that returned an error
01570  *  ulFlags  [I] 0=return Ascii strings, MAPI_UNICODE=return Unicode strings
01571  *  lppError [O] Destination for detailed error information
01572  *
01573  * RETURNS
01574  *  Success: S_OK. *lppError contains details about the last error.
01575  *  Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid,
01576  *           MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails.
01577  *
01578  * NOTES
01579  *  - If this function succeeds, the returned information in *lppError must be
01580  *  freed using MAPIFreeBuffer() once the caller is finished with it.
01581  *  - It is possible for this function to succeed and set *lppError to NULL,
01582  *  if there is no further information to report about hRes.
01583  */
01584 static inline HRESULT
01585 IMAPIProp_fnGetLastError(LPMAPIPROP iface, HRESULT hRes,
01586                          ULONG ulFlags, LPMAPIERROR *lppError)
01587 {
01588     TRACE("(%p,0x%08X,0x%08X,%p)\n", iface, hRes, ulFlags, lppError);
01589 
01590     if (!lppError  || SUCCEEDED(hRes) || (ulFlags & ~MAPI_UNICODE))
01591         return MAPI_E_INVALID_PARAMETER;
01592 
01593     *lppError = NULL;
01594     return S_OK;
01595 }
01596 
01597 /**************************************************************************
01598  *  IMAPIProp_SaveChanges {MAPI32}
01599  *
01600  * Update any changes made to a transactional IMAPIProp object.
01601  *
01602  * PARAMS
01603  *  iface    [I] IMAPIProp object to update
01604  *  ulFlags  [I] Flags controlling the update.
01605  *
01606  * RETURNS
01607  *  Success: S_OK. Any outstanding changes are committed to the object.
01608  *  Failure: An HRESULT error code describing the error.
01609  */
01610 static inline HRESULT
01611 IMAPIProp_fnSaveChanges(LPMAPIPROP iface, ULONG ulFlags)
01612 {
01613     TRACE("(%p,0x%08X)\n", iface, ulFlags);
01614 
01615      /* Since this object is not transacted we do not need to implement this */
01616      /* FIXME: Should we set the access levels to clean? */
01617     return S_OK;
01618 }
01619 
01620 /**************************************************************************
01621  *  IMAPIProp_GetProps {MAPI32}
01622  *
01623  * Get property values from an IMAPIProp object.
01624  *
01625  * PARAMS
01626  *  iface    [I] IMAPIProp object to get the property values from
01627  *  lpTags   [I] Property tage of property values to be retrieved
01628  *  ulFlags  [I] Return 0=Ascii MAPI_UNICODE=Unicode strings for
01629  *                 unspecified types
01630  *  lpCount  [O] Destination for number of properties returned
01631  *  lppProps [O] Destination for returned property values
01632  *
01633  * RETURNS
01634  *  Success: S_OK. *lppProps and *lpCount are updated.
01635  *  Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
01636  *           MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails, or
01637  *           MAPI_W_ERRORS_RETURNED if not all properties were retrieved
01638  *           successfully.
01639  * NOTES
01640  *  - If MAPI_W_ERRORS_RETURNED is returned, any properties that could not be
01641  *    retrieved from iface are present in lppProps with their type
01642  *    changed to PT_ERROR and Id unchanged.
01643  */
01644 static inline HRESULT
01645 IMAPIProp_fnGetProps(LPMAPIPROP iface, LPSPropTagArray lpTags,
01646                      ULONG ulFlags, ULONG *lpCount, LPSPropValue *lppProps)
01647 {
01648     ULONG i;
01649     HRESULT hRet = S_OK;
01650     IPropDataImpl *This = (IPropDataImpl*)iface;
01651 
01652     TRACE("(%p,%p,0x%08x,%p,%p) stub\n", iface, lpTags, ulFlags,
01653           lpCount, lppProps);
01654 
01655     if (!iface || ulFlags & ~MAPI_UNICODE || !lpTags || *lpCount || !lppProps)
01656         return MAPI_E_INVALID_PARAMETER;
01657 
01658     FIXME("semi-stub, flags not supported\n");
01659 
01660     *lpCount = lpTags->cValues;
01661     *lppProps = NULL;
01662 
01663     if (*lpCount)
01664     {
01665         hRet = MAPIAllocateBuffer(*lpCount * sizeof(SPropValue), (LPVOID*)lppProps);
01666         if (FAILED(hRet))
01667             return hRet;
01668 
01669         IMAPIPROP_Lock(This);
01670 
01671         for (i = 0; i < lpTags->cValues; i++)
01672         {
01673             HRESULT hRetTmp = E_INVALIDARG;
01674             LPIPropDataItem item;
01675 
01676             item = IMAPIPROP_GetValue(This, lpTags->aulPropTag[i]);
01677 
01678             if (item)
01679                 hRetTmp = PropCopyMore(&(*lppProps)[i], item->value,
01680                                        This->lpMore, *lppProps);
01681             if (FAILED(hRetTmp))
01682             {
01683                 hRet = MAPI_W_ERRORS_RETURNED;
01684                 (*lppProps)[i].ulPropTag =
01685                     CHANGE_PROP_TYPE(lpTags->aulPropTag[i], PT_ERROR);
01686             }
01687         }
01688 
01689         IMAPIPROP_Unlock(This);
01690     }
01691     return hRet;
01692 }
01693 
01694 /**************************************************************************
01695  *  MAPIProp_GetPropList {MAPI32}
01696  *
01697  * Get the list of property tags for all values in an IMAPIProp object.
01698  *
01699  * PARAMS
01700  *  iface   [I] IMAPIProp object to get the property tag list from
01701  *  ulFlags [I] Return 0=Ascii MAPI_UNICODE=Unicode strings for
01702  *              unspecified types
01703  *  lppTags [O] Destination for the retrieved property tag list
01704  *
01705  * RETURNS
01706  *  Success: S_OK. *lppTags contains the tags for all available properties.
01707  *  Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
01708  *           MAPI_E_BAD_CHARWIDTH, if Ascii or Unicode strings are requested
01709  *           and that type of string is not supported.
01710  */
01711 static inline HRESULT
01712 IMAPIProp_fnGetPropList(LPMAPIPROP iface, ULONG ulFlags,
01713                         LPSPropTagArray *lppTags)
01714 {
01715     IPropDataImpl *This = (IPropDataImpl*)iface;
01716     ULONG i;
01717     HRESULT hRet;
01718 
01719     TRACE("(%p,0x%08x,%p) stub\n", iface, ulFlags, lppTags);
01720 
01721     if (!iface || ulFlags & ~MAPI_UNICODE || !lppTags)
01722         return MAPI_E_INVALID_PARAMETER;
01723 
01724     FIXME("semi-stub, flags not supported\n");
01725 
01726     *lppTags = NULL;
01727 
01728     IMAPIPROP_Lock(This);
01729 
01730     hRet = MAPIAllocateBuffer(CbNewSPropTagArray(This->ulNumValues),
01731                               (LPVOID*)lppTags);
01732     if (SUCCEEDED(hRet))
01733     {
01734         struct list *cursor;
01735 
01736         i = 0;
01737         LIST_FOR_EACH(cursor, &This->values)
01738         {
01739             LPIPropDataItem current = LIST_ENTRY(cursor, IPropDataItem, entry);
01740             (*lppTags)->aulPropTag[i] = current->value->ulPropTag;
01741             i++;
01742         }
01743         (*lppTags)->cValues = This->ulNumValues;
01744     }
01745 
01746     IMAPIPROP_Unlock(This);
01747     return hRet;
01748 }
01749 
01750 /**************************************************************************
01751  *  IMAPIProp_OpenProperty {MAPI32}
01752  *
01753  * Not documented at this time.
01754  *
01755  * RETURNS
01756  *  An HRESULT success/failure code.
01757  */
01758 static inline HRESULT
01759 IMAPIProp_fnOpenProperty(LPMAPIPROP iface, ULONG ulPropTag, LPCIID iid,
01760                          ULONG ulOpts, ULONG ulFlags, LPUNKNOWN *lpUnk)
01761 {
01762     FIXME("(%p,%u,%s,%u,0x%08x,%p) stub\n", iface, ulPropTag,
01763           debugstr_guid(iid), ulOpts, ulFlags, lpUnk);
01764     return MAPI_E_NO_SUPPORT;
01765 }
01766 
01767 
01768 /**************************************************************************
01769  *  IMAPIProp_SetProps {MAPI32}
01770  *
01771  * Add or edit the property values in an IMAPIProp object.
01772  *
01773  * PARAMS
01774  *  iface    [I] IMAPIProp object to get the property tag list from
01775  *  ulValues [I] Number of properties in lpProps
01776  *  lpProps  [I] Property values to set
01777  *  lppProbs [O] Optional destination for any problems that occurred
01778  *
01779  * RETURNS
01780  *  Success: S_OK. The properties in lpProps are added to iface if they don't
01781  *           exist, or changed to the values in lpProps if they do
01782  *  Failure: An HRESULT error code describing the error
01783  */
01784 static inline HRESULT
01785 IMAPIProp_fnSetProps(LPMAPIPROP iface, ULONG ulValues,
01786                      LPSPropValue lpProps, LPSPropProblemArray *lppProbs)
01787 {
01788     IPropDataImpl *This = (IPropDataImpl*)iface;
01789     HRESULT hRet = S_OK;
01790     ULONG i;
01791 
01792     TRACE("(%p,%u,%p,%p)\n", iface, ulValues, lpProps, lppProbs);
01793 
01794     if (!iface || !lpProps)
01795       return MAPI_E_INVALID_PARAMETER;
01796 
01797     for (i = 0; i < ulValues; i++)
01798     {
01799         if (FBadProp(&lpProps[i]) ||
01800             PROP_TYPE(lpProps[i].ulPropTag) == PT_OBJECT ||
01801             PROP_TYPE(lpProps[i].ulPropTag) == PT_NULL)
01802           return MAPI_E_INVALID_PARAMETER;
01803     }
01804 
01805     IMAPIPROP_Lock(This);
01806 
01807     /* FIXME: Under what circumstances is lpProbs created? */
01808     for (i = 0; i < ulValues; i++)
01809     {
01810         LPIPropDataItem item = IMAPIPROP_GetValue(This, lpProps[i].ulPropTag);
01811 
01812         if (item)
01813         {
01814             HRESULT hRetTmp;
01815             LPVOID lpMem = NULL;
01816 
01817             /* Found, so update the existing value */
01818             if (item->value->ulPropTag != lpProps[i].ulPropTag)
01819                 FIXME("semi-stub, overwriting type (not coercing)\n");
01820 
01821             hRetTmp = This->lpAlloc(sizeof(SPropValue), &lpMem);
01822             if (SUCCEEDED(hRetTmp))
01823             {
01824                 hRetTmp = PropCopyMore(lpMem, &lpProps[i], This->lpMore, lpMem);
01825                 if (SUCCEEDED(hRetTmp))
01826                 {
01827                     This->lpFree(item->value);
01828                     item->value = lpMem;
01829                     continue;
01830                 }
01831                 This->lpFree(lpMem);
01832             }
01833             hRet = hRetTmp;
01834         }
01835         else
01836         {
01837             /* Add new value */
01838             if (!IMAPIPROP_AddValue(This, &lpProps[i]))
01839                 hRet = MAPI_E_NOT_ENOUGH_MEMORY;
01840         }
01841     }
01842 
01843     IMAPIPROP_Unlock(This);
01844     return hRet;
01845 }
01846 
01847 /**************************************************************************
01848  *  IMAPIProp_DeleteProps {MAPI32}
01849  *
01850  * Delete one or more property values from an IMAPIProp object.
01851  *
01852  * PARAMS
01853  *  iface    [I] IMAPIProp object to remove property values from.
01854  *  lpTags   [I] Collection of property Id's to remove from iface.
01855  *  lppProbs [O] Destination for problems encountered, if any.
01856  *
01857  * RETURNS
01858  *  Success: S_OK. Any properties in iface matching property Id's in lpTags have
01859  *           been deleted. If lppProbs is non-NULL it contains details of any
01860  *           errors that occurred.
01861  *  Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
01862  *           E_ACCESSDENIED, if this object was created using CreateIProp() and
01863  *           a subsequent call to IPropData_SetObjAcess() was made specifying
01864  *           IPROP_READONLY as the access type.
01865  *
01866  * NOTES
01867  *  - lppProbs will not be populated for cases where a property Id is present
01868  *    in lpTags but not in iface.
01869  *  - lppProbs should be deleted with MAPIFreeBuffer() if returned.
01870  */
01871 static inline HRESULT
01872 IMAPIProp_fnDeleteProps(LPMAPIPROP iface, LPSPropTagArray lpTags,
01873                         LPSPropProblemArray *lppProbs)
01874 {
01875     IPropDataImpl *This = (IPropDataImpl*)iface;
01876     ULONG i, numProbs = 0;
01877     HRESULT hRet = S_OK;
01878 
01879     TRACE("(%p,%p,%p)\n", iface, lpTags, lppProbs);
01880 
01881     if (!iface || !lpTags)
01882         return MAPI_E_INVALID_PARAMETER;
01883 
01884     if (lppProbs)
01885         *lppProbs = NULL;
01886 
01887     for (i = 0; i < lpTags->cValues; i++)
01888     {
01889         if (FBadPropTag(lpTags->aulPropTag[i]) ||
01890             PROP_TYPE(lpTags->aulPropTag[i]) == PT_OBJECT ||
01891             PROP_TYPE(lpTags->aulPropTag[i]) == PT_NULL)
01892           return MAPI_E_INVALID_PARAMETER;
01893     }
01894 
01895     IMAPIPROP_Lock(This);
01896 
01897     if (This->ulObjAccess != IPROP_READWRITE)
01898     {
01899         IMAPIPROP_Unlock(This);
01900         return E_ACCESSDENIED;
01901     }
01902 
01903     for (i = 0; i < lpTags->cValues; i++)
01904     {
01905         LPIPropDataItem item = IMAPIPROP_GetValue(This, lpTags->aulPropTag[i]);
01906 
01907         if (item)
01908         {
01909             if (item->ulAccess & IPROP_READWRITE)
01910             {
01911                 /* Everything hunky-dory, remove the item */
01912                 list_remove(&item->entry);
01913                 This->lpFree(item->value); /* Also frees value pointers */
01914                 This->lpFree(item);
01915                 This->ulNumValues--;
01916             }
01917             else if (lppProbs)
01918             {
01919                  /* Can't write the value. Create/populate problems array */
01920                  if (!*lppProbs)
01921                  {
01922                      /* Create problems array */
01923                      ULONG ulSize = CbNewSPropProblemArray(lpTags->cValues - i);
01924                      HRESULT hRetTmp = MAPIAllocateBuffer(ulSize, (LPVOID*)lppProbs);
01925                      if (FAILED(hRetTmp))
01926                          hRet = hRetTmp;
01927                  }
01928                  if (*lppProbs)
01929                  {
01930                      LPSPropProblem lpProb = &(*lppProbs)->aProblem[numProbs];
01931                      lpProb->ulIndex = i;
01932                      lpProb->ulPropTag = lpTags->aulPropTag[i];
01933                      lpProb->scode = E_ACCESSDENIED;
01934                      numProbs++;
01935                  }
01936             }
01937         }
01938     }
01939     if (lppProbs && *lppProbs)
01940         (*lppProbs)->cProblem = numProbs;
01941 
01942     IMAPIPROP_Unlock(This);
01943     return hRet;
01944 }
01945 
01946 
01947 /**************************************************************************
01948  *  IMAPIProp_CopyTo {MAPI32}
01949  *
01950  * Not documented at this time.
01951  *
01952  * RETURNS
01953  *  An HRESULT success/failure code.
01954  */
01955 static inline HRESULT
01956 IMAPIProp_fnCopyTo(LPMAPIPROP iface, ULONG niids, LPCIID lpiidExcl,
01957                    LPSPropTagArray lpPropsExcl, ULONG ulParam,
01958                    LPMAPIPROGRESS lpIProgress, LPCIID lpIfaceIid, LPVOID lpDstObj,
01959                    ULONG ulFlags, LPSPropProblemArray *lppProbs)
01960 {
01961     FIXME("(%p,%u,%p,%p,%x,%p,%s,%p,0x%08X,%p) stub\n", iface, niids,
01962           lpiidExcl, lpPropsExcl, ulParam, lpIProgress,
01963           debugstr_guid(lpIfaceIid), lpDstObj, ulFlags, lppProbs);
01964     return MAPI_E_NO_SUPPORT;
01965 }
01966 
01967 /**************************************************************************
01968  *  IMAPIProp_CopyProps {MAPI32}
01969  *
01970  * Not documented at this time.
01971  *
01972  * RETURNS
01973  *  An HRESULT success/failure code.
01974  */
01975 static inline HRESULT
01976 IMAPIProp_fnCopyProps(LPMAPIPROP iface, LPSPropTagArray lpInclProps,
01977                       ULONG ulParam, LPMAPIPROGRESS lpIProgress, LPCIID lpIface,
01978                       LPVOID lpDstObj, ULONG ulFlags,
01979                       LPSPropProblemArray *lppProbs)
01980 {
01981     FIXME("(%p,%p,%x,%p,%s,%p,0x%08X,%p) stub\n", iface, lpInclProps,
01982           ulParam, lpIProgress, debugstr_guid(lpIface), lpDstObj, ulFlags,
01983           lppProbs);
01984     return MAPI_E_NO_SUPPORT;
01985 }
01986 
01987 /**************************************************************************
01988  *  IMAPIProp_GetNamesFromIDs {MAPI32}
01989  *
01990  * Get the names of properties from their identifiers.
01991  *
01992  * PARAMS
01993  *  iface       [I]   IMAPIProp object to operate on
01994  *  lppPropTags [I/O] Property identifiers to get the names for, or NULL to
01995  *                    get all names
01996  *  iid         [I]   Property set identifier, or NULL
01997  *  ulFlags     [I]   MAPI_NO_IDS=Don't return numeric named properties,
01998  *                    or MAPI_NO_STRINGS=Don't return strings
01999  *  lpCount     [O]   Destination for number of properties returned
02000  *  lpppNames   [O]   Destination for returned names
02001  *
02002  * RETURNS
02003  *  Success: S_OK. *lppPropTags and lpppNames contain the returned
02004  *           name/identifiers.
02005  *  Failure: MAPI_E_NO_SUPPORT, if the object does not support named properties,
02006  *           MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails, or
02007  *           MAPI_W_ERRORS_RETURNED if not all properties were retrieved
02008  *           successfully.
02009  */
02010 static inline HRESULT
02011 IMAPIProp_fnGetNamesFromIDs(LPMAPIPROP iface, LPSPropTagArray *lppPropTags,
02012                             LPGUID iid, ULONG ulFlags, ULONG *lpCount,
02013                             LPMAPINAMEID **lpppNames)
02014 {
02015     FIXME("(%p,%p,%s,0x%08X,%p,%p) stub\n", iface, lppPropTags,
02016           debugstr_guid(iid), ulFlags, lpCount, lpppNames);
02017     return MAPI_E_NO_SUPPORT;
02018 }
02019 
02020 /**************************************************************************
02021  *  IMAPIProp_GetIDsFromNames {MAPI32}
02022  *
02023  * Get property identifiers associated with one or more named properties.
02024  *
02025  * PARAMS
02026  *  iface       [I] IMAPIProp object to operate on
02027  *  ulNames     [I] Number of names in lppNames
02028  *  lppNames    [I] Names to query or create, or NULL to query all names
02029  *  ulFlags     [I] Pass MAPI_CREATE to create new named properties
02030  *  lppPropTags [O] Destination for queried or created property identifiers
02031  *
02032  * RETURNS
02033  *  Success: S_OK. *lppPropTags contains the property tags created or requested.
02034  *  Failure: MAPI_E_NO_SUPPORT, if the object does not support named properties,
02035  *           MAPI_E_TOO_BIG, if the object cannot process the number of
02036  *           properties involved.
02037  *           MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails, or
02038  *           MAPI_W_ERRORS_RETURNED if not all properties were retrieved
02039  *           successfully.
02040  */
02041 static inline HRESULT
02042 IMAPIProp_fnGetIDsFromNames(LPMAPIPROP iface, ULONG ulNames,
02043                             LPMAPINAMEID *lppNames, ULONG ulFlags,
02044                             LPSPropTagArray *lppPropTags)
02045 {
02046     FIXME("(%p,%d,%p,0x%08X,%p) stub\n",
02047           iface, ulNames, lppNames, ulFlags, lppPropTags);
02048     return MAPI_E_NO_SUPPORT;
02049 }
02050 
02051 /**************************************************************************
02052  *  IPropData {MAPI32}
02053  *
02054  * A default Mapi interface to provide manipulation of object properties.
02055  *
02056  * DESCRIPTION
02057  *  This object provides a default interface suitable in some cases as an
02058  *  implementation of the IMAPIProp interface (which has no default
02059  *  implementation). In addition to the IMAPIProp() methods inherited, this
02060  *  interface allows read/write control over access to the object and its
02061  *  individual properties.
02062  *
02063  *  To obtain the default implementation of this interface from Mapi, call
02064  *  CreateIProp().
02065  *
02066  * METHODS
02067  */
02068 
02069 /**************************************************************************
02070  *  IPropData_QueryInterface {MAPI32}
02071  *
02072  * Inherited method from the IMAPIProp Interface.
02073  * See IMAPIProp_QueryInterface.
02074  */
02075 static HRESULT WINAPI
02076 IPropData_fnQueryInterface(LPPROPDATA iface, REFIID riid, LPVOID *ppvObj)
02077 {
02078     return IMAPIProp_fnQueryInterface((LPMAPIPROP)iface, riid, ppvObj);
02079 }
02080 
02081 /**************************************************************************
02082  *  IPropData_AddRef {MAPI32}
02083  *
02084  * Inherited method from the IMAPIProp Interface.
02085  * See IMAPIProp_AddRef.
02086  */
02087 static ULONG WINAPI
02088 IPropData_fnAddRef(LPPROPDATA iface)
02089 {
02090     return IMAPIProp_fnAddRef((LPMAPIPROP)iface);
02091 }
02092 
02093 /**************************************************************************
02094  *  IPropData_Release {MAPI32}
02095  *
02096  * Inherited method from the IMAPIProp Interface.
02097  * See IMAPIProp_Release.
02098  */
02099 static ULONG WINAPI
02100 IPropData_fnRelease(LPPROPDATA iface)
02101 {
02102     return IMAPIProp_fnRelease((LPMAPIPROP)iface);
02103 }
02104 
02105 /**************************************************************************
02106  *  IPropData_GetLastError {MAPI32}
02107  *
02108  * Inherited method from the IMAPIProp Interface.
02109  * See IMAPIProp_GetLastError.
02110  */
02111 static HRESULT WINAPI
02112 IPropData_fnGetLastError(LPPROPDATA iface, HRESULT hRes, ULONG ulFlags,
02113                          LPMAPIERROR *lppError)
02114 {
02115     return IMAPIProp_fnGetLastError((LPMAPIPROP)iface, hRes, ulFlags, lppError);
02116 }
02117 
02118 /**************************************************************************
02119  *  IPropData_SaveChanges {MAPI32}
02120  *
02121  * Inherited method from the IMAPIProp Interface.
02122  * See IMAPIProp_SaveChanges.
02123  */
02124 static HRESULT WINAPI
02125 IPropData_fnSaveChanges(LPPROPDATA iface, ULONG ulFlags)
02126 {
02127     return IMAPIProp_fnSaveChanges((LPMAPIPROP)iface, ulFlags);
02128 }
02129 
02130 /**************************************************************************
02131  *  IPropData_GetProps {MAPI32}
02132  *
02133  * Inherited method from the IMAPIProp Interface.
02134  * See IMAPIProp_GetProps.
02135  */
02136 static HRESULT WINAPI
02137 IPropData_fnGetProps(LPPROPDATA iface, LPSPropTagArray lpPropTags,
02138                      ULONG ulFlags, ULONG *lpCount, LPSPropValue *lppProps)
02139 {
02140     return IMAPIProp_fnGetProps((LPMAPIPROP)iface, lpPropTags, ulFlags,
02141                                 lpCount, lppProps);
02142 }
02143 
02144 /**************************************************************************
02145  *  IPropData_GetPropList {MAPI32}
02146  *
02147  * Inherited method from the IMAPIProp Interface.
02148  * See IMAPIProp_GetPropList.
02149  */
02150 static HRESULT WINAPI
02151 IPropData_fnGetPropList(LPPROPDATA iface, ULONG ulFlags,
02152                                               LPSPropTagArray *lppPropTags)
02153 {
02154     return IMAPIProp_fnGetPropList((LPMAPIPROP)iface, ulFlags, lppPropTags);
02155 }
02156 
02157 /**************************************************************************
02158  *  IPropData_OpenProperty {MAPI32}
02159  *
02160  * Inherited method from the IMAPIProp Interface.
02161  * See IMAPIProp_OpenProperty.
02162  */
02163 static HRESULT WINAPI
02164 IPropData_fnOpenProperty(LPPROPDATA iface, ULONG ulPropTag, LPCIID iid,
02165                          ULONG ulOpts, ULONG ulFlags, LPUNKNOWN *lpUnk)
02166 {
02167     return IMAPIProp_fnOpenProperty((LPMAPIPROP)iface, ulPropTag, iid,
02168                                     ulOpts, ulFlags, lpUnk);
02169 }
02170 
02171 /**************************************************************************
02172  *  IPropData_SetProps {MAPI32}
02173  *
02174  * Inherited method from the IMAPIProp Interface.
02175  * See IMAPIProp_SetProps.
02176  */
02177 static HRESULT WINAPI
02178 IPropData_fnSetProps(LPPROPDATA iface, ULONG cValues, LPSPropValue lpProps,
02179                      LPSPropProblemArray *lppProbs)
02180 {
02181     return IMAPIProp_fnSetProps((LPMAPIPROP)iface, cValues, lpProps, lppProbs);
02182 }
02183 
02184 /**************************************************************************
02185  *  IPropData_DeleteProps {MAPI32}
02186  *
02187  * Inherited method from the IMAPIProp Interface.
02188  * See IMAPIProp_DeleteProps.
02189  */
02190 static HRESULT WINAPI
02191 IPropData_fnDeleteProps(LPPROPDATA iface, LPSPropTagArray lpPropTags,
02192                         LPSPropProblemArray *lppProbs)
02193 {
02194     return IMAPIProp_fnDeleteProps((LPMAPIPROP)iface, lpPropTags, lppProbs);
02195 }
02196 
02197 /**************************************************************************
02198  *  IPropData_CopyTo {MAPI32}
02199  *
02200  * Inherited method from the IMAPIProp Interface.
02201  * See IMAPIProp_CopyTo.
02202  */
02203 static HRESULT WINAPI
02204 IPropData_fnCopyTo(LPPROPDATA iface, ULONG ciidExclude, LPCIID lpIid,
02205                    LPSPropTagArray lpProps, ULONG ulParam,
02206                    LPMAPIPROGRESS lpProgress, LPCIID lpIface, LPVOID lpDst,
02207                    ULONG ulFlags, LPSPropProblemArray *lppProbs)
02208 {
02209     return IMAPIProp_fnCopyTo((LPMAPIPROP)iface, ciidExclude, lpIid, lpProps,
02210                               ulParam, lpProgress, lpIface, lpDst,
02211                               ulFlags, lppProbs);
02212 }
02213 
02214 /**************************************************************************
02215  *  IPropData_CopyProps {MAPI32}
02216  *
02217  * Inherited method from the IMAPIProp Interface.
02218  * See IMAPIProp_CopyProps.
02219  */
02220 static HRESULT WINAPI
02221 IPropData_fnCopyProps(LPPROPDATA iface, LPSPropTagArray lpProps,
02222                       ULONG ulParam, LPMAPIPROGRESS lpProgress, LPCIID lpIface,
02223                       LPVOID lpDst, ULONG ulFlags, LPSPropProblemArray *lppProbs)
02224 {
02225     return IMAPIProp_fnCopyProps((LPMAPIPROP)iface, lpProps, ulParam,
02226                                  lpProgress, lpIface, lpDst, ulFlags, lppProbs);
02227 }
02228 
02229 /**************************************************************************
02230  *  IPropData_GetNamesFromIDs {MAPI32}
02231  *
02232  * Inherited method from the IMAPIProp Interface.
02233  * See IMAPIProp_GetNamesFromIDs.
02234  */
02235 static HRESULT WINAPI
02236 IPropData_fnGetNamesFromIDs(LPPROPDATA iface, LPSPropTagArray *lppPropTags,
02237                             LPGUID iid, ULONG ulFlags, ULONG *lpCount,
02238                             LPMAPINAMEID **lpppNames)
02239 {
02240     return IMAPIProp_fnGetNamesFromIDs((LPMAPIPROP)iface, lppPropTags, iid,
02241                                        ulFlags, lpCount, lpppNames);
02242 }
02243 
02244 /**************************************************************************
02245  *  IPropData_GetIDsFromNames {MAPI32}
02246  *
02247  * Inherited method from the IMAPIProp Interface.
02248  * See IMAPIProp_GetIDsFromNames.
02249  */
02250 static HRESULT WINAPI
02251 IPropData_fnGetIDsFromNames(LPPROPDATA iface, ULONG ulNames,
02252                             LPMAPINAMEID *lppNames, ULONG ulFlags,
02253                             LPSPropTagArray *lppPropTags)
02254 {
02255     return IMAPIProp_fnGetIDsFromNames((LPMAPIPROP)iface, ulNames, lppNames,
02256                                        ulFlags, lppPropTags);
02257 }
02258 
02259 /**************************************************************************
02260  *  IPropData_HrSetObjAccess {MAPI32}
02261  *
02262  * Set the access level of an IPropData object.
02263  *
02264  * PARAMS
02265  *  iface    [I] IPropData object to set the access on
02266  *  ulAccess [I] Either IPROP_READONLY or IPROP_READWRITE for read or
02267  *               read/write access respectively.
02268  *
02269  * RETURNS
02270  *  Success: S_OK. The objects access level is changed.
02271  *  Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
02272  */
02273 static HRESULT WINAPI
02274 IPropData_fnHrSetObjAccess(LPPROPDATA iface, ULONG ulAccess)
02275 {
02276     IPropDataImpl *This = (IPropDataImpl*)iface;
02277 
02278     TRACE("(%p,%x)\n", iface, ulAccess);
02279 
02280     if (!iface || ulAccess < IPROP_READONLY || ulAccess > IPROP_READWRITE)
02281         return MAPI_E_INVALID_PARAMETER;
02282 
02283     IMAPIPROP_Lock(This);
02284 
02285     This->ulObjAccess = ulAccess;
02286 
02287     IMAPIPROP_Unlock(This);
02288     return S_OK;
02289 }
02290 
02291 /* Internal - determine if an access value is bad */
02292 static inline BOOL PROP_IsBadAccess(ULONG ulAccess)
02293 {
02294     switch (ulAccess)
02295     {
02296     case IPROP_READONLY|IPROP_CLEAN:
02297     case IPROP_READONLY|IPROP_DIRTY:
02298     case IPROP_READWRITE|IPROP_CLEAN:
02299     case IPROP_READWRITE|IPROP_DIRTY:
02300         return FALSE;
02301     }
02302     return TRUE;
02303 }
02304 
02305 /**************************************************************************
02306  *  IPropData_HrSetPropAccess {MAPI32}
02307  *
02308  * Set the access levels for a group of property values in an IPropData object.
02309  *
02310  * PARAMS
02311  *  iface    [I] IPropData object to set access levels in.
02312  *  lpTags   [I] List of property Id's to set access for.
02313  *  lpAccess [O] Access level for each property in lpTags.
02314  *
02315  * RETURNS
02316  *  Success: S_OK. The access level of each property value in lpTags that is
02317  *           present in iface is changed.
02318  *  Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
02319  *
02320  * NOTES
02321  *  - Each access level in lpAccess must contain at least one of IPROP_READONLY
02322  *    or IPROP_READWRITE, but not both, and also IPROP_CLEAN or IPROP_DIRTY,
02323  *    but not both. No other bits should be set.
02324  *  - If a property Id in lpTags is not present in iface, it is ignored.
02325  */
02326 static HRESULT WINAPI
02327 IPropData_fnHrSetPropAccess(LPPROPDATA iface, LPSPropTagArray lpTags,
02328                             ULONG *lpAccess)
02329 {
02330     IPropDataImpl *This = (IPropDataImpl*)iface;
02331 
02332     ULONG i;
02333 
02334     TRACE("(%p,%p,%p)\n", iface, lpTags, lpAccess);
02335 
02336     if (!iface || !lpTags || !lpAccess)
02337         return MAPI_E_INVALID_PARAMETER;
02338 
02339     for (i = 0; i < lpTags->cValues; i++)
02340     {
02341         if (FBadPropTag(lpTags->aulPropTag[i]) || PROP_IsBadAccess(lpAccess[i]))
02342             return MAPI_E_INVALID_PARAMETER;
02343     }
02344 
02345     IMAPIPROP_Lock(This);
02346 
02347     for (i = 0; i < lpTags->cValues; i++)
02348     {
02349         LPIPropDataItem item = IMAPIPROP_GetValue(This, lpTags->aulPropTag[i]);
02350 
02351         if (item)
02352             item->ulAccess = lpAccess[i];
02353     }
02354 
02355     IMAPIPROP_Unlock(This);
02356     return S_OK;
02357 }
02358 
02359 /**************************************************************************
02360  *  IPropData_HrGetPropAccess {MAPI32}
02361  *
02362  * Get the access levels for a group of property values in an IPropData object.
02363  *
02364  * PARAMS
02365  *  iface     [I] IPropData object to get access levels from.
02366  *  lppTags   [O] Destination for the list of property Id's in iface.
02367  *  lppAccess [O] Destination for access level for each property in lppTags.
02368  *
02369  * RETURNS
02370  *  Success: S_OK. lppTags and lppAccess contain the property Id's and the
02371  *           Access level of each property value in iface.
02372  *  Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid, or
02373  *           MAPI_E_NOT_ENOUGH_MEMORY if memory allocation fails.
02374  *
02375  * NOTES
02376  *  - *lppTags and *lppAccess should be freed with MAPIFreeBuffer() by the caller.
02377  */
02378 static HRESULT WINAPI
02379 IPropData_fnHrGetPropAccess(LPPROPDATA iface, LPSPropTagArray *lppTags,
02380                             ULONG **lppAccess)
02381 {
02382     IPropDataImpl *This = (IPropDataImpl*)iface;
02383     LPVOID lpMem;
02384     HRESULT hRet;
02385     ULONG i;
02386 
02387     TRACE("(%p,%p,%p) stub\n", iface, lppTags, lppAccess);
02388 
02389     if (!iface || !lppTags || !lppAccess)
02390         return MAPI_E_INVALID_PARAMETER;
02391 
02392     *lppTags = NULL;
02393     *lppAccess = NULL;
02394 
02395     IMAPIPROP_Lock(This);
02396 
02397     hRet = This->lpAlloc(CbNewSPropTagArray(This->ulNumValues), &lpMem);
02398     if (SUCCEEDED(hRet))
02399     {
02400         *lppTags = lpMem;
02401 
02402         hRet = This->lpAlloc(This->ulNumValues * sizeof(ULONG), &lpMem);
02403         if (SUCCEEDED(hRet))
02404         {
02405             struct list *cursor;
02406 
02407             *lppAccess = lpMem;
02408             (*lppTags)->cValues = This->ulNumValues;
02409 
02410             i = 0;
02411             LIST_FOR_EACH(cursor, &This->values)
02412             {
02413                 LPIPropDataItem item = LIST_ENTRY(cursor, IPropDataItem, entry);
02414                 (*lppTags)->aulPropTag[i] = item->value->ulPropTag;
02415                 (*lppAccess)[i] = item->ulAccess;
02416                 i++;
02417             }
02418             IMAPIPROP_Unlock(This);
02419             return S_OK;
02420         }
02421         This->lpFree(*lppTags);
02422         *lppTags = 0;
02423     }
02424     IMAPIPROP_Unlock(This);
02425     return MAPI_E_NOT_ENOUGH_MEMORY;
02426 }
02427 
02428 /**************************************************************************
02429  *  IPropData_HrAddObjProps {MAPI32}
02430  *
02431  * Not documented at this time.
02432  *
02433  * RETURNS
02434  *  An HRESULT success/failure code.
02435  */
02436 static HRESULT WINAPI
02437 IPropData_fnHrAddObjProps(LPPROPDATA iface, LPSPropTagArray lpTags,
02438                           LPSPropProblemArray *lppProbs)
02439 {
02440 #if 0
02441     ULONG i;
02442     HRESULT hRet;
02443     LPSPropValue lpValues;
02444 #endif
02445 
02446     FIXME("(%p,%p,%p) stub\n", iface, lpTags, lppProbs);
02447 
02448     if (!iface || !lpTags)
02449         return MAPI_E_INVALID_PARAMETER;
02450 
02451     /* FIXME: Below is the obvious implementation, adding all the properties
02452      *        in lpTags to the object. However, it doesn't appear that this
02453      *        is what this function does.
02454      */
02455     return S_OK;
02456 #if 0
02457     if (!lpTags->cValues)
02458         return S_OK;
02459 
02460     lpValues = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
02461                          lpTags->cValues * sizeof(SPropValue));
02462     if (!lpValues)
02463         return MAPI_E_NOT_ENOUGH_MEMORY;
02464 
02465     for (i = 0; i < lpTags->cValues; i++)
02466         lpValues[i].ulPropTag = lpTags->aulPropTag[i];
02467 
02468     hRet = IPropData_SetProps(iface, lpTags->cValues, lpValues, lppProbs);
02469     HeapFree(GetProcessHeap(), 0, lpValues);
02470     return hRet;
02471 #endif
02472 }
02473 
02474 static const IPropDataVtbl IPropDataImpl_vtbl =
02475 {
02476     IPropData_fnQueryInterface,
02477     IPropData_fnAddRef,
02478     IPropData_fnRelease,
02479     IPropData_fnGetLastError,
02480     IPropData_fnSaveChanges,
02481     IPropData_fnGetProps,
02482     IPropData_fnGetPropList,
02483     IPropData_fnOpenProperty,
02484     IPropData_fnSetProps,
02485     IPropData_fnDeleteProps,
02486     IPropData_fnCopyTo,
02487     IPropData_fnCopyProps,
02488     IPropData_fnGetNamesFromIDs,
02489     IPropData_fnGetIDsFromNames,
02490     IPropData_fnHrSetObjAccess,
02491     IPropData_fnHrSetPropAccess,
02492     IPropData_fnHrGetPropAccess,
02493     IPropData_fnHrAddObjProps
02494 };
02495 
02496 /*************************************************************************
02497  * CreateIProp@24 (MAPI32.60)
02498  *
02499  * Create an IPropData object.
02500  *
02501  * PARAMS
02502  *  iid         [I] GUID of the object to create. Use &IID_IMAPIPropData or NULL
02503  *  lpAlloc     [I] Memory allocation function. Use MAPIAllocateBuffer()
02504  *  lpMore      [I] Linked memory allocation function. Use MAPIAllocateMore()
02505  *  lpFree      [I] Memory free function. Use MAPIFreeBuffer()
02506  *  lpReserved  [I] Reserved, set to NULL
02507  *  lppPropData [O] Destination for created IPropData object
02508  *
02509  * RETURNS
02510  *  Success: S_OK. *lppPropData contains the newly created object.
02511  *  Failure: MAPI_E_INTERFACE_NOT_SUPPORTED, if iid is non-NULL and not supported,
02512  *           MAPI_E_INVALID_PARAMETER, if any parameter is invalid
02513  */
02514 SCODE WINAPI CreateIProp(LPCIID iid, ALLOCATEBUFFER *lpAlloc,
02515                          ALLOCATEMORE *lpMore, FREEBUFFER *lpFree,
02516                          LPVOID lpReserved, LPPROPDATA *lppPropData)
02517 {
02518     IPropDataImpl *lpPropData;
02519     SCODE scode;
02520 
02521     TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_guid(iid), lpAlloc, lpMore, lpFree,
02522           lpReserved, lppPropData);
02523 
02524     if (lppPropData)
02525         *lppPropData = NULL;
02526 
02527     if (iid && !IsEqualGUID(iid, &IID_IMAPIPropData))
02528         return MAPI_E_INTERFACE_NOT_SUPPORTED;
02529 
02530     if (!lpAlloc || !lpMore || !lpFree || lpReserved || !lppPropData)
02531         return MAPI_E_INVALID_PARAMETER;
02532 
02533     scode = lpAlloc(sizeof(IPropDataImpl), (LPVOID*)&lpPropData);
02534 
02535     if (SUCCEEDED(scode))
02536     {
02537         lpPropData->lpVtbl = &IPropDataImpl_vtbl;
02538         lpPropData->lRef = 1;
02539         lpPropData->lpAlloc = lpAlloc;
02540         lpPropData->lpMore = lpMore;
02541         lpPropData->lpFree = lpFree;
02542         lpPropData->ulObjAccess = IPROP_READWRITE;
02543         lpPropData->ulNumValues = 0;
02544         list_init(&lpPropData->values);
02545         InitializeCriticalSection(&lpPropData->cs);
02546         lpPropData->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IPropDataImpl.cs");
02547         *lppPropData = (LPPROPDATA)lpPropData;
02548     }
02549     return scode;
02550 }

Generated on Sat May 26 2012 04:23:11 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.