1 /* 2 * Unit test suite for MAPI property functions 3 * 4 * Copyright 2004 Jon Griffiths 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include "wine/test.h" 22 #include "windef.h" 23 #include "winbase.h" 24 #include "winuser.h" 25 #include "winerror.h" 26 #include "winnt.h" 27 #include "initguid.h" 28 #include "mapiutil.h" 29 #include "mapitags.h" 30 #include "mapi32_test.h" 31 32 static HMODULE hMapi32 = 0; 33 34 static SCODE (WINAPI *pScInitMapiUtil)(ULONG); 35 static void (WINAPI *pDeinitMapiUtil)(void); 36 static SCODE (WINAPI *pPropCopyMore)(LPSPropValue,LPSPropValue,ALLOCATEMORE*,LPVOID); 37 static ULONG (WINAPI *pUlPropSize)(LPSPropValue); 38 static BOOL (WINAPI *pFPropContainsProp)(LPSPropValue,LPSPropValue,ULONG); 39 static BOOL (WINAPI *pFPropCompareProp)(LPSPropValue,ULONG,LPSPropValue); 40 static LONG (WINAPI *pLPropCompareProp)(LPSPropValue,LPSPropValue); 41 static LPSPropValue (WINAPI *pPpropFindProp)(LPSPropValue,ULONG,ULONG); 42 static SCODE (WINAPI *pScCountProps)(INT,LPSPropValue,ULONG*); 43 static SCODE (WINAPI *pScCopyProps)(int,LPSPropValue,LPVOID,ULONG*); 44 static SCODE (WINAPI *pScRelocProps)(int,LPSPropValue,LPVOID,LPVOID,ULONG*); 45 static LPSPropValue (WINAPI *pLpValFindProp)(ULONG,ULONG,LPSPropValue); 46 static BOOL (WINAPI *pFBadRglpszA)(LPSTR*,ULONG); 47 static BOOL (WINAPI *pFBadRglpszW)(LPWSTR*,ULONG); 48 static BOOL (WINAPI *pFBadRowSet)(LPSRowSet); 49 static ULONG (WINAPI *pFBadPropTag)(ULONG); 50 static ULONG (WINAPI *pFBadRow)(LPSRow); 51 static ULONG (WINAPI *pFBadProp)(LPSPropValue); 52 static ULONG (WINAPI *pFBadColumnSet)(LPSPropTagArray); 53 static SCODE (WINAPI *pCreateIProp)(LPCIID,ALLOCATEBUFFER*,ALLOCATEMORE*, 54 FREEBUFFER*,LPVOID,LPPROPDATA*); 55 static SCODE (WINAPI *pMAPIAllocateBuffer)(ULONG, LPVOID); 56 static SCODE (WINAPI *pMAPIAllocateMore)(ULONG, LPVOID, LPVOID); 57 static SCODE (WINAPI *pMAPIInitialize)(LPVOID); 58 static SCODE (WINAPI *pMAPIFreeBuffer)(LPVOID); 59 static void (WINAPI *pMAPIUninitialize)(void); 60 61 static BOOL InitFuncPtrs(void) 62 { 63 hMapi32 = LoadLibraryA("mapi32.dll"); 64 65 pPropCopyMore = (void*)GetProcAddress(hMapi32, "PropCopyMore@16"); 66 pUlPropSize = (void*)GetProcAddress(hMapi32, "UlPropSize@4"); 67 pFPropContainsProp = (void*)GetProcAddress(hMapi32, "FPropContainsProp@12"); 68 pFPropCompareProp = (void*)GetProcAddress(hMapi32, "FPropCompareProp@12"); 69 pLPropCompareProp = (void*)GetProcAddress(hMapi32, "LPropCompareProp@8"); 70 pPpropFindProp = (void*)GetProcAddress(hMapi32, "PpropFindProp@12"); 71 pScCountProps = (void*)GetProcAddress(hMapi32, "ScCountProps@12"); 72 pScCopyProps = (void*)GetProcAddress(hMapi32, "ScCopyProps@16"); 73 pScRelocProps = (void*)GetProcAddress(hMapi32, "ScRelocProps@20"); 74 pLpValFindProp = (void*)GetProcAddress(hMapi32, "LpValFindProp@12"); 75 pFBadRglpszA = (void*)GetProcAddress(hMapi32, "FBadRglpszA@8"); 76 pFBadRglpszW = (void*)GetProcAddress(hMapi32, "FBadRglpszW@8"); 77 pFBadRowSet = (void*)GetProcAddress(hMapi32, "FBadRowSet@4"); 78 pFBadPropTag = (void*)GetProcAddress(hMapi32, "FBadPropTag@4"); 79 pFBadRow = (void*)GetProcAddress(hMapi32, "FBadRow@4"); 80 pFBadProp = (void*)GetProcAddress(hMapi32, "FBadProp@4"); 81 pFBadColumnSet = (void*)GetProcAddress(hMapi32, "FBadColumnSet@4"); 82 pCreateIProp = (void*)GetProcAddress(hMapi32, "CreateIProp@24"); 83 84 pScInitMapiUtil = (void*)GetProcAddress(hMapi32, "ScInitMapiUtil@4"); 85 pDeinitMapiUtil = (void*)GetProcAddress(hMapi32, "DeinitMapiUtil@0"); 86 pMAPIAllocateBuffer = (void*)GetProcAddress(hMapi32, "MAPIAllocateBuffer"); 87 pMAPIAllocateMore = (void*)GetProcAddress(hMapi32, "MAPIAllocateMore"); 88 pMAPIFreeBuffer = (void*)GetProcAddress(hMapi32, "MAPIFreeBuffer"); 89 pMAPIInitialize = (void*)GetProcAddress(hMapi32, "MAPIInitialize"); 90 pMAPIUninitialize = (void*)GetProcAddress(hMapi32, "MAPIUninitialize"); 91 92 return pMAPIAllocateBuffer && pMAPIAllocateMore && pMAPIFreeBuffer && 93 pScInitMapiUtil && pDeinitMapiUtil; 94 } 95 96 /* FIXME: Test PT_I2, PT_I4, PT_R4, PT_R8, PT_CURRENCY, PT_APPTIME, PT_SYSTIME, 97 * PT_ERROR, PT_BOOLEAN, PT_I8, and PT_CLSID. */ 98 static ULONG ptTypes[] = { 99 PT_STRING8, PT_BINARY, PT_UNICODE 100 }; 101 102 static inline int strcmpW(const WCHAR *str1, const WCHAR *str2) 103 { 104 while (*str1 && (*str1 == *str2)) { str1++; str2++; } 105 return *str1 - *str2; 106 } 107 108 static void test_PropCopyMore(void) 109 { 110 static char szHiA[] = "Hi!"; 111 static WCHAR szHiW[] = { 'H', 'i', '!', '\0' }; 112 SPropValue *lpDest = NULL, *lpSrc = NULL; 113 ULONG i; 114 SCODE scode; 115 116 if (!pPropCopyMore) 117 { 118 win_skip("PropCopyMore is not available\n"); 119 return; 120 } 121 122 scode = pMAPIAllocateBuffer(sizeof(SPropValue), &lpDest); 123 ok(scode == S_OK, "Expected MAPIAllocateBuffer to return S_OK, got 0x%x\n", scode); 124 if (FAILED(scode)) 125 { 126 skip("MAPIAllocateBuffer failed\n"); 127 return; 128 } 129 130 scode = pMAPIAllocateMore(sizeof(SPropValue), lpDest, &lpSrc); 131 ok(scode == S_OK, "Expected MAPIAllocateMore to return S_OK, got 0x%x\n", scode); 132 if (FAILED(scode)) 133 { 134 skip("MAPIAllocateMore failed\n"); 135 return; 136 } 137 138 for (i = 0; i < ARRAY_SIZE(ptTypes); i++) 139 { 140 lpSrc->ulPropTag = ptTypes[i]; 141 142 switch (ptTypes[i]) 143 { 144 case PT_STRING8: 145 lpSrc->Value.lpszA = szHiA; 146 break; 147 case PT_UNICODE: 148 lpSrc->Value.lpszW = szHiW; 149 break; 150 case PT_BINARY: 151 lpSrc->Value.bin.cb = 4; 152 lpSrc->Value.bin.lpb = (LPBYTE)szHiA; 153 break; 154 } 155 156 memset(lpDest, 0xff, sizeof(SPropValue)); 157 158 scode = pPropCopyMore(lpDest, lpSrc, (ALLOCATEMORE*)pMAPIAllocateMore, lpDest); 159 ok(!scode && lpDest->ulPropTag == lpSrc->ulPropTag, 160 "PropCopyMore: Expected 0x0,%d, got 0x%08x,%d\n", 161 lpSrc->ulPropTag, scode, lpDest->ulPropTag); 162 if (SUCCEEDED(scode)) 163 { 164 switch (ptTypes[i]) 165 { 166 case PT_STRING8: 167 ok(lstrcmpA(lpDest->Value.lpszA, lpSrc->Value.lpszA) == 0, 168 "PropCopyMore: Ascii string differs\n"); 169 break; 170 case PT_UNICODE: 171 ok(strcmpW(lpDest->Value.lpszW, lpSrc->Value.lpszW) == 0, 172 "PropCopyMore: Unicode string differs\n"); 173 break; 174 case PT_BINARY: 175 ok(lpDest->Value.bin.cb == 4 && 176 !memcmp(lpSrc->Value.bin.lpb, lpDest->Value.bin.lpb, 4), 177 "PropCopyMore: Binary array differs\n"); 178 break; 179 } 180 } 181 } 182 183 /* Since all allocations are linked, freeing lpDest frees everything */ 184 scode = pMAPIFreeBuffer(lpDest); 185 ok(scode == S_OK, "Expected MAPIFreeBuffer to return S_OK, got 0x%x\n", scode); 186 } 187 188 static void test_UlPropSize(void) 189 { 190 static char szHiA[] = "Hi!"; 191 static WCHAR szHiW[] = { 'H', 'i', '!', '\0' }; 192 LPSTR buffa[2]; 193 LPWSTR buffw[2]; 194 SBinary buffbin[2]; 195 ULONG pt, exp, res; 196 197 if (!pUlPropSize) 198 { 199 win_skip("UlPropSize is not available\n"); 200 return; 201 } 202 203 for (pt = 0; pt < PROP_ID_INVALID; pt++) 204 { 205 SPropValue pv; 206 207 memset(&pv, 0 ,sizeof(pv)); 208 pv.ulPropTag = pt; 209 210 exp = 1u; /* Default to one item for non-MV properties */ 211 212 switch (PROP_TYPE(pt)) 213 { 214 case PT_MV_I2: pv.Value.MVi.cValues = exp = 2; 215 case PT_I2: exp *= sizeof(USHORT); break; 216 case PT_MV_I4: pv.Value.MVl.cValues = exp = 2; 217 case PT_I4: exp *= sizeof(LONG); break; 218 case PT_MV_R4: pv.Value.MVflt.cValues = exp = 2; 219 case PT_R4: exp *= sizeof(float); break; 220 case PT_MV_DOUBLE: pv.Value.MVdbl.cValues = exp = 2; 221 case PT_R8: exp *= sizeof(double); break; 222 case PT_MV_CURRENCY: pv.Value.MVcur.cValues = exp = 2; 223 case PT_CURRENCY: exp *= sizeof(CY); break; 224 case PT_MV_APPTIME: pv.Value.MVat.cValues = exp = 2; 225 case PT_APPTIME: exp *= sizeof(double); break; 226 case PT_MV_SYSTIME: pv.Value.MVft.cValues = exp = 2; 227 case PT_SYSTIME: exp *= sizeof(FILETIME); break; 228 case PT_ERROR: exp = sizeof(SCODE); break; 229 case PT_BOOLEAN: exp = sizeof(USHORT); break; 230 case PT_OBJECT: exp = 0; break; 231 case PT_MV_I8: pv.Value.MVli.cValues = exp = 2; 232 case PT_I8: exp *= sizeof(LONG64); break; 233 #if 0 234 /* My version of native mapi returns 0 for PT_MV_CLSID even if a valid 235 * array is given. This _has_ to be a bug, so Wine does 236 * the right thing(tm) and we don't test it here. 237 */ 238 case PT_MV_CLSID: pv.Value.MVguid.cValues = exp = 2; 239 #endif 240 case PT_CLSID: exp *= sizeof(GUID); break; 241 case PT_STRING8: 242 pv.Value.lpszA = szHiA; 243 exp = 4; 244 break; 245 case PT_UNICODE: 246 pv.Value.lpszW = szHiW; 247 exp = 4 * sizeof(WCHAR); 248 break; 249 case PT_BINARY: 250 pv.Value.bin.cb = exp = 19; 251 break; 252 case PT_MV_STRING8: 253 pv.Value.MVszA.cValues = 2; 254 pv.Value.MVszA.lppszA = buffa; 255 buffa[0] = szHiA; 256 buffa[1] = szHiA; 257 exp = 8; 258 break; 259 case PT_MV_UNICODE: 260 pv.Value.MVszW.cValues = 2; 261 pv.Value.MVszW.lppszW = buffw; 262 buffw[0] = szHiW; 263 buffw[1] = szHiW; 264 exp = 8 * sizeof(WCHAR); 265 break; 266 case PT_MV_BINARY: 267 pv.Value.MVbin.cValues = 2; 268 pv.Value.MVbin.lpbin = buffbin; 269 buffbin[0].cb = 19; 270 buffbin[1].cb = 1; 271 exp = 20; 272 break; 273 default: 274 exp = 0; 275 } 276 277 res = pUlPropSize(&pv); 278 ok(res == exp, 279 "pt= %d: Expected %d, got %d\n", pt, exp, res); 280 } 281 } 282 283 static void test_FPropContainsProp(void) 284 { 285 static char szFull[] = "Full String"; 286 static char szFullLower[] = "full string"; 287 static char szPrefix[] = "Full"; 288 static char szPrefixLower[] = "full"; 289 static char szSubstring[] = "ll St"; 290 static char szSubstringLower[] = "ll st"; 291 SPropValue pvLeft, pvRight; 292 ULONG pt; 293 BOOL bRet; 294 295 if (!pFPropContainsProp) 296 { 297 win_skip("FPropContainsProp is not available\n"); 298 return; 299 } 300 301 /* Ensure that only PT_STRING8 and PT_BINARY are handled */ 302 for (pt = 0; pt < PROP_ID_INVALID; pt++) 303 { 304 if (pt == PT_STRING8 || pt == PT_BINARY) 305 continue; /* test these later */ 306 307 memset(&pvLeft, 0 ,sizeof(pvLeft)); 308 memset(&pvRight, 0 ,sizeof(pvRight)); 309 pvLeft.ulPropTag = pvRight.ulPropTag = pt; 310 311 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING); 312 ok(bRet == FALSE, "pt= %d: Expected FALSE, got %d\n", pt, bRet); 313 } 314 315 /* test the various flag combinations */ 316 pvLeft.ulPropTag = pvRight.ulPropTag = PT_STRING8; 317 pvLeft.Value.lpszA = szFull; 318 pvRight.Value.lpszA = szFull; 319 320 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING); 321 ok(bRet == TRUE, "(full,full)[] match failed\n"); 322 pvRight.Value.lpszA = szPrefix; 323 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING); 324 ok(bRet == FALSE, "(full,prefix)[] match failed\n"); 325 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX); 326 ok(bRet == TRUE, "(full,prefix)[PREFIX] match failed\n"); 327 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING); 328 ok(bRet == TRUE, "(full,prefix)[SUBSTRING] match failed\n"); 329 pvRight.Value.lpszA = szPrefixLower; 330 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX); 331 ok(bRet == FALSE, "(full,prefixlow)[PREFIX] match failed\n"); 332 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING); 333 ok(bRet == FALSE, "(full,prefixlow)[SUBSTRING] match failed\n"); 334 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX|FL_IGNORECASE); 335 ok(bRet == TRUE, "(full,prefixlow)[PREFIX|IGNORECASE] match failed\n"); 336 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING|FL_IGNORECASE); 337 ok(bRet == TRUE, "(full,prefixlow)[SUBSTRING|IGNORECASE] match failed\n"); 338 pvRight.Value.lpszA = szSubstring; 339 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING); 340 ok(bRet == FALSE, "(full,substr)[] match failed\n"); 341 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX); 342 ok(bRet == FALSE, "(full,substr)[PREFIX] match failed\n"); 343 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING); 344 ok(bRet == TRUE, "(full,substr)[SUBSTRING] match failed\n"); 345 pvRight.Value.lpszA = szSubstringLower; 346 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX); 347 ok(bRet == FALSE, "(full,substrlow)[PREFIX] match failed\n"); 348 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING); 349 ok(bRet == FALSE, "(full,substrlow)[SUBSTRING] match failed\n"); 350 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX|FL_IGNORECASE); 351 ok(bRet == FALSE, "(full,substrlow)[PREFIX|IGNORECASE] match failed\n"); 352 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING|FL_IGNORECASE); 353 ok(bRet == TRUE, "(full,substrlow)[SUBSTRING|IGNORECASE] match failed\n"); 354 pvRight.Value.lpszA = szFullLower; 355 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING|FL_IGNORECASE); 356 ok(bRet == TRUE, "(full,fulllow)[IGNORECASE] match failed\n"); 357 358 pvLeft.ulPropTag = pvRight.ulPropTag = PT_BINARY; 359 pvLeft.Value.bin.lpb = (LPBYTE)szFull; 360 pvRight.Value.bin.lpb = (LPBYTE)szFull; 361 pvLeft.Value.bin.cb = pvRight.Value.bin.cb = strlen(szFull); 362 363 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING); 364 ok(bRet == TRUE, "bin(full,full)[] match failed\n"); 365 pvRight.Value.bin.lpb = (LPBYTE)szPrefix; 366 pvRight.Value.bin.cb = strlen(szPrefix); 367 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING); 368 ok(bRet == FALSE, "bin(full,prefix)[] match failed\n"); 369 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX); 370 ok(bRet == TRUE, "bin(full,prefix)[PREFIX] match failed\n"); 371 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING); 372 ok(bRet == TRUE, "bin(full,prefix)[SUBSTRING] match failed\n"); 373 pvRight.Value.bin.lpb = (LPBYTE)szPrefixLower; 374 pvRight.Value.bin.cb = strlen(szPrefixLower); 375 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX); 376 ok(bRet == FALSE, "bin(full,prefixlow)[PREFIX] match failed\n"); 377 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING); 378 ok(bRet == FALSE, "bin(full,prefixlow)[SUBSTRING] match failed\n"); 379 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX|FL_IGNORECASE); 380 ok(bRet == FALSE, "bin(full,prefixlow)[PREFIX|IGNORECASE] match failed\n"); 381 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING|FL_IGNORECASE); 382 ok(bRet == FALSE, "bin(full,prefixlow)[SUBSTRING|IGNORECASE] match failed\n"); 383 pvRight.Value.bin.lpb = (LPBYTE)szSubstring; 384 pvRight.Value.bin.cb = strlen(szSubstring); 385 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING); 386 ok(bRet == FALSE, "bin(full,substr)[] match failed\n"); 387 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX); 388 ok(bRet == FALSE, "bin(full,substr)[PREFIX] match failed\n"); 389 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING); 390 ok(bRet == TRUE, "bin(full,substr)[SUBSTRING] match failed\n"); 391 pvRight.Value.bin.lpb = (LPBYTE)szSubstringLower; 392 pvRight.Value.bin.cb = strlen(szSubstringLower); 393 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX); 394 ok(bRet == FALSE, "bin(full,substrlow)[PREFIX] match failed\n"); 395 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING); 396 ok(bRet == FALSE, "bin(full,substrlow)[SUBSTRING] match failed\n"); 397 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX|FL_IGNORECASE); 398 ok(bRet == FALSE, "bin(full,substrlow)[PREFIX|IGNORECASE] match failed\n"); 399 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING|FL_IGNORECASE); 400 ok(bRet == FALSE, "bin(full,substrlow)[SUBSTRING|IGNORECASE] match failed\n"); 401 pvRight.Value.bin.lpb = (LPBYTE)szFullLower; 402 pvRight.Value.bin.cb = strlen(szFullLower); 403 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING|FL_IGNORECASE); 404 ok(bRet == FALSE, "bin(full,fulllow)[IGNORECASE] match failed\n"); 405 } 406 407 typedef struct tagFPropCompareProp_Result 408 { 409 SHORT lVal; 410 SHORT rVal; 411 ULONG relOp; 412 BOOL bRet; 413 } FPropCompareProp_Result; 414 415 static const FPropCompareProp_Result FPCProp_Results[] = 416 { 417 { 1, 2, RELOP_LT, TRUE }, 418 { 1, 1, RELOP_LT, FALSE }, 419 { 2, 1, RELOP_LT, FALSE }, 420 { 1, 2, RELOP_LE, TRUE }, 421 { 1, 1, RELOP_LE, TRUE }, 422 { 2, 1, RELOP_LE, FALSE }, 423 { 1, 2, RELOP_GT, FALSE }, 424 { 1, 1, RELOP_GT, FALSE }, 425 { 2, 1, RELOP_GT, TRUE }, 426 { 1, 2, RELOP_GE, FALSE }, 427 { 1, 1, RELOP_GE, TRUE }, 428 { 2, 1, RELOP_GE, TRUE }, 429 { 1, 2, RELOP_EQ, FALSE }, 430 { 1, 1, RELOP_EQ, TRUE }, 431 { 2, 1, RELOP_EQ, FALSE } 432 }; 433 434 static const char *relops[] = { "RELOP_LT", "RELOP_LE", "RELOP_GT", "RELOP_GE", "RELOP_EQ" }; 435 436 static void test_FPropCompareProp(void) 437 { 438 SPropValue pvLeft, pvRight; 439 GUID lguid, rguid; 440 char lbuffa[2], rbuffa[2]; 441 WCHAR lbuffw[2], rbuffw[2]; 442 ULONG i, j; 443 BOOL bRet, bExp; 444 445 if (!pFPropCompareProp) 446 { 447 win_skip("FPropCompareProp is not available\n"); 448 return; 449 } 450 451 lbuffa[1] = '\0'; 452 rbuffa[1] = '\0'; 453 lbuffw[1] = '\0'; 454 rbuffw[1] = '\0'; 455 456 for (i = 0; i < ARRAY_SIZE(ptTypes); i++) 457 { 458 pvLeft.ulPropTag = pvRight.ulPropTag = ptTypes[i]; 459 460 for (j = 0; j < ARRAY_SIZE(FPCProp_Results); j++) 461 { 462 SHORT lVal = FPCProp_Results[j].lVal; 463 SHORT rVal = FPCProp_Results[j].rVal; 464 465 bExp = FPCProp_Results[j].bRet; 466 467 switch (ptTypes[i]) 468 { 469 case PT_BOOLEAN: 470 /* Boolean values have no concept of less or greater than, only equality */ 471 if ((lVal == 1 && rVal == 2 && FPCProp_Results[j].relOp == RELOP_LT) || 472 (lVal == 2 && rVal == 1 && FPCProp_Results[j].relOp == RELOP_LE)|| 473 (lVal == 2 && rVal == 1 && FPCProp_Results[j].relOp == RELOP_GT)|| 474 (lVal == 1 && rVal == 2 && FPCProp_Results[j].relOp == RELOP_GE)|| 475 (lVal == 1 && rVal == 2 && FPCProp_Results[j].relOp == RELOP_EQ)|| 476 (lVal == 2 && rVal == 1 && FPCProp_Results[j].relOp == RELOP_EQ)) 477 bExp = !bExp; 478 /* Fall through ... */ 479 case PT_I2: 480 pvLeft.Value.i = lVal; 481 pvRight.Value.i = rVal; 482 break; 483 case PT_ERROR: 484 case PT_I4: 485 pvLeft.Value.l = lVal; 486 pvRight.Value.l = rVal; 487 break; 488 case PT_R4: 489 pvLeft.Value.flt = lVal; 490 pvRight.Value.flt = rVal; 491 break; 492 case PT_APPTIME: 493 case PT_R8: 494 pvLeft.Value.dbl = lVal; 495 pvRight.Value.dbl = rVal; 496 break; 497 case PT_CURRENCY: 498 pvLeft.Value.cur.int64 = lVal; 499 pvRight.Value.cur.int64 = rVal; 500 break; 501 case PT_SYSTIME: 502 pvLeft.Value.ft.dwLowDateTime = lVal; 503 pvLeft.Value.ft.dwHighDateTime = 0; 504 pvRight.Value.ft.dwLowDateTime = rVal; 505 pvRight.Value.ft.dwHighDateTime = 0; 506 break; 507 case PT_I8: 508 pvLeft.Value.li.u.LowPart = lVal; 509 pvLeft.Value.li.u.HighPart = 0; 510 pvRight.Value.li.u.LowPart = rVal; 511 pvRight.Value.li.u.HighPart = 0; 512 break; 513 case PT_CLSID: 514 memset(&lguid, 0, sizeof(GUID)); 515 memset(&rguid, 0, sizeof(GUID)); 516 lguid.Data4[7] = lVal; 517 rguid.Data4[7] = rVal; 518 pvLeft.Value.lpguid = &lguid; 519 pvRight.Value.lpguid = &rguid; 520 break; 521 case PT_STRING8: 522 pvLeft.Value.lpszA = lbuffa; 523 pvRight.Value.lpszA = rbuffa; 524 lbuffa[0] = '0' + lVal; 525 rbuffa[0] = '0' + rVal; 526 break; 527 case PT_UNICODE: 528 pvLeft.Value.lpszW = lbuffw; 529 pvRight.Value.lpszW = rbuffw; 530 lbuffw[0] = '0' + lVal; 531 rbuffw[0] = '0' + rVal; 532 break; 533 case PT_BINARY: 534 pvLeft.Value.bin.cb = 1; 535 pvRight.Value.bin.cb = 1; 536 pvLeft.Value.bin.lpb = (LPBYTE)lbuffa; 537 pvRight.Value.bin.lpb = (LPBYTE)rbuffa; 538 lbuffa[0] = lVal; 539 rbuffa[0] = rVal; 540 break; 541 } 542 543 bRet = pFPropCompareProp(&pvLeft, FPCProp_Results[j].relOp, &pvRight); 544 ok(bRet == bExp, 545 "pt %d (%d,%d,%s): expected %d, got %d\n", ptTypes[i], 546 FPCProp_Results[j].lVal, FPCProp_Results[j].rVal, 547 relops[FPCProp_Results[j].relOp], bExp, bRet); 548 } 549 } 550 } 551 552 typedef struct tagLPropCompareProp_Result 553 { 554 SHORT lVal; 555 SHORT rVal; 556 INT iRet; 557 } LPropCompareProp_Result; 558 559 static const LPropCompareProp_Result LPCProp_Results[] = 560 { 561 { 1, 2, -1 }, 562 { 1, 1, 0 }, 563 { 2, 1, 1 }, 564 }; 565 566 static void test_LPropCompareProp(void) 567 { 568 SPropValue pvLeft, pvRight; 569 GUID lguid, rguid; 570 char lbuffa[2], rbuffa[2]; 571 WCHAR lbuffw[2], rbuffw[2]; 572 ULONG i, j; 573 INT iRet, iExp; 574 575 if (!pLPropCompareProp) 576 { 577 win_skip("LPropCompareProp is not available\n"); 578 return; 579 } 580 581 lbuffa[1] = '\0'; 582 rbuffa[1] = '\0'; 583 lbuffw[1] = '\0'; 584 rbuffw[1] = '\0'; 585 586 for (i = 0; i < ARRAY_SIZE(ptTypes); i++) 587 { 588 pvLeft.ulPropTag = pvRight.ulPropTag = ptTypes[i]; 589 590 for (j = 0; j < ARRAY_SIZE(LPCProp_Results); j++) 591 { 592 SHORT lVal = LPCProp_Results[j].lVal; 593 SHORT rVal = LPCProp_Results[j].rVal; 594 595 iExp = LPCProp_Results[j].iRet; 596 597 switch (ptTypes[i]) 598 { 599 case PT_BOOLEAN: 600 /* Boolean values have no concept of less or greater than, only equality */ 601 if (lVal && rVal) 602 iExp = 0; 603 /* Fall through ... */ 604 case PT_I2: 605 pvLeft.Value.i = lVal; 606 pvRight.Value.i = rVal; 607 break; 608 case PT_ERROR: 609 case PT_I4: 610 pvLeft.Value.l = lVal; 611 pvRight.Value.l = rVal; 612 break; 613 case PT_R4: 614 pvLeft.Value.flt = lVal; 615 pvRight.Value.flt = rVal; 616 break; 617 case PT_APPTIME: 618 case PT_R8: 619 pvLeft.Value.dbl = lVal; 620 pvRight.Value.dbl = rVal; 621 break; 622 case PT_CURRENCY: 623 pvLeft.Value.cur.int64 = lVal; 624 pvRight.Value.cur.int64 = rVal; 625 break; 626 case PT_SYSTIME: 627 pvLeft.Value.ft.dwLowDateTime = lVal; 628 pvLeft.Value.ft.dwHighDateTime = 0; 629 pvRight.Value.ft.dwLowDateTime = rVal; 630 pvRight.Value.ft.dwHighDateTime = 0; 631 break; 632 case PT_I8: 633 pvLeft.Value.li.u.LowPart = lVal; 634 pvLeft.Value.li.u.HighPart = 0; 635 pvRight.Value.li.u.LowPart = rVal; 636 pvRight.Value.li.u.HighPart = 0; 637 break; 638 case PT_CLSID: 639 memset(&lguid, 0, sizeof(GUID)); 640 memset(&rguid, 0, sizeof(GUID)); 641 lguid.Data4[7] = lVal; 642 rguid.Data4[7] = rVal; 643 pvLeft.Value.lpguid = &lguid; 644 pvRight.Value.lpguid = &rguid; 645 break; 646 case PT_STRING8: 647 pvLeft.Value.lpszA = lbuffa; 648 pvRight.Value.lpszA = rbuffa; 649 lbuffa[0] = '0' + lVal; 650 rbuffa[0] = '0' + rVal; 651 break; 652 case PT_UNICODE: 653 pvLeft.Value.lpszW = lbuffw; 654 pvRight.Value.lpszW = rbuffw; 655 lbuffw[0] = '0' + lVal; 656 rbuffw[0] = '0' + rVal; 657 break; 658 case PT_BINARY: 659 pvLeft.Value.bin.cb = 1; 660 pvRight.Value.bin.cb = 1; 661 pvLeft.Value.bin.lpb = (LPBYTE)lbuffa; 662 pvRight.Value.bin.lpb = (LPBYTE)rbuffa; 663 lbuffa[0] = lVal; 664 rbuffa[0] = rVal; 665 break; 666 } 667 668 iRet = pLPropCompareProp(&pvLeft, &pvRight); 669 ok(iRet == iExp, 670 "pt %d (%d,%d): expected %d, got %d\n", ptTypes[i], 671 LPCProp_Results[j].lVal, LPCProp_Results[j].rVal, iExp, iRet); 672 } 673 } 674 } 675 676 static void test_PpropFindProp(void) 677 { 678 SPropValue pvProp, *pRet; 679 ULONG i; 680 681 if (!pPpropFindProp) 682 { 683 win_skip("PpropFindProp is not available\n"); 684 return; 685 } 686 687 for (i = 0; i < ARRAY_SIZE(ptTypes); i++) 688 { 689 pvProp.ulPropTag = ptTypes[i]; 690 691 pRet = pPpropFindProp(&pvProp, 1u, ptTypes[i]); 692 ok(pRet == &pvProp, 693 "PpropFindProp[%d]: Didn't find existing property\n", 694 ptTypes[i]); 695 696 pRet = pPpropFindProp(&pvProp, 1u, i ? ptTypes[i-1] : ptTypes[i+1]); 697 ok(pRet == NULL, "PpropFindProp[%d]: Found nonexistent property\n", 698 ptTypes[i]); 699 } 700 701 pvProp.ulPropTag = PROP_TAG(PT_I2, 1u); 702 pRet = pPpropFindProp(&pvProp, 1u, PROP_TAG(PT_UNSPECIFIED, 0u)); 703 ok(pRet == NULL, "PpropFindProp[UNSPECIFIED]: Matched on different id\n"); 704 pRet = pPpropFindProp(&pvProp, 1u, PROP_TAG(PT_UNSPECIFIED, 1u)); 705 ok(pRet == &pvProp, "PpropFindProp[UNSPECIFIED]: Didn't match id\n"); 706 } 707 708 static void test_ScCountProps(void) 709 { 710 static char szHiA[] = "Hi!"; 711 static WCHAR szHiW[] = { 'H', 'i', '!', '\0' }; 712 static const ULONG ULHILEN = 4; /* chars in szHiA/W incl. NUL */ 713 LPSTR buffa[3]; 714 LPWSTR buffw[3]; 715 SBinary buffbin[3]; 716 GUID iids[4], *iid = iids; 717 SCODE res; 718 ULONG pt, exp, ulRet; 719 BOOL success = TRUE; 720 721 if (!pScCountProps) 722 { 723 win_skip("ScCountProps is not available\n"); 724 return; 725 } 726 727 for (pt = 0; pt < PROP_ID_INVALID && success; pt++) 728 { 729 SPropValue pv; 730 731 memset(&pv, 0 ,sizeof(pv)); 732 pv.ulPropTag = PROP_TAG(pt, 1u); 733 734 switch (PROP_TYPE(pt)) 735 { 736 case PT_I2: 737 case PT_I4: 738 case PT_R4: 739 case PT_R8: 740 case PT_CURRENCY: 741 case PT_APPTIME: 742 case PT_SYSTIME: 743 case PT_ERROR: 744 case PT_BOOLEAN: 745 case PT_OBJECT: 746 case PT_I8: 747 exp = sizeof(pv); 748 break; 749 case PT_CLSID: 750 pv.Value.lpguid = iid; 751 exp = sizeof(GUID) + sizeof(pv); 752 break; 753 case PT_STRING8: 754 pv.Value.lpszA = szHiA; 755 exp = 4 + sizeof(pv); 756 break; 757 case PT_UNICODE: 758 pv.Value.lpszW = szHiW; 759 exp = 4 * sizeof(WCHAR) + sizeof(pv); 760 break; 761 case PT_BINARY: 762 pv.Value.bin.cb = 2; 763 pv.Value.bin.lpb = (LPBYTE)iid; 764 exp = 2 + sizeof(pv); 765 break; 766 case PT_MV_I2: 767 pv.Value.MVi.cValues = 3; 768 pv.Value.MVi.lpi = (SHORT*)iid; 769 exp = 3 * sizeof(SHORT) + sizeof(pv); 770 break; 771 case PT_MV_I4: 772 pv.Value.MVl.cValues = 3; 773 pv.Value.MVl.lpl = (LONG*)iid; 774 exp = 3 * sizeof(LONG) + sizeof(pv); 775 break; 776 case PT_MV_I8: 777 pv.Value.MVli.cValues = 3; 778 pv.Value.MVli.lpli = (LARGE_INTEGER*)iid; 779 exp = 3 * sizeof(LARGE_INTEGER) + sizeof(pv); 780 break; 781 case PT_MV_R4: 782 pv.Value.MVflt.cValues = 3; 783 pv.Value.MVflt.lpflt = (float*)iid; 784 exp = 3 * sizeof(float) + sizeof(pv); 785 break; 786 case PT_MV_APPTIME: 787 case PT_MV_R8: 788 pv.Value.MVdbl.cValues = 3; 789 pv.Value.MVdbl.lpdbl = (double*)iid; 790 exp = 3 * sizeof(double) + sizeof(pv); 791 break; 792 case PT_MV_CURRENCY: 793 pv.Value.MVcur.cValues = 3; 794 pv.Value.MVcur.lpcur = (CY*)iid; 795 exp = 3 * sizeof(CY) + sizeof(pv); 796 break; 797 case PT_MV_SYSTIME: 798 pv.Value.MVft.cValues = 3; 799 pv.Value.MVft.lpft = (FILETIME*)iid; 800 exp = 3 * sizeof(CY) + sizeof(pv); 801 break; 802 case PT_MV_STRING8: 803 pv.Value.MVszA.cValues = 3; 804 pv.Value.MVszA.lppszA = buffa; 805 buffa[0] = szHiA; 806 buffa[1] = szHiA; 807 buffa[2] = szHiA; 808 exp = ULHILEN * 3 + 3 * sizeof(char*) + sizeof(pv); 809 break; 810 case PT_MV_UNICODE: 811 pv.Value.MVszW.cValues = 3; 812 pv.Value.MVszW.lppszW = buffw; 813 buffw[0] = szHiW; 814 buffw[1] = szHiW; 815 buffw[2] = szHiW; 816 exp = ULHILEN * 3 * sizeof(WCHAR) + 3 * sizeof(WCHAR*) + sizeof(pv); 817 break; 818 case PT_MV_BINARY: 819 pv.Value.MVbin.cValues = 3; 820 pv.Value.MVbin.lpbin = buffbin; 821 buffbin[0].cb = 17; 822 buffbin[0].lpb = (LPBYTE)&iid; 823 buffbin[1].cb = 2; 824 buffbin[1].lpb = (LPBYTE)&iid; 825 buffbin[2].cb = 1; 826 buffbin[2].lpb = (LPBYTE)&iid; 827 exp = 20 + sizeof(pv) + sizeof(SBinary) * 3; 828 break; 829 default: 830 exp = 0; 831 } 832 833 ulRet = 0xffffffff; 834 res = pScCountProps(1, &pv, &ulRet); 835 if (!exp) { 836 success = res == MAPI_E_INVALID_PARAMETER && ulRet == 0xffffffff; 837 ok(success, "pt= %d: Expected failure, got %d, ret=0x%08X\n", 838 pt, ulRet, res); 839 } 840 else { 841 success = res == S_OK && ulRet == exp; 842 ok(success, "pt= %d: Expected %d, got %d, ret=0x%08X\n", 843 pt, exp, ulRet, res); 844 } 845 } 846 847 } 848 849 static void test_ScCopyRelocProps(void) 850 { 851 static char szTestA[] = "Test"; 852 char buffer[512], buffer2[512], *lppszA[1]; 853 SPropValue pvProp, *lpResProp = (LPSPropValue)buffer; 854 ULONG ulCount; 855 SCODE sc; 856 857 if (!pScCopyProps || !pScRelocProps) 858 { 859 win_skip("SPropValue copy functions are not available\n"); 860 return; 861 } 862 863 pvProp.ulPropTag = PROP_TAG(PT_MV_STRING8, 1u); 864 865 lppszA[0] = szTestA; 866 pvProp.Value.MVszA.cValues = 1; 867 pvProp.Value.MVszA.lppszA = lppszA; 868 ulCount = 0; 869 870 sc = pScCopyProps(1, &pvProp, buffer, &ulCount); 871 ok(sc == S_OK, "wrong ret %d\n", sc); 872 if(sc == S_OK) 873 { 874 ok(lpResProp->ulPropTag == pvProp.ulPropTag, "wrong tag %x\n",lpResProp->ulPropTag); 875 ok(lpResProp->Value.MVszA.cValues == 1, "wrong cValues %d\n", lpResProp->Value.MVszA.cValues); 876 ok(lpResProp->Value.MVszA.lppszA[0] == buffer + sizeof(SPropValue) + sizeof(char*), 877 "wrong lppszA[0] %p\n",lpResProp->Value.MVszA.lppszA[0]); 878 ok(ulCount == sizeof(SPropValue) + sizeof(char*) + 5, "wrong count %d\n", ulCount); 879 ok(!strcmp(lpResProp->Value.MVszA.lppszA[0], szTestA), 880 "wrong string '%s'\n", lpResProp->Value.MVszA.lppszA[0]); 881 } 882 883 memcpy(buffer2, buffer, sizeof(buffer)); 884 885 /* Clear the data in the source buffer. Since pointers in the copied buffer 886 * refer to the source buffer, this proves that native always assumes that 887 * the copied buffers pointers are bad (needing to be relocated first). 888 */ 889 memset(buffer, 0, sizeof(buffer)); 890 ulCount = 0; 891 892 sc = pScRelocProps(1, (LPSPropValue)buffer2, buffer, buffer2, &ulCount); 893 lpResProp = (LPSPropValue)buffer2; 894 895 ok(sc == S_OK, "wrong ret %d\n", sc); 896 if(sc == S_OK) 897 { 898 ok(lpResProp->ulPropTag == pvProp.ulPropTag, "wrong tag %x\n",lpResProp->ulPropTag); 899 ok(lpResProp->Value.MVszA.cValues == 1, "wrong cValues %d\n", lpResProp->Value.MVszA.cValues); 900 ok(lpResProp->Value.MVszA.lppszA[0] == buffer2 + sizeof(SPropValue) + sizeof(char*), 901 "wrong lppszA[0] %p\n",lpResProp->Value.MVszA.lppszA[0]); 902 /* Native has a bug whereby it calculates the size correctly when copying 903 * but when relocating does not (presumably it uses UlPropSize() which 904 * ignores multivalue pointers). Wine returns the correct value. 905 */ 906 ok(ulCount == sizeof(SPropValue) + sizeof(char*) + 5 || ulCount == sizeof(SPropValue) + 5, 907 "wrong count %d\n", ulCount); 908 ok(!strcmp(lpResProp->Value.MVszA.lppszA[0], szTestA), 909 "wrong string '%s'\n", lpResProp->Value.MVszA.lppszA[0]); 910 } 911 912 /* Native crashes with lpNew or lpOld set to NULL so skip testing this */ 913 } 914 915 static void test_LpValFindProp(void) 916 { 917 SPropValue pvProp, *pRet; 918 ULONG i; 919 920 if (!pLpValFindProp) 921 { 922 win_skip("LpValFindProp is not available\n"); 923 return; 924 } 925 926 for (i = 0; i < ARRAY_SIZE(ptTypes); i++) 927 { 928 pvProp.ulPropTag = PROP_TAG(ptTypes[i], 1u); 929 930 pRet = pLpValFindProp(PROP_TAG(ptTypes[i], 1u), 1u, &pvProp); 931 ok(pRet == &pvProp, 932 "LpValFindProp[%d]: Didn't find existing property id/type\n", 933 ptTypes[i]); 934 935 pRet = pLpValFindProp(PROP_TAG(ptTypes[i], 0u), 1u, &pvProp); 936 ok(pRet == NULL, "LpValFindProp[%d]: Found nonexistent property id\n", 937 ptTypes[i]); 938 939 pRet = pLpValFindProp(PROP_TAG(PT_NULL, 0u), 1u, &pvProp); 940 ok(pRet == NULL, "LpValFindProp[%d]: Found nonexistent property id/type\n", 941 ptTypes[i]); 942 943 pRet = pLpValFindProp(PROP_TAG(PT_NULL, 1u), 1u, &pvProp); 944 ok(pRet == &pvProp, 945 "LpValFindProp[%d]: Didn't find existing property id\n", 946 ptTypes[i]); 947 } 948 } 949 950 static void test_FBadRglpszA(void) 951 { 952 LPSTR lpStrs[4]; 953 static CHAR szString[] = "A String"; 954 BOOL bRet; 955 956 if (!pFBadRglpszA) 957 { 958 win_skip("FBadRglpszA is not available\n"); 959 return; 960 } 961 962 bRet = pFBadRglpszA(NULL, 10); 963 ok(bRet == TRUE, "FBadRglpszA(Null): expected TRUE, got FALSE\n"); 964 965 lpStrs[0] = lpStrs[1] = lpStrs[2] = lpStrs[3] = NULL; 966 bRet = pFBadRglpszA(lpStrs, 4); 967 ok(bRet == TRUE, "FBadRglpszA(Nulls): expected TRUE, got FALSE\n"); 968 969 lpStrs[0] = lpStrs[1] = lpStrs[2] = szString; 970 bRet = pFBadRglpszA(lpStrs, 3); 971 ok(bRet == FALSE, "FBadRglpszA(valid): expected FALSE, got TRUE\n"); 972 973 bRet = pFBadRglpszA(lpStrs, 4); 974 ok(bRet == TRUE, "FBadRglpszA(1 invalid): expected TRUE, got FALSE\n"); 975 } 976 977 static void test_FBadRglpszW(void) 978 { 979 LPWSTR lpStrs[4]; 980 static WCHAR szString[] = { 'A',' ','S','t','r','i','n','g','\0' }; 981 BOOL bRet; 982 983 if (!pFBadRglpszW) 984 { 985 win_skip("FBadRglpszW is not available\n"); 986 return; 987 } 988 989 bRet = pFBadRglpszW(NULL, 10); 990 ok(bRet == TRUE, "FBadRglpszW(Null): expected TRUE, got FALSE\n"); 991 992 lpStrs[0] = lpStrs[1] = lpStrs[2] = lpStrs[3] = NULL; 993 bRet = pFBadRglpszW(lpStrs, 4); 994 ok(bRet == TRUE, "FBadRglpszW(Nulls): expected TRUE, got FALSE\n"); 995 996 lpStrs[0] = lpStrs[1] = lpStrs[2] = szString; 997 bRet = pFBadRglpszW(lpStrs, 3); 998 ok(bRet == FALSE, "FBadRglpszW(valid): expected FALSE, got TRUE\n"); 999 1000 bRet = pFBadRglpszW(lpStrs, 4); 1001 ok(bRet == TRUE, "FBadRglpszW(1 invalid): expected TRUE, got FALSE\n"); 1002 } 1003 1004 static void test_FBadRowSet(void) 1005 { 1006 ULONG ulRet; 1007 1008 if (!pFBadRowSet) 1009 { 1010 win_skip("FBadRowSet is not available\n"); 1011 return; 1012 } 1013 1014 ulRet = pFBadRowSet(NULL); 1015 ok(ulRet != 0, "FBadRow(null): Expected non-zero, got 0\n"); 1016 1017 /* FIXME */ 1018 } 1019 1020 static void test_FBadPropTag(void) 1021 { 1022 ULONG pt, res; 1023 1024 if (!pFBadPropTag) 1025 { 1026 win_skip("FBadPropTag is not available\n"); 1027 return; 1028 } 1029 1030 for (pt = 0; pt < PROP_ID_INVALID; pt++) 1031 { 1032 BOOL bBad = TRUE; 1033 1034 switch (pt & (~MV_FLAG & PROP_TYPE_MASK)) 1035 { 1036 case PT_UNSPECIFIED: 1037 case PT_NULL: case PT_I2: case PT_I4: case PT_R4: 1038 case PT_R8: case PT_CURRENCY: case PT_APPTIME: 1039 case PT_ERROR: case PT_BOOLEAN: case PT_OBJECT: 1040 case PT_I8: case PT_STRING8: case PT_UNICODE: 1041 case PT_SYSTIME: case PT_CLSID: case PT_BINARY: 1042 bBad = FALSE; 1043 } 1044 1045 res = pFBadPropTag(pt); 1046 if (bBad) 1047 ok(res != 0, "pt= %d: Expected non-zero, got 0\n", pt); 1048 else 1049 ok(res == 0, 1050 "pt= %d: Expected zero, got %d\n", pt, res); 1051 } 1052 } 1053 1054 static void test_FBadRow(void) 1055 { 1056 ULONG ulRet; 1057 1058 if (!pFBadRow) 1059 { 1060 win_skip("FBadRow is not available\n"); 1061 return; 1062 } 1063 1064 ulRet = pFBadRow(NULL); 1065 ok(ulRet != 0, "FBadRow(null): Expected non-zero, got 0\n"); 1066 1067 /* FIXME */ 1068 } 1069 1070 static void test_FBadProp(void) 1071 { 1072 static WCHAR szEmpty[] = { '\0' }; 1073 GUID iid; 1074 ULONG pt, res; 1075 SPropValue pv; 1076 1077 if (!pFBadProp) 1078 { 1079 win_skip("FBadProp is not available\n"); 1080 return; 1081 } 1082 1083 for (pt = 0; pt < PROP_ID_INVALID; pt++) 1084 { 1085 BOOL bBad = TRUE; 1086 1087 memset(&pv, 0, sizeof(pv)); 1088 pv.ulPropTag = pt; 1089 1090 /* Note that MV values are valid below because their array count is 0, 1091 * so no pointers are validated. 1092 */ 1093 switch (PROP_TYPE(pt)) 1094 { 1095 case (MV_FLAG|PT_UNSPECIFIED): 1096 case PT_UNSPECIFIED: 1097 case (MV_FLAG|PT_NULL): 1098 case PT_NULL: 1099 case PT_MV_I2: 1100 case PT_I2: 1101 case PT_MV_I4: 1102 case PT_I4: 1103 case PT_MV_I8: 1104 case PT_I8: 1105 case PT_MV_R4: 1106 case PT_R4: 1107 case PT_MV_R8: 1108 case PT_R8: 1109 case PT_MV_CURRENCY: 1110 case PT_CURRENCY: 1111 case PT_MV_APPTIME: 1112 case PT_APPTIME: 1113 case (MV_FLAG|PT_ERROR): 1114 case PT_ERROR: 1115 case (MV_FLAG|PT_BOOLEAN): 1116 case PT_BOOLEAN: 1117 case (MV_FLAG|PT_OBJECT): 1118 case PT_OBJECT: 1119 case PT_MV_STRING8: 1120 case PT_MV_UNICODE: 1121 case PT_MV_SYSTIME: 1122 case PT_SYSTIME: 1123 case PT_MV_BINARY: 1124 case PT_BINARY: 1125 case PT_MV_CLSID: 1126 bBad = FALSE; 1127 break; 1128 case PT_STRING8: 1129 case PT_UNICODE: 1130 pv.Value.lpszW = szEmpty; 1131 bBad = FALSE; 1132 break; 1133 case PT_CLSID: 1134 pv.Value.lpguid = &iid; 1135 bBad = FALSE; 1136 break; 1137 } 1138 1139 res = pFBadProp(&pv); 1140 if (bBad) 1141 ok(res != 0, "pt= %d: Expected non-zero, got 0\n", pt); 1142 else 1143 ok(res == 0, 1144 "pt= %d: Expected zero, got %d\n", pt, res); 1145 } 1146 } 1147 1148 static void test_FBadColumnSet(void) 1149 { 1150 SPropTagArray pta; 1151 ULONG pt, res; 1152 1153 if (!pFBadColumnSet) 1154 { 1155 win_skip("FBadColumnSet is not available\n"); 1156 return; 1157 } 1158 1159 res = pFBadColumnSet(NULL); 1160 ok(res != 0, "(null): Expected non-zero, got 0\n"); 1161 1162 pta.cValues = 1; 1163 1164 for (pt = 0; pt < PROP_ID_INVALID; pt++) 1165 { 1166 BOOL bBad = TRUE; 1167 1168 pta.aulPropTag[0] = pt; 1169 1170 switch (pt & (~MV_FLAG & PROP_TYPE_MASK)) 1171 { 1172 case PT_UNSPECIFIED: 1173 case PT_NULL: 1174 case PT_I2: 1175 case PT_I4: 1176 case PT_R4: 1177 case PT_R8: 1178 case PT_CURRENCY: 1179 case PT_APPTIME: 1180 case PT_BOOLEAN: 1181 case PT_OBJECT: 1182 case PT_I8: 1183 case PT_STRING8: 1184 case PT_UNICODE: 1185 case PT_SYSTIME: 1186 case PT_CLSID: 1187 case PT_BINARY: 1188 bBad = FALSE; 1189 } 1190 if (pt == (MV_FLAG|PT_ERROR)) 1191 bBad = FALSE; 1192 1193 res = pFBadColumnSet(&pta); 1194 if (bBad) 1195 ok(res != 0, "pt= %d: Expected non-zero, got 0\n", pt); 1196 else 1197 ok(res == 0, 1198 "pt= %d: Expected zero, got %d\n", pt, res); 1199 } 1200 } 1201 1202 1203 static void test_IProp(void) 1204 { 1205 IPropData *lpIProp; 1206 LPMAPIERROR lpError; 1207 LPSPropProblemArray lpProbs; 1208 LPSPropValue lpProps; 1209 LPSPropTagArray lpTags; 1210 SPropValue pvs[2]; 1211 SizedSPropTagArray(2,tags); 1212 ULONG access[2], count; 1213 SCODE sc; 1214 1215 if (!pCreateIProp) 1216 { 1217 win_skip("CreateIProp is not available\n"); 1218 return; 1219 } 1220 1221 memset(&tags, 0 , sizeof(tags)); 1222 1223 /* Create the object */ 1224 lpIProp = NULL; 1225 sc = pCreateIProp(&IID_IMAPIPropData, (ALLOCATEBUFFER *)pMAPIAllocateBuffer, (ALLOCATEMORE*)pMAPIAllocateMore, 1226 (FREEBUFFER *)pMAPIFreeBuffer, NULL, &lpIProp); 1227 ok(sc == S_OK && lpIProp, 1228 "CreateIProp: expected S_OK, non-null, got 0x%08X,%p\n", sc, lpIProp); 1229 1230 if (sc != S_OK || !lpIProp) 1231 return; 1232 1233 /* GetLastError - No errors set */ 1234 lpError = NULL; 1235 sc = IPropData_GetLastError(lpIProp, E_INVALIDARG, 0, &lpError); 1236 ok(sc == S_OK && !lpError, 1237 "GetLastError: Expected S_OK, null, got 0x%08X,%p\n", sc, lpError); 1238 1239 /* Get prop tags - succeeds returning 0 items */ 1240 lpTags = NULL; 1241 sc = IPropData_GetPropList(lpIProp, 0, &lpTags); 1242 ok(sc == S_OK && lpTags && lpTags->cValues == 0, 1243 "GetPropList(empty): Expected S_OK, non-null, 0, got 0x%08X,%p,%d\n", 1244 sc, lpTags, lpTags ? lpTags->cValues : 0); 1245 if (lpTags) 1246 pMAPIFreeBuffer(lpTags); 1247 1248 /* Get props - succeeds returning 0 items */ 1249 lpProps = NULL; 1250 count = 0; 1251 tags.cValues = 1; 1252 tags.aulPropTag[0] = PR_IMPORTANCE; 1253 sc = IPropData_GetProps(lpIProp, (LPSPropTagArray)&tags, 0, &count, &lpProps); 1254 ok(sc == MAPI_W_ERRORS_RETURNED && lpProps && count == 1, 1255 "GetProps(empty): Expected ERRORS_RETURNED, non-null, 1, got 0x%08X,%p,%d\n", 1256 sc, lpProps, count); 1257 if (lpProps && count > 0) 1258 { 1259 ok(lpProps[0].ulPropTag == CHANGE_PROP_TYPE(PR_IMPORTANCE,PT_ERROR), 1260 "GetProps(empty): Expected %x, got %x\n", 1261 CHANGE_PROP_TYPE(PR_IMPORTANCE,PT_ERROR), lpProps[0].ulPropTag); 1262 1263 pMAPIFreeBuffer(lpProps); 1264 } 1265 1266 /* Add (NULL) - Can't add NULLs */ 1267 lpProbs = NULL; 1268 pvs[0].ulPropTag = PROP_TAG(PT_NULL,0x01); 1269 sc = IPropData_SetProps(lpIProp, 1, pvs, &lpProbs); 1270 ok(sc == MAPI_E_INVALID_PARAMETER && !lpProbs, 1271 "SetProps(): Expected INVALID_PARAMETER, null, got 0x%08X,%p\n", 1272 sc, lpProbs); 1273 1274 /* Add (OBJECT) - Can't add OBJECTs */ 1275 lpProbs = NULL; 1276 pvs[0].ulPropTag = PROP_TAG(PT_OBJECT,0x01); 1277 sc = IPropData_SetProps(lpIProp, 1, pvs, &lpProbs); 1278 ok(sc == MAPI_E_INVALID_PARAMETER && !lpProbs, 1279 "SetProps(OBJECT): Expected INVALID_PARAMETER, null, got 0x%08X,%p\n", 1280 sc, lpProbs); 1281 1282 /* Add - Adds value */ 1283 lpProbs = NULL; 1284 pvs[0].ulPropTag = PR_IMPORTANCE; 1285 sc = IPropData_SetProps(lpIProp, 1, pvs, &lpProbs); 1286 ok(sc == S_OK && !lpProbs, 1287 "SetProps(ERROR): Expected S_OK, null, got 0x%08X,%p\n", sc, lpProbs); 1288 1289 /* Get prop list - returns 1 item */ 1290 lpTags = NULL; 1291 IPropData_GetPropList(lpIProp, 0, &lpTags); 1292 ok(sc == S_OK && lpTags && lpTags->cValues == 1, 1293 "GetPropList: Expected S_OK, non-null, 1, got 0x%08X,%p,%d\n", 1294 sc, lpTags, lpTags ? lpTags->cValues : 0); 1295 if (lpTags && lpTags->cValues > 0) 1296 { 1297 ok(lpTags->aulPropTag[0] == PR_IMPORTANCE, 1298 "GetPropList: Expected %x, got %x\n", 1299 PR_IMPORTANCE, lpTags->aulPropTag[0]); 1300 pMAPIFreeBuffer(lpTags); 1301 } 1302 1303 /* Set access to read and write */ 1304 sc = IPropData_HrSetObjAccess(lpIProp, IPROP_READWRITE); 1305 ok(sc == S_OK, "SetObjAccess(WRITE): Expected S_OK got 0x%08X\n", sc); 1306 1307 tags.cValues = 1; 1308 tags.aulPropTag[0] = PR_IMPORTANCE; 1309 1310 /* Set item access (bad access) - Fails */ 1311 access[0] = 0; 1312 sc = IPropData_HrSetPropAccess(lpIProp, (LPSPropTagArray)&tags, access); 1313 ok(sc == MAPI_E_INVALID_PARAMETER, 1314 "SetPropAccess(0): Expected INVALID_PARAMETER got 0x%08X\n",sc); 1315 access[0] = IPROP_READWRITE; 1316 sc = IPropData_HrSetPropAccess(lpIProp, (LPSPropTagArray)&tags, access); 1317 ok(sc == MAPI_E_INVALID_PARAMETER, 1318 "SetPropAccess(RW): Expected INVALID_PARAMETER got 0x%08X\n",sc); 1319 access[0] = IPROP_CLEAN; 1320 sc = IPropData_HrSetPropAccess(lpIProp, (LPSPropTagArray)&tags, access); 1321 ok(sc == MAPI_E_INVALID_PARAMETER, 1322 "SetPropAccess(C): Expected INVALID_PARAMETER got 0x%08X\n",sc); 1323 1324 /* Set item access to read/write/clean */ 1325 tags.cValues = 1; 1326 tags.aulPropTag[0] = PR_IMPORTANCE; 1327 access[0] = IPROP_READWRITE|IPROP_CLEAN; 1328 sc = IPropData_HrSetPropAccess(lpIProp, (LPSPropTagArray)&tags, access); 1329 ok(sc == S_OK, "SetPropAccess(RW/C): Expected S_OK got 0x%08X\n",sc); 1330 1331 /* Set object access to read only */ 1332 sc = IPropData_HrSetObjAccess(lpIProp, IPROP_READONLY); 1333 ok(sc == S_OK, "SetObjAccess(READ): Expected S_OK got 0x%08X\n", sc); 1334 1335 /* Set item access to read/write/dirty - doesn't care about RO object */ 1336 access[0] = IPROP_READONLY|IPROP_DIRTY; 1337 sc = IPropData_HrSetPropAccess(lpIProp, (LPSPropTagArray)&tags, access); 1338 ok(sc == S_OK, "SetPropAccess(WRITE): Expected S_OK got 0x%08X\n", sc); 1339 1340 /* Delete any item when set to read only - Error */ 1341 lpProbs = NULL; 1342 tags.aulPropTag[0] = PR_RESPONSE_REQUESTED; 1343 sc = IPropData_DeleteProps(lpIProp, (LPSPropTagArray)&tags, &lpProbs); 1344 ok(sc == E_ACCESSDENIED && !lpProbs, 1345 "DeleteProps(nonexistent): Expected E_ACCESSDENIED null got 0x%08X %p\n", 1346 sc, lpProbs); 1347 1348 /* Set access to read and write */ 1349 sc = IPropData_HrSetObjAccess(lpIProp, IPROP_READWRITE); 1350 ok(sc == S_OK, "SetObjAccess(WRITE): Expected S_OK got 0x%08X\n", sc); 1351 1352 /* Delete nonexistent item - No error */ 1353 lpProbs = NULL; 1354 tags.aulPropTag[0] = PR_RESPONSE_REQUESTED; 1355 sc = IPropData_DeleteProps(lpIProp, (LPSPropTagArray)&tags, &lpProbs); 1356 ok(sc == S_OK && !lpProbs, 1357 "DeleteProps(nonexistent): Expected S_OK null got 0x%08X %p\n", 1358 sc, lpProbs); 1359 1360 /* Delete existing item (r/o) - No error, but lpProbs populated */ 1361 lpProbs = NULL; 1362 tags.aulPropTag[0] = PR_IMPORTANCE; 1363 sc = IPropData_DeleteProps(lpIProp, (LPSPropTagArray)&tags, &lpProbs); 1364 ok(sc == S_OK && lpProbs, 1365 "DeleteProps(RO): Expected S_OK non-null got 0x%08X %p\n", sc, lpProbs); 1366 1367 if (lpProbs && lpProbs->cProblem > 0) 1368 { 1369 ok(lpProbs->cProblem == 1 && 1370 lpProbs->aProblem[0].ulIndex == 0 && 1371 lpProbs->aProblem[0].ulPropTag == PR_IMPORTANCE && 1372 lpProbs->aProblem[0].scode == E_ACCESSDENIED, 1373 "DeleteProps(RO): Expected (1,0,%x,%x) got (%d,%x,%x)\n", 1374 PR_IMPORTANCE, E_ACCESSDENIED, 1375 lpProbs->aProblem[0].ulIndex, lpProbs->aProblem[0].ulPropTag, 1376 lpProbs->aProblem[0].scode); 1377 pMAPIFreeBuffer(lpProbs); 1378 } 1379 1380 lpProbs = NULL; 1381 tags.cValues = 1; 1382 tags.aulPropTag[0] = PR_RESPONSE_REQUESTED; 1383 IPropData_HrAddObjProps(lpIProp, (LPSPropTagArray)&tags, &lpProbs); 1384 ok(sc == S_OK && !lpProbs, 1385 "AddObjProps(RO): Expected S_OK null got 0x%08X %p\n", sc, lpProbs); 1386 1387 /* Get prop list - returns 1 item */ 1388 lpTags = NULL; 1389 IPropData_GetPropList(lpIProp, 0, &lpTags); 1390 ok(sc == S_OK && lpTags && lpTags->cValues == 1, 1391 "GetPropList: Expected S_OK, non-null, 1, got 0x%08X,%p,%d\n", 1392 sc, lpTags, lpTags ? lpTags->cValues : 0); 1393 if (lpTags && lpTags->cValues > 0) 1394 { 1395 ok(lpTags->aulPropTag[0] == PR_IMPORTANCE, 1396 "GetPropList: Expected %x, got %x\n", 1397 PR_IMPORTANCE, lpTags->aulPropTag[0]); 1398 pMAPIFreeBuffer(lpTags); 1399 } 1400 1401 /* Set item to r/w again */ 1402 access[0] = IPROP_READWRITE|IPROP_DIRTY; 1403 sc = IPropData_HrSetPropAccess(lpIProp, (LPSPropTagArray)&tags, access); 1404 ok(sc == S_OK, "SetPropAccess(WRITE): Expected S_OK got 0x%08X\n", sc); 1405 1406 /* Delete existing item (r/w) - No error, no problems */ 1407 lpProbs = NULL; 1408 sc = IPropData_DeleteProps(lpIProp, (LPSPropTagArray)&tags, &lpProbs); 1409 ok(sc == S_OK && !lpProbs, 1410 "DeleteProps(RO): Expected S_OK null got 0x%08X %p\n", sc, lpProbs); 1411 1412 /* Free the list */ 1413 IPropData_Release(lpIProp); 1414 } 1415 1416 START_TEST(prop) 1417 { 1418 SCODE ret; 1419 1420 if (!HaveDefaultMailClient()) 1421 { 1422 win_skip("No default mail client installed\n"); 1423 return; 1424 } 1425 1426 if(!InitFuncPtrs()) 1427 { 1428 win_skip("Needed functions are not available\n"); 1429 return; 1430 } 1431 1432 SetLastError(0xdeadbeef); 1433 ret = pScInitMapiUtil(0); 1434 if ((ret != S_OK) && (GetLastError() == ERROR_PROC_NOT_FOUND)) 1435 { 1436 win_skip("ScInitMapiUtil is not implemented\n"); 1437 FreeLibrary(hMapi32); 1438 return; 1439 } 1440 else if ((ret == E_FAIL) && (GetLastError() == ERROR_INVALID_HANDLE)) 1441 { 1442 win_skip("ScInitMapiUtil doesn't work on some Win98 and WinME systems\n"); 1443 FreeLibrary(hMapi32); 1444 return; 1445 } 1446 1447 test_PropCopyMore(); 1448 test_UlPropSize(); 1449 1450 /* We call MAPIInitialize here for the benefit of native extended MAPI 1451 * providers which crash in the FPropContainsProp tests when MAPIInitialize 1452 * has not been called. Since MAPIInitialize is irrelevant for FPropContainsProp 1453 * on Wine, we do not care whether MAPIInitialize succeeds. */ 1454 if (pMAPIInitialize) 1455 ret = pMAPIInitialize(NULL); 1456 test_FPropContainsProp(); 1457 if (pMAPIUninitialize && ret == S_OK) 1458 pMAPIUninitialize(); 1459 1460 test_FPropCompareProp(); 1461 test_LPropCompareProp(); 1462 test_PpropFindProp(); 1463 test_ScCountProps(); 1464 test_ScCopyRelocProps(); 1465 test_LpValFindProp(); 1466 test_FBadRglpszA(); 1467 test_FBadRglpszW(); 1468 test_FBadRowSet(); 1469 test_FBadPropTag(); 1470 test_FBadRow(); 1471 test_FBadProp(); 1472 test_FBadColumnSet(); 1473 1474 test_IProp(); 1475 1476 pDeinitMapiUtil(); 1477 FreeLibrary(hMapi32); 1478 } 1479