mapi32/tests: Fix the PropCopyMore tests and add an additional test.
[wine/multimedia.git] / dlls / mapi32 / tests / prop.c
blobce6fbd577e3dbbcc4a3902e80ebb3950b6e6b8df
1 /*
2 * Unit test suite for MAPI property functions
4 * Copyright 2004 Jon Griffiths
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.
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.
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
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"
32 static HMODULE hMapi32 = 0;
34 static SCODE (WINAPI *pScInitMapiUtil)(ULONG);
35 static SCODE (WINAPI *pPropCopyMore)(LPSPropValue,LPSPropValue,ALLOCATEMORE*,LPVOID);
36 static ULONG (WINAPI *pUlPropSize)(LPSPropValue);
37 static BOOL (WINAPI *pFPropContainsProp)(LPSPropValue,LPSPropValue,ULONG);
38 static BOOL (WINAPI *pFPropCompareProp)(LPSPropValue,ULONG,LPSPropValue);
39 static LONG (WINAPI *pLPropCompareProp)(LPSPropValue,LPSPropValue);
40 static LPSPropValue (WINAPI *pPpropFindProp)(LPSPropValue,ULONG,ULONG);
41 static SCODE (WINAPI *pScCountProps)(INT,LPSPropValue,ULONG*);
42 static SCODE (WINAPI *pScCopyProps)(int,LPSPropValue,LPVOID,ULONG*);
43 static SCODE (WINAPI *pScRelocProps)(int,LPSPropValue,LPVOID,LPVOID,ULONG*);
44 static LPSPropValue (WINAPI *pLpValFindProp)(ULONG,ULONG,LPSPropValue);
45 static BOOL (WINAPI *pFBadRglpszA)(LPSTR*,ULONG);
46 static BOOL (WINAPI *pFBadRglpszW)(LPWSTR*,ULONG);
47 static BOOL (WINAPI *pFBadRowSet)(LPSRowSet);
48 static ULONG (WINAPI *pFBadPropTag)(ULONG);
49 static ULONG (WINAPI *pFBadRow)(LPSRow);
50 static ULONG (WINAPI *pFBadProp)(LPSPropValue);
51 static ULONG (WINAPI *pFBadColumnSet)(LPSPropTagArray);
52 static SCODE (WINAPI *pCreateIProp)(LPCIID,ALLOCATEBUFFER*,ALLOCATEMORE*,
53 FREEBUFFER*,LPVOID,LPPROPDATA*);
54 static SCODE (WINAPI *pMAPIAllocateBuffer)(ULONG, LPVOID);
55 static SCODE (WINAPI *pMAPIAllocateMore)(ULONG, LPVOID, LPVOID);
56 static SCODE (WINAPI *pMAPIFreeBuffer)(LPVOID);
58 static BOOL InitFuncPtrs(void)
60 hMapi32 = LoadLibraryA("mapi32.dll");
62 pScInitMapiUtil = (void*)GetProcAddress(hMapi32, "ScInitMapiUtil@4");
63 pMAPIAllocateBuffer = (void*)GetProcAddress(hMapi32, "MAPIAllocateBuffer");
64 pMAPIAllocateMore = (void*)GetProcAddress(hMapi32, "MAPIAllocateMore");
65 pMAPIFreeBuffer = (void*)GetProcAddress(hMapi32, "MAPIFreeBuffer");
66 if(pScInitMapiUtil && pMAPIAllocateBuffer && pMAPIAllocateMore && pMAPIFreeBuffer)
67 return TRUE;
68 else
69 return FALSE;
72 /* FIXME: Test PT_I2, PT_I4, PT_R4, PT_R8, PT_CURRENCY, PT_APPTIME, PT_SYSTIME,
73 * PT_ERROR, PT_BOOLEAN, PT_I8, and PT_CLSID. */
74 static ULONG ptTypes[] = {
75 PT_STRING8, PT_BINARY, PT_UNICODE
78 static inline int strcmpW(const WCHAR *str1, const WCHAR *str2)
80 while (*str1 && (*str1 == *str2)) { str1++; str2++; }
81 return *str1 - *str2;
84 static void test_PropCopyMore(void)
86 static char szHiA[] = "Hi!";
87 static WCHAR szHiW[] = { 'H', 'i', '!', '\0' };
88 SPropValue *lpDest = NULL, *lpSrc = NULL;
89 ULONG i;
90 SCODE scode;
92 pPropCopyMore = (void*)GetProcAddress(hMapi32, "PropCopyMore@16");
94 if (!pPropCopyMore)
96 win_skip("PropCopyMore is not available\n");
97 return;
100 scode = pMAPIAllocateBuffer(sizeof(SPropValue), &lpDest);
101 ok(scode == S_OK, "Expected MAPIAllocateBuffer to return S_OK, got 0x%x\n", scode);
102 if (FAILED(scode))
104 skip("MAPIAllocateBuffer failed\n");
105 return;
108 scode = pMAPIAllocateMore(sizeof(SPropValue), lpDest, &lpSrc);
109 ok(scode == S_OK, "Expected MAPIAllocateMore to return S_OK, got 0x%x\n", scode);
110 if (FAILED(scode))
112 skip("MAPIAllocateMore failed\n");
113 return;
116 for (i = 0; i < sizeof(ptTypes)/sizeof(ptTypes[0]); i++)
118 lpSrc->ulPropTag = ptTypes[i];
120 switch (ptTypes[i])
122 case PT_STRING8:
123 lpSrc->Value.lpszA = szHiA;
124 break;
125 case PT_UNICODE:
126 lpSrc->Value.lpszW = szHiW;
127 break;
128 case PT_BINARY:
129 lpSrc->Value.bin.cb = 4;
130 lpSrc->Value.bin.lpb = (LPBYTE)szHiA;
131 break;
134 memset(lpDest, 0xff, sizeof(SPropValue));
136 scode = pPropCopyMore(lpDest, lpSrc, (ALLOCATEMORE*)pMAPIAllocateMore, lpDest);
137 ok(!scode && lpDest->ulPropTag == lpSrc->ulPropTag,
138 "PropCopyMore: Expected 0x0,%d, got 0x%08x,%d\n",
139 lpSrc->ulPropTag, scode, lpDest->ulPropTag);
140 if (SUCCEEDED(scode))
142 switch (ptTypes[i])
144 case PT_STRING8:
145 ok(lstrcmpA(lpDest->Value.lpszA, lpSrc->Value.lpszA) == 0,
146 "PropCopyMore: Ascii string differs\n");
147 break;
148 case PT_UNICODE:
149 ok(strcmpW(lpDest->Value.lpszW, lpSrc->Value.lpszW) == 0,
150 "PropCopyMore: Unicode string differs\n");
151 break;
152 case PT_BINARY:
153 ok(lpDest->Value.bin.cb == 4 &&
154 !memcmp(lpSrc->Value.bin.lpb, lpDest->Value.bin.lpb, 4),
155 "PropCopyMore: Binary array differs\n");
156 break;
161 /* Since all allocations are linked, freeing lpDest frees everything */
162 scode = pMAPIFreeBuffer(lpDest);
163 ok(scode == S_OK, "Expected MAPIFreeBuffer to return S_OK, got 0x%x\n", scode);
166 static void test_UlPropSize(void)
168 static char szHiA[] = "Hi!";
169 static WCHAR szHiW[] = { 'H', 'i', '!', '\0' };
170 LPSTR buffa[2];
171 LPWSTR buffw[2];
172 SBinary buffbin[2];
173 ULONG pt, exp, res;
175 pUlPropSize = (void*)GetProcAddress(hMapi32, "UlPropSize@4");
177 if (!pUlPropSize)
179 win_skip("UlPropSize is not available\n");
180 return;
183 for (pt = 0; pt < PROP_ID_INVALID; pt++)
185 SPropValue pv;
187 memset(&pv, 0 ,sizeof(pv));
188 pv.ulPropTag = pt;
190 exp = 1u; /* Default to one item for non-MV properties */
192 switch (PROP_TYPE(pt))
194 case PT_MV_I2: pv.Value.MVi.cValues = exp = 2;
195 case PT_I2: exp *= sizeof(USHORT); break;
196 case PT_MV_I4: pv.Value.MVl.cValues = exp = 2;
197 case PT_I4: exp *= sizeof(LONG); break;
198 case PT_MV_R4: pv.Value.MVflt.cValues = exp = 2;
199 case PT_R4: exp *= sizeof(float); break;
200 case PT_MV_DOUBLE: pv.Value.MVdbl.cValues = exp = 2;
201 case PT_R8: exp *= sizeof(double); break;
202 case PT_MV_CURRENCY: pv.Value.MVcur.cValues = exp = 2;
203 case PT_CURRENCY: exp *= sizeof(CY); break;
204 case PT_MV_APPTIME: pv.Value.MVat.cValues = exp = 2;
205 case PT_APPTIME: exp *= sizeof(double); break;
206 case PT_MV_SYSTIME: pv.Value.MVft.cValues = exp = 2;
207 case PT_SYSTIME: exp *= sizeof(FILETIME); break;
208 case PT_ERROR: exp = sizeof(SCODE); break;
209 case PT_BOOLEAN: exp = sizeof(USHORT); break;
210 case PT_OBJECT: exp = 0; break;
211 case PT_MV_I8: pv.Value.MVli.cValues = exp = 2;
212 case PT_I8: exp *= sizeof(LONG64); break;
213 #if 0
214 /* My version of native mapi returns 0 for PT_MV_CLSID even if a valid
215 * array is given. This _has_ to be a bug, so Wine does
216 * the right thing(tm) and we don't test it here.
218 case PT_MV_CLSID: pv.Value.MVguid.cValues = exp = 2;
219 #endif
220 case PT_CLSID: exp *= sizeof(GUID); break;
221 case PT_STRING8:
222 pv.Value.lpszA = szHiA;
223 exp = 4;
224 break;
225 case PT_UNICODE:
226 pv.Value.lpszW = szHiW;
227 exp = 4 * sizeof(WCHAR);
228 break;
229 case PT_BINARY:
230 pv.Value.bin.cb = exp = 19;
231 break;
232 case PT_MV_STRING8:
233 pv.Value.MVszA.cValues = 2;
234 pv.Value.MVszA.lppszA = buffa;
235 buffa[0] = szHiA;
236 buffa[1] = szHiA;
237 exp = 8;
238 break;
239 case PT_MV_UNICODE:
240 pv.Value.MVszW.cValues = 2;
241 pv.Value.MVszW.lppszW = buffw;
242 buffw[0] = szHiW;
243 buffw[1] = szHiW;
244 exp = 8 * sizeof(WCHAR);
245 break;
246 case PT_MV_BINARY:
247 pv.Value.MVbin.cValues = 2;
248 pv.Value.MVbin.lpbin = buffbin;
249 buffbin[0].cb = 19;
250 buffbin[1].cb = 1;
251 exp = 20;
252 break;
253 default:
254 exp = 0;
257 res = pUlPropSize(&pv);
258 ok(res == exp,
259 "pt= %d: Expected %d, got %d\n", pt, exp, res);
263 static void test_FPropContainsProp(void)
265 static char szFull[] = "Full String";
266 static char szFullLower[] = "full string";
267 static char szPrefix[] = "Full";
268 static char szPrefixLower[] = "full";
269 static char szSubstring[] = "ll St";
270 static char szSubstringLower[] = "ll st";
271 SPropValue pvLeft, pvRight;
272 ULONG pt;
273 BOOL bRet;
275 pFPropContainsProp = (void*)GetProcAddress(hMapi32, "FPropContainsProp@12");
277 if (!pFPropContainsProp)
279 win_skip("FPropContainsProp is not available\n");
280 return;
283 /* Ensure that only PT_STRING8 and PT_BINARY are handled */
284 for (pt = 0; pt < PROP_ID_INVALID; pt++)
286 if (pt == PT_STRING8 || pt == PT_BINARY)
287 continue; /* test these later */
289 memset(&pvLeft, 0 ,sizeof(pvLeft));
290 memset(&pvRight, 0 ,sizeof(pvRight));
291 pvLeft.ulPropTag = pvRight.ulPropTag = pt;
293 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
294 ok(bRet == FALSE, "pt= %d: Expected FALSE, got %d\n", pt, bRet);
297 /* test the various flag combinations */
298 pvLeft.ulPropTag = pvRight.ulPropTag = PT_STRING8;
299 pvLeft.Value.lpszA = szFull;
300 pvRight.Value.lpszA = szFull;
302 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
303 ok(bRet == TRUE, "(full,full)[] match failed\n");
304 pvRight.Value.lpszA = szPrefix;
305 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
306 ok(bRet == FALSE, "(full,prefix)[] match failed\n");
307 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
308 ok(bRet == TRUE, "(full,prefix)[PREFIX] match failed\n");
309 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
310 ok(bRet == TRUE, "(full,prefix)[SUBSTRING] match failed\n");
311 pvRight.Value.lpszA = szPrefixLower;
312 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
313 ok(bRet == FALSE, "(full,prefixlow)[PREFIX] match failed\n");
314 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
315 ok(bRet == FALSE, "(full,prefixlow)[SUBSTRING] match failed\n");
316 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX|FL_IGNORECASE);
317 ok(bRet == TRUE, "(full,prefixlow)[PREFIX|IGNORECASE] match failed\n");
318 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING|FL_IGNORECASE);
319 ok(bRet == TRUE, "(full,prefixlow)[SUBSTRING|IGNORECASE] match failed\n");
320 pvRight.Value.lpszA = szSubstring;
321 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
322 ok(bRet == FALSE, "(full,substr)[] match failed\n");
323 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
324 ok(bRet == FALSE, "(full,substr)[PREFIX] match failed\n");
325 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
326 ok(bRet == TRUE, "(full,substr)[SUBSTRING] match failed\n");
327 pvRight.Value.lpszA = szSubstringLower;
328 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
329 ok(bRet == FALSE, "(full,substrlow)[PREFIX] match failed\n");
330 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
331 ok(bRet == FALSE, "(full,substrlow)[SUBSTRING] match failed\n");
332 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX|FL_IGNORECASE);
333 ok(bRet == FALSE, "(full,substrlow)[PREFIX|IGNORECASE] match failed\n");
334 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING|FL_IGNORECASE);
335 ok(bRet == TRUE, "(full,substrlow)[SUBSTRING|IGNORECASE] match failed\n");
336 pvRight.Value.lpszA = szFullLower;
337 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING|FL_IGNORECASE);
338 ok(bRet == TRUE, "(full,fulllow)[IGNORECASE] match failed\n");
340 pvLeft.ulPropTag = pvRight.ulPropTag = PT_BINARY;
341 pvLeft.Value.bin.lpb = (LPBYTE)szFull;
342 pvRight.Value.bin.lpb = (LPBYTE)szFull;
343 pvLeft.Value.bin.cb = pvRight.Value.bin.cb = strlen(szFull);
345 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
346 ok(bRet == TRUE, "bin(full,full)[] match failed\n");
347 pvRight.Value.bin.lpb = (LPBYTE)szPrefix;
348 pvRight.Value.bin.cb = strlen(szPrefix);
349 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
350 ok(bRet == FALSE, "bin(full,prefix)[] match failed\n");
351 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
352 ok(bRet == TRUE, "bin(full,prefix)[PREFIX] match failed\n");
353 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
354 ok(bRet == TRUE, "bin(full,prefix)[SUBSTRING] match failed\n");
355 pvRight.Value.bin.lpb = (LPBYTE)szPrefixLower;
356 pvRight.Value.bin.cb = strlen(szPrefixLower);
357 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
358 ok(bRet == FALSE, "bin(full,prefixlow)[PREFIX] match failed\n");
359 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
360 ok(bRet == FALSE, "bin(full,prefixlow)[SUBSTRING] match failed\n");
361 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX|FL_IGNORECASE);
362 ok(bRet == FALSE, "bin(full,prefixlow)[PREFIX|IGNORECASE] match failed\n");
363 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING|FL_IGNORECASE);
364 ok(bRet == FALSE, "bin(full,prefixlow)[SUBSTRING|IGNORECASE] match failed\n");
365 pvRight.Value.bin.lpb = (LPBYTE)szSubstring;
366 pvRight.Value.bin.cb = strlen(szSubstring);
367 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
368 ok(bRet == FALSE, "bin(full,substr)[] match failed\n");
369 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
370 ok(bRet == FALSE, "bin(full,substr)[PREFIX] match failed\n");
371 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
372 ok(bRet == TRUE, "bin(full,substr)[SUBSTRING] match failed\n");
373 pvRight.Value.bin.lpb = (LPBYTE)szSubstringLower;
374 pvRight.Value.bin.cb = strlen(szSubstringLower);
375 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
376 ok(bRet == FALSE, "bin(full,substrlow)[PREFIX] match failed\n");
377 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
378 ok(bRet == FALSE, "bin(full,substrlow)[SUBSTRING] match failed\n");
379 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX|FL_IGNORECASE);
380 ok(bRet == FALSE, "bin(full,substrlow)[PREFIX|IGNORECASE] match failed\n");
381 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING|FL_IGNORECASE);
382 ok(bRet == FALSE, "bin(full,substrlow)[SUBSTRING|IGNORECASE] match failed\n");
383 pvRight.Value.bin.lpb = (LPBYTE)szFullLower;
384 pvRight.Value.bin.cb = strlen(szFullLower);
385 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING|FL_IGNORECASE);
386 ok(bRet == FALSE, "bin(full,fulllow)[IGNORECASE] match failed\n");
389 typedef struct tagFPropCompareProp_Result
391 SHORT lVal;
392 SHORT rVal;
393 ULONG relOp;
394 BOOL bRet;
395 } FPropCompareProp_Result;
397 static const FPropCompareProp_Result FPCProp_Results[] =
399 { 1, 2, RELOP_LT, TRUE },
400 { 1, 1, RELOP_LT, FALSE },
401 { 2, 1, RELOP_LT, FALSE },
402 { 1, 2, RELOP_LE, TRUE },
403 { 1, 1, RELOP_LE, TRUE },
404 { 2, 1, RELOP_LE, FALSE },
405 { 1, 2, RELOP_GT, FALSE },
406 { 1, 1, RELOP_GT, FALSE },
407 { 2, 1, RELOP_GT, TRUE },
408 { 1, 2, RELOP_GE, FALSE },
409 { 1, 1, RELOP_GE, TRUE },
410 { 2, 1, RELOP_GE, TRUE },
411 { 1, 2, RELOP_EQ, FALSE },
412 { 1, 1, RELOP_EQ, TRUE },
413 { 2, 1, RELOP_EQ, FALSE }
416 static const char *relops[] = { "RELOP_LT", "RELOP_LE", "RELOP_GT", "RELOP_GE", "RELOP_EQ" };
418 static void test_FPropCompareProp(void)
420 SPropValue pvLeft, pvRight;
421 GUID lguid, rguid;
422 char lbuffa[2], rbuffa[2];
423 WCHAR lbuffw[2], rbuffw[2];
424 ULONG i, j;
425 BOOL bRet, bExp;
427 pFPropCompareProp = (void*)GetProcAddress(hMapi32, "FPropCompareProp@12");
429 if (!pFPropCompareProp)
431 win_skip("FPropCompareProp is not available\n");
432 return;
435 lbuffa[1] = '\0';
436 rbuffa[1] = '\0';
437 lbuffw[1] = '\0';
438 rbuffw[1] = '\0';
440 for (i = 0; i < sizeof(ptTypes)/sizeof(ptTypes[0]); i++)
442 pvLeft.ulPropTag = pvRight.ulPropTag = ptTypes[i];
444 for (j = 0; j < sizeof(FPCProp_Results)/sizeof(FPCProp_Results[0]); j++)
446 SHORT lVal = FPCProp_Results[j].lVal;
447 SHORT rVal = FPCProp_Results[j].rVal;
449 bExp = FPCProp_Results[j].bRet;
451 switch (ptTypes[i])
453 case PT_BOOLEAN:
454 /* Boolean values have no concept of less or greater than, only equality */
455 if ((lVal == 1 && rVal == 2 && FPCProp_Results[j].relOp == RELOP_LT) ||
456 (lVal == 2 && rVal == 1 && FPCProp_Results[j].relOp == RELOP_LE)||
457 (lVal == 2 && rVal == 1 && FPCProp_Results[j].relOp == RELOP_GT)||
458 (lVal == 1 && rVal == 2 && FPCProp_Results[j].relOp == RELOP_GE)||
459 (lVal == 1 && rVal == 2 && FPCProp_Results[j].relOp == RELOP_EQ)||
460 (lVal == 2 && rVal == 1 && FPCProp_Results[j].relOp == RELOP_EQ))
461 bExp = !bExp;
462 /* Fall through ... */
463 case PT_I2:
464 pvLeft.Value.i = lVal;
465 pvRight.Value.i = rVal;
466 break;
467 case PT_ERROR:
468 case PT_I4:
469 pvLeft.Value.l = lVal;
470 pvRight.Value.l = rVal;
471 break;
472 case PT_R4:
473 pvLeft.Value.flt = lVal;
474 pvRight.Value.flt = rVal;
475 break;
476 case PT_APPTIME:
477 case PT_R8:
478 pvLeft.Value.dbl = lVal;
479 pvRight.Value.dbl = rVal;
480 break;
481 case PT_CURRENCY:
482 pvLeft.Value.cur.int64 = lVal;
483 pvRight.Value.cur.int64 = rVal;
484 break;
485 case PT_SYSTIME:
486 pvLeft.Value.ft.dwLowDateTime = lVal;
487 pvLeft.Value.ft.dwHighDateTime = 0;
488 pvRight.Value.ft.dwLowDateTime = rVal;
489 pvRight.Value.ft.dwHighDateTime = 0;
490 break;
491 case PT_I8:
492 pvLeft.Value.li.u.LowPart = lVal;
493 pvLeft.Value.li.u.HighPart = 0;
494 pvRight.Value.li.u.LowPart = rVal;
495 pvRight.Value.li.u.HighPart = 0;
496 break;
497 case PT_CLSID:
498 memset(&lguid, 0, sizeof(GUID));
499 memset(&rguid, 0, sizeof(GUID));
500 lguid.Data4[7] = lVal;
501 rguid.Data4[7] = rVal;
502 pvLeft.Value.lpguid = &lguid;
503 pvRight.Value.lpguid = &rguid;
504 break;
505 case PT_STRING8:
506 pvLeft.Value.lpszA = lbuffa;
507 pvRight.Value.lpszA = rbuffa;
508 lbuffa[0] = '0' + lVal;
509 rbuffa[0] = '0' + rVal;
510 break;
511 case PT_UNICODE:
512 pvLeft.Value.lpszW = lbuffw;
513 pvRight.Value.lpszW = rbuffw;
514 lbuffw[0] = '0' + lVal;
515 rbuffw[0] = '0' + rVal;
516 break;
517 case PT_BINARY:
518 pvLeft.Value.bin.cb = 1;
519 pvRight.Value.bin.cb = 1;
520 pvLeft.Value.bin.lpb = (LPBYTE)lbuffa;
521 pvRight.Value.bin.lpb = (LPBYTE)rbuffa;
522 lbuffa[0] = lVal;
523 rbuffa[0] = rVal;
524 break;
527 bRet = pFPropCompareProp(&pvLeft, FPCProp_Results[j].relOp, &pvRight);
528 ok(bRet == bExp,
529 "pt %d (%d,%d,%s): expected %d, got %d\n", ptTypes[i],
530 FPCProp_Results[j].lVal, FPCProp_Results[j].rVal,
531 relops[FPCProp_Results[j].relOp], bExp, bRet);
536 typedef struct tagLPropCompareProp_Result
538 SHORT lVal;
539 SHORT rVal;
540 INT iRet;
541 } LPropCompareProp_Result;
543 static const LPropCompareProp_Result LPCProp_Results[] =
545 { 1, 2, -1 },
546 { 1, 1, 0 },
547 { 2, 1, 1 },
550 static void test_LPropCompareProp(void)
552 SPropValue pvLeft, pvRight;
553 GUID lguid, rguid;
554 char lbuffa[2], rbuffa[2];
555 WCHAR lbuffw[2], rbuffw[2];
556 ULONG i, j;
557 INT iRet, iExp;
559 pLPropCompareProp = (void*)GetProcAddress(hMapi32, "LPropCompareProp@8");
561 if (!pLPropCompareProp)
563 win_skip("LPropCompareProp is not available\n");
564 return;
567 lbuffa[1] = '\0';
568 rbuffa[1] = '\0';
569 lbuffw[1] = '\0';
570 rbuffw[1] = '\0';
572 for (i = 0; i < sizeof(ptTypes)/sizeof(ptTypes[0]); i++)
574 pvLeft.ulPropTag = pvRight.ulPropTag = ptTypes[i];
576 for (j = 0; j < sizeof(LPCProp_Results)/sizeof(LPCProp_Results[0]); j++)
578 SHORT lVal = LPCProp_Results[j].lVal;
579 SHORT rVal = LPCProp_Results[j].rVal;
581 iExp = LPCProp_Results[j].iRet;
583 switch (ptTypes[i])
585 case PT_BOOLEAN:
586 /* Boolean values have no concept of less or greater than, only equality */
587 if (lVal && rVal)
588 iExp = 0;
589 /* Fall through ... */
590 case PT_I2:
591 pvLeft.Value.i = lVal;
592 pvRight.Value.i = rVal;
593 break;
594 case PT_ERROR:
595 case PT_I4:
596 pvLeft.Value.l = lVal;
597 pvRight.Value.l = rVal;
598 break;
599 case PT_R4:
600 pvLeft.Value.flt = lVal;
601 pvRight.Value.flt = rVal;
602 break;
603 case PT_APPTIME:
604 case PT_R8:
605 pvLeft.Value.dbl = lVal;
606 pvRight.Value.dbl = rVal;
607 break;
608 case PT_CURRENCY:
609 pvLeft.Value.cur.int64 = lVal;
610 pvRight.Value.cur.int64 = rVal;
611 break;
612 case PT_SYSTIME:
613 pvLeft.Value.ft.dwLowDateTime = lVal;
614 pvLeft.Value.ft.dwHighDateTime = 0;
615 pvRight.Value.ft.dwLowDateTime = rVal;
616 pvRight.Value.ft.dwHighDateTime = 0;
617 break;
618 case PT_I8:
619 pvLeft.Value.li.u.LowPart = lVal;
620 pvLeft.Value.li.u.HighPart = 0;
621 pvRight.Value.li.u.LowPart = rVal;
622 pvRight.Value.li.u.HighPart = 0;
623 break;
624 case PT_CLSID:
625 memset(&lguid, 0, sizeof(GUID));
626 memset(&rguid, 0, sizeof(GUID));
627 lguid.Data4[7] = lVal;
628 rguid.Data4[7] = rVal;
629 pvLeft.Value.lpguid = &lguid;
630 pvRight.Value.lpguid = &rguid;
631 break;
632 case PT_STRING8:
633 pvLeft.Value.lpszA = lbuffa;
634 pvRight.Value.lpszA = rbuffa;
635 lbuffa[0] = '0' + lVal;
636 rbuffa[0] = '0' + rVal;
637 break;
638 case PT_UNICODE:
639 pvLeft.Value.lpszW = lbuffw;
640 pvRight.Value.lpszW = rbuffw;
641 lbuffw[0] = '0' + lVal;
642 rbuffw[0] = '0' + rVal;
643 break;
644 case PT_BINARY:
645 pvLeft.Value.bin.cb = 1;
646 pvRight.Value.bin.cb = 1;
647 pvLeft.Value.bin.lpb = (LPBYTE)lbuffa;
648 pvRight.Value.bin.lpb = (LPBYTE)rbuffa;
649 lbuffa[0] = lVal;
650 rbuffa[0] = rVal;
651 break;
654 iRet = pLPropCompareProp(&pvLeft, &pvRight);
655 ok(iRet == iExp,
656 "pt %d (%d,%d): expected %d, got %d\n", ptTypes[i],
657 LPCProp_Results[j].lVal, LPCProp_Results[j].rVal, iExp, iRet);
662 static void test_PpropFindProp(void)
664 SPropValue pvProp, *pRet;
665 ULONG i;
667 pPpropFindProp = (void*)GetProcAddress(hMapi32, "PpropFindProp@12");
669 if (!pPpropFindProp)
671 win_skip("PpropFindProp is not available\n");
672 return;
675 for (i = 0; i < sizeof(ptTypes)/sizeof(ptTypes[0]); i++)
677 pvProp.ulPropTag = ptTypes[i];
679 pRet = pPpropFindProp(&pvProp, 1u, ptTypes[i]);
680 ok(pRet == &pvProp,
681 "PpropFindProp[%d]: Didn't find existing propery\n",
682 ptTypes[i]);
684 pRet = pPpropFindProp(&pvProp, 1u, i ? ptTypes[i-1] : ptTypes[i+1]);
685 ok(pRet == NULL, "PpropFindProp[%d]: Found nonexistent propery\n",
686 ptTypes[i]);
689 pvProp.ulPropTag = PROP_TAG(PT_I2, 1u);
690 pRet = pPpropFindProp(&pvProp, 1u, PROP_TAG(PT_UNSPECIFIED, 0u));
691 ok(pRet == NULL, "PpropFindProp[UNSPECIFIED]: Matched on different id\n");
692 pRet = pPpropFindProp(&pvProp, 1u, PROP_TAG(PT_UNSPECIFIED, 1u));
693 ok(pRet == &pvProp, "PpropFindProp[UNSPECIFIED]: Didn't match id\n");
696 static void test_ScCountProps(void)
698 static char szHiA[] = "Hi!";
699 static WCHAR szHiW[] = { 'H', 'i', '!', '\0' };
700 static const ULONG ULHILEN = 4; /* chars in szHiA/W incl. NUL */
701 LPSTR buffa[3];
702 LPWSTR buffw[3];
703 SBinary buffbin[3];
704 GUID iids[4], *iid = iids;
705 SCODE res;
706 ULONG pt, exp, ulRet;
707 int success = 1;
709 pScCountProps = (void*)GetProcAddress(hMapi32, "ScCountProps@12");
711 if (!pScCountProps)
713 win_skip("ScCountProps is not available\n");
714 return;
717 for (pt = 0; pt < PROP_ID_INVALID && success; pt++)
719 SPropValue pv;
721 memset(&pv, 0 ,sizeof(pv));
722 pv.ulPropTag = PROP_TAG(pt, 1u);
724 switch (PROP_TYPE(pt))
726 case PT_I2:
727 case PT_I4:
728 case PT_R4:
729 case PT_R8:
730 case PT_CURRENCY:
731 case PT_APPTIME:
732 case PT_SYSTIME:
733 case PT_ERROR:
734 case PT_BOOLEAN:
735 case PT_OBJECT:
736 case PT_I8:
737 exp = sizeof(pv);
738 break;
739 case PT_CLSID:
740 pv.Value.lpguid = iid;
741 exp = sizeof(GUID) + sizeof(pv);
742 break;
743 case PT_STRING8:
744 pv.Value.lpszA = szHiA;
745 exp = 4 + sizeof(pv);
746 break;
747 case PT_UNICODE:
748 pv.Value.lpszW = szHiW;
749 exp = 4 * sizeof(WCHAR) + sizeof(pv);
750 break;
751 case PT_BINARY:
752 pv.Value.bin.cb = 2;
753 pv.Value.bin.lpb = (LPBYTE)iid;
754 exp = 2 + sizeof(pv);
755 break;
756 case PT_MV_I2:
757 pv.Value.MVi.cValues = 3;
758 pv.Value.MVi.lpi = (SHORT*)iid;
759 exp = 3 * sizeof(SHORT) + sizeof(pv);
760 break;
761 case PT_MV_I4:
762 pv.Value.MVl.cValues = 3;
763 pv.Value.MVl.lpl = (LONG*)iid;
764 exp = 3 * sizeof(LONG) + sizeof(pv);
765 break;
766 case PT_MV_I8:
767 pv.Value.MVli.cValues = 3;
768 pv.Value.MVli.lpli = (LARGE_INTEGER*)iid;
769 exp = 3 * sizeof(LARGE_INTEGER) + sizeof(pv);
770 break;
771 case PT_MV_R4:
772 pv.Value.MVflt.cValues = 3;
773 pv.Value.MVflt.lpflt = (float*)iid;
774 exp = 3 * sizeof(float) + sizeof(pv);
775 break;
776 case PT_MV_APPTIME:
777 case PT_MV_R8:
778 pv.Value.MVdbl.cValues = 3;
779 pv.Value.MVdbl.lpdbl = (double*)iid;
780 exp = 3 * sizeof(double) + sizeof(pv);
781 break;
782 case PT_MV_CURRENCY:
783 pv.Value.MVcur.cValues = 3;
784 pv.Value.MVcur.lpcur = (CY*)iid;
785 exp = 3 * sizeof(CY) + sizeof(pv);
786 break;
787 case PT_MV_SYSTIME:
788 pv.Value.MVft.cValues = 3;
789 pv.Value.MVft.lpft = (FILETIME*)iid;
790 exp = 3 * sizeof(CY) + sizeof(pv);
791 break;
792 case PT_MV_STRING8:
793 pv.Value.MVszA.cValues = 3;
794 pv.Value.MVszA.lppszA = buffa;
795 buffa[0] = szHiA;
796 buffa[1] = szHiA;
797 buffa[2] = szHiA;
798 exp = ULHILEN * 3 + 3 * sizeof(char*) + sizeof(pv);
799 break;
800 case PT_MV_UNICODE:
801 pv.Value.MVszW.cValues = 3;
802 pv.Value.MVszW.lppszW = buffw;
803 buffw[0] = szHiW;
804 buffw[1] = szHiW;
805 buffw[2] = szHiW;
806 exp = ULHILEN * 3 * sizeof(WCHAR) + 3 * sizeof(WCHAR*) + sizeof(pv);
807 break;
808 case PT_MV_BINARY:
809 pv.Value.MVbin.cValues = 3;
810 pv.Value.MVbin.lpbin = buffbin;
811 buffbin[0].cb = 17;
812 buffbin[0].lpb = (LPBYTE)&iid;
813 buffbin[1].cb = 2;
814 buffbin[1].lpb = (LPBYTE)&iid;
815 buffbin[2].cb = 1;
816 buffbin[2].lpb = (LPBYTE)&iid;
817 exp = 20 + sizeof(pv) + sizeof(SBinary) * 3;
818 break;
819 default:
820 exp = 0;
823 ulRet = 0xffffffff;
824 res = pScCountProps(1, &pv, &ulRet);
825 if (!exp) {
826 success = res == MAPI_E_INVALID_PARAMETER && ulRet == 0xffffffff;
827 ok(success, "pt= %d: Expected failure, got %d, ret=0x%08X\n",
828 pt, ulRet, res);
830 else {
831 success = res == S_OK && ulRet == exp;
832 ok(success, "pt= %d: Expected %d, got %d, ret=0x%08X\n",
833 pt, exp, ulRet, res);
839 static void test_ScCopyRelocProps(void)
841 static char szTestA[] = "Test";
842 char buffer[512], buffer2[512], *lppszA[1];
843 SPropValue pvProp, *lpResProp = (LPSPropValue)buffer;
844 ULONG ulCount;
845 SCODE sc;
847 pScCopyProps = (void*)GetProcAddress(hMapi32, "ScCopyProps@16");
848 pScRelocProps = (void*)GetProcAddress(hMapi32, "ScRelocProps@20");
850 if (!pScCopyProps || !pScRelocProps)
852 win_skip("SPropValue copy functions are not available\n");
853 return;
856 pvProp.ulPropTag = PROP_TAG(PT_MV_STRING8, 1u);
858 lppszA[0] = szTestA;
859 pvProp.Value.MVszA.cValues = 1;
860 pvProp.Value.MVszA.lppszA = lppszA;
861 ulCount = 0;
863 sc = pScCopyProps(1, &pvProp, buffer, &ulCount);
864 ok(sc == S_OK, "wrong ret %d\n", sc);
865 if(sc == S_OK)
867 ok(lpResProp->ulPropTag == pvProp.ulPropTag, "wrong tag %x\n",lpResProp->ulPropTag);
868 ok(lpResProp->Value.MVszA.cValues == 1, "wrong cValues %d\n", lpResProp->Value.MVszA.cValues);
869 ok(lpResProp->Value.MVszA.lppszA[0] == buffer + sizeof(SPropValue) + sizeof(char*),
870 "wrong lppszA[0] %p\n",lpResProp->Value.MVszA.lppszA[0]);
871 ok(ulCount == sizeof(SPropValue) + sizeof(char*) + 5, "wrong count %d\n", ulCount);
872 ok(!strcmp(lpResProp->Value.MVszA.lppszA[0], szTestA),
873 "wrong string '%s'\n", lpResProp->Value.MVszA.lppszA[0]);
876 memcpy(buffer2, buffer, sizeof(buffer));
878 /* Clear the data in the source buffer. Since pointers in the copied buffer
879 * refer to the source buffer, this proves that native always assumes that
880 * the copied buffers pointers are bad (needing to be relocated first).
882 memset(buffer, 0, sizeof(buffer));
883 ulCount = 0;
885 sc = pScRelocProps(1, (LPSPropValue)buffer2, buffer, buffer2, &ulCount);
886 lpResProp = (LPSPropValue)buffer2;
888 ok(sc == S_OK, "wrong ret %d\n", sc);
889 if(sc == S_OK)
891 ok(lpResProp->ulPropTag == pvProp.ulPropTag, "wrong tag %x\n",lpResProp->ulPropTag);
892 ok(lpResProp->Value.MVszA.cValues == 1, "wrong cValues %d\n", lpResProp->Value.MVszA.cValues);
893 ok(lpResProp->Value.MVszA.lppszA[0] == buffer2 + sizeof(SPropValue) + sizeof(char*),
894 "wrong lppszA[0] %p\n",lpResProp->Value.MVszA.lppszA[0]);
895 /* Native has a bug whereby it calculates the size correctly when copying
896 * but when relocating does not (presumably it uses UlPropSize() which
897 * ignores multivalue pointers). Wine returns the correct value.
899 ok(ulCount == sizeof(SPropValue) + sizeof(char*) + 5 || ulCount == sizeof(SPropValue) + 5,
900 "wrong count %d\n", ulCount);
901 ok(!strcmp(lpResProp->Value.MVszA.lppszA[0], szTestA),
902 "wrong string '%s'\n", lpResProp->Value.MVszA.lppszA[0]);
905 /* Native crashes with lpNew or lpOld set to NULL so skip testing this */
908 static void test_LpValFindProp(void)
910 SPropValue pvProp, *pRet;
911 ULONG i;
913 pLpValFindProp = (void*)GetProcAddress(hMapi32, "LpValFindProp@12");
915 if (!pLpValFindProp)
917 win_skip("LpValFindProp is not available\n");
918 return;
921 for (i = 0; i < sizeof(ptTypes)/sizeof(ptTypes[0]); i++)
923 pvProp.ulPropTag = PROP_TAG(ptTypes[i], 1u);
925 pRet = pLpValFindProp(PROP_TAG(ptTypes[i], 1u), 1u, &pvProp);
926 ok(pRet == &pvProp,
927 "LpValFindProp[%d]: Didn't find existing propery id/type\n",
928 ptTypes[i]);
930 pRet = pLpValFindProp(PROP_TAG(ptTypes[i], 0u), 1u, &pvProp);
931 ok(pRet == NULL, "LpValFindProp[%d]: Found nonexistent propery id\n",
932 ptTypes[i]);
934 pRet = pLpValFindProp(PROP_TAG(PT_NULL, 0u), 1u, &pvProp);
935 ok(pRet == NULL, "LpValFindProp[%d]: Found nonexistent propery id/type\n",
936 ptTypes[i]);
938 pRet = pLpValFindProp(PROP_TAG(PT_NULL, 1u), 1u, &pvProp);
939 ok(pRet == &pvProp,
940 "LpValFindProp[%d]: Didn't find existing propery id\n",
941 ptTypes[i]);
945 static void test_FBadRglpszA(void)
947 LPSTR lpStrs[4];
948 static CHAR szString[] = "A String";
949 BOOL bRet;
951 pFBadRglpszA = (void*)GetProcAddress(hMapi32, "FBadRglpszA@8");
952 if (!pFBadRglpszA)
954 win_skip("FBadRglpszA is not available\n");
955 return;
958 bRet = pFBadRglpszA(NULL, 10);
959 ok(bRet == TRUE, "FBadRglpszA(Null): expected TRUE, got FALSE\n");
961 lpStrs[0] = lpStrs[1] = lpStrs[2] = lpStrs[3] = NULL;
962 bRet = pFBadRglpszA(lpStrs, 4);
963 ok(bRet == TRUE, "FBadRglpszA(Nulls): expected TRUE, got FALSE\n");
965 lpStrs[0] = lpStrs[1] = lpStrs[2] = szString;
966 bRet = pFBadRglpszA(lpStrs, 3);
967 ok(bRet == FALSE, "FBadRglpszA(valid): expected FALSE, got TRUE\n");
969 bRet = pFBadRglpszA(lpStrs, 4);
970 ok(bRet == TRUE, "FBadRglpszA(1 invalid): expected TRUE, got FALSE\n");
973 static void test_FBadRglpszW(void)
975 LPWSTR lpStrs[4];
976 static WCHAR szString[] = { 'A',' ','S','t','r','i','n','g','\0' };
977 BOOL bRet;
979 pFBadRglpszW = (void*)GetProcAddress(hMapi32, "FBadRglpszW@8");
980 if (!pFBadRglpszW)
982 win_skip("FBadRglpszW is not available\n");
983 return;
986 bRet = pFBadRglpszW(NULL, 10);
987 ok(bRet == TRUE, "FBadRglpszW(Null): expected TRUE, got FALSE\n");
989 lpStrs[0] = lpStrs[1] = lpStrs[2] = lpStrs[3] = NULL;
990 bRet = pFBadRglpszW(lpStrs, 4);
991 ok(bRet == TRUE, "FBadRglpszW(Nulls): expected TRUE, got FALSE\n");
993 lpStrs[0] = lpStrs[1] = lpStrs[2] = szString;
994 bRet = pFBadRglpszW(lpStrs, 3);
995 ok(bRet == FALSE, "FBadRglpszW(valid): expected FALSE, got TRUE\n");
997 bRet = pFBadRglpszW(lpStrs, 4);
998 ok(bRet == TRUE, "FBadRglpszW(1 invalid): expected TRUE, got FALSE\n");
1001 static void test_FBadRowSet(void)
1003 ULONG ulRet;
1005 pFBadRowSet = (void*)GetProcAddress(hMapi32, "FBadRowSet@4");
1006 if (!pFBadRowSet)
1008 win_skip("FBadRowSet is not available\n");
1009 return;
1012 ulRet = pFBadRowSet(NULL);
1013 ok(ulRet != 0, "FBadRow(null): Expected non-zero, got 0\n");
1015 /* FIXME */
1018 static void test_FBadPropTag(void)
1020 ULONG pt, res;
1022 pFBadPropTag = (void*)GetProcAddress(hMapi32, "FBadPropTag@4");
1023 if (!pFBadPropTag)
1025 win_skip("FBadPropTag is not available\n");
1026 return;
1029 for (pt = 0; pt < PROP_ID_INVALID; pt++)
1031 BOOL bBad = TRUE;
1033 switch (pt & (~MV_FLAG & PROP_TYPE_MASK))
1035 case PT_UNSPECIFIED:
1036 case PT_NULL: case PT_I2: case PT_I4: case PT_R4:
1037 case PT_R8: case PT_CURRENCY: case PT_APPTIME:
1038 case PT_ERROR: case PT_BOOLEAN: case PT_OBJECT:
1039 case PT_I8: case PT_STRING8: case PT_UNICODE:
1040 case PT_SYSTIME: case PT_CLSID: case PT_BINARY:
1041 bBad = FALSE;
1044 res = pFBadPropTag(pt);
1045 if (bBad)
1046 ok(res != 0, "pt= %d: Expected non-zero, got 0\n", pt);
1047 else
1048 ok(res == 0,
1049 "pt= %d: Expected zero, got %d\n", pt, res);
1053 static void test_FBadRow(void)
1055 ULONG ulRet;
1057 pFBadRow = (void*)GetProcAddress(hMapi32, "FBadRow@4");
1058 if (!pFBadRow)
1060 win_skip("FBadRow is not available\n");
1061 return;
1064 ulRet = pFBadRow(NULL);
1065 ok(ulRet != 0, "FBadRow(null): Expected non-zero, got 0\n");
1067 /* FIXME */
1070 static void test_FBadProp(void)
1072 static WCHAR szEmpty[] = { '\0' };
1073 GUID iid;
1074 ULONG pt, res;
1075 SPropValue pv;
1077 pFBadProp = (void*)GetProcAddress(hMapi32, "FBadProp@4");
1078 if (!pFBadProp)
1080 win_skip("FBadProp is not available\n");
1081 return;
1084 for (pt = 0; pt < PROP_ID_INVALID; pt++)
1086 BOOL bBad = TRUE;
1088 memset(&pv, 0, sizeof(pv));
1089 pv.ulPropTag = pt;
1091 /* Note that MV values are valid below because their array count is 0,
1092 * so no pointers are validated.
1094 switch (PROP_TYPE(pt))
1096 case (MV_FLAG|PT_UNSPECIFIED):
1097 case PT_UNSPECIFIED:
1098 case (MV_FLAG|PT_NULL):
1099 case PT_NULL:
1100 case PT_MV_I2:
1101 case PT_I2:
1102 case PT_MV_I4:
1103 case PT_I4:
1104 case PT_MV_I8:
1105 case PT_I8:
1106 case PT_MV_R4:
1107 case PT_R4:
1108 case PT_MV_R8:
1109 case PT_R8:
1110 case PT_MV_CURRENCY:
1111 case PT_CURRENCY:
1112 case PT_MV_APPTIME:
1113 case PT_APPTIME:
1114 case (MV_FLAG|PT_ERROR):
1115 case PT_ERROR:
1116 case (MV_FLAG|PT_BOOLEAN):
1117 case PT_BOOLEAN:
1118 case (MV_FLAG|PT_OBJECT):
1119 case PT_OBJECT:
1120 case PT_MV_STRING8:
1121 case PT_MV_UNICODE:
1122 case PT_MV_SYSTIME:
1123 case PT_SYSTIME:
1124 case PT_MV_BINARY:
1125 case PT_BINARY:
1126 case PT_MV_CLSID:
1127 bBad = FALSE;
1128 break;
1129 case PT_STRING8:
1130 case PT_UNICODE:
1131 pv.Value.lpszW = szEmpty;
1132 bBad = FALSE;
1133 break;
1134 case PT_CLSID:
1135 pv.Value.lpguid = &iid;
1136 bBad = FALSE;
1137 break;
1140 res = pFBadProp(&pv);
1141 if (bBad)
1142 ok(res != 0, "pt= %d: Expected non-zero, got 0\n", pt);
1143 else
1144 ok(res == 0,
1145 "pt= %d: Expected zero, got %d\n", pt, res);
1149 static void test_FBadColumnSet(void)
1151 SPropTagArray pta;
1152 ULONG pt, res;
1154 pFBadColumnSet = (void*)GetProcAddress(hMapi32, "FBadColumnSet@4");
1155 if (!pFBadColumnSet)
1157 win_skip("FBadColumnSet is not available\n");
1158 return;
1161 res = pFBadColumnSet(NULL);
1162 ok(res != 0, "(null): Expected non-zero, got 0\n");
1164 pta.cValues = 1;
1166 for (pt = 0; pt < PROP_ID_INVALID; pt++)
1168 BOOL bBad = TRUE;
1170 pta.aulPropTag[0] = pt;
1172 switch (pt & (~MV_FLAG & PROP_TYPE_MASK))
1174 case PT_UNSPECIFIED:
1175 case PT_NULL:
1176 case PT_I2:
1177 case PT_I4:
1178 case PT_R4:
1179 case PT_R8:
1180 case PT_CURRENCY:
1181 case PT_APPTIME:
1182 case PT_BOOLEAN:
1183 case PT_OBJECT:
1184 case PT_I8:
1185 case PT_STRING8:
1186 case PT_UNICODE:
1187 case PT_SYSTIME:
1188 case PT_CLSID:
1189 case PT_BINARY:
1190 bBad = FALSE;
1192 if (pt == (MV_FLAG|PT_ERROR))
1193 bBad = FALSE;
1195 res = pFBadColumnSet(&pta);
1196 if (bBad)
1197 ok(res != 0, "pt= %d: Expected non-zero, got 0\n", pt);
1198 else
1199 ok(res == 0,
1200 "pt= %d: Expected zero, got %d\n", pt, res);
1205 static void test_IProp(void)
1207 IPropData *lpIProp;
1208 LPMAPIERROR lpError;
1209 LPSPropProblemArray lpProbs;
1210 LPSPropValue lpProps;
1211 LPSPropTagArray lpTags;
1212 SPropValue pvs[2];
1213 SizedSPropTagArray(2,tags);
1214 ULONG access[2], count;
1215 SCODE sc;
1217 pCreateIProp = (void*)GetProcAddress(hMapi32, "CreateIProp@24");
1219 if (!pCreateIProp)
1221 win_skip("CreateIProp is not available\n");
1222 return;
1225 memset(&tags, 0 , sizeof(tags));
1227 /* Create the object */
1228 lpIProp = NULL;
1229 sc = pCreateIProp(&IID_IMAPIPropData, (ALLOCATEBUFFER *)pMAPIAllocateBuffer, (ALLOCATEMORE*)pMAPIAllocateMore,
1230 (FREEBUFFER *)pMAPIFreeBuffer, NULL, &lpIProp);
1231 ok(sc == S_OK && lpIProp,
1232 "CreateIProp: expected S_OK, non-null, got 0x%08X,%p\n", sc, lpIProp);
1234 if (sc != S_OK || !lpIProp)
1235 return;
1237 /* GetLastError - No errors set */
1238 lpError = NULL;
1239 IPropData_GetLastError(lpIProp, E_INVALIDARG, 0, &lpError);
1240 ok(sc == S_OK && !lpError,
1241 "GetLastError: Expected S_OK, null, got 0x%08X,%p\n", sc, lpError);
1243 /* Get prop tags - succeeds returning 0 items */
1244 lpTags = NULL;
1245 sc = IPropData_GetPropList(lpIProp, 0, &lpTags);
1246 ok(sc == S_OK && lpTags && lpTags->cValues == 0,
1247 "GetPropList(empty): Expected S_OK, non-null, 0, got 0x%08X,%p,%d\n",
1248 sc, lpTags, lpTags ? lpTags->cValues : 0);
1249 if (lpTags)
1250 pMAPIFreeBuffer(lpTags);
1252 /* Get props - succeeds returning 0 items */
1253 lpProps = NULL;
1254 count = 0;
1255 tags.cValues = 1;
1256 tags.aulPropTag[0] = PR_IMPORTANCE;
1257 sc = IPropData_GetProps(lpIProp, (LPSPropTagArray)&tags, 0, &count, &lpProps);
1258 ok(sc == MAPI_W_ERRORS_RETURNED && lpProps && count == 1,
1259 "GetProps(empty): Expected ERRORS_RETURNED, non-null, 1, got 0x%08X,%p,%d\n",
1260 sc, lpProps, count);
1261 if (lpProps && count > 0)
1263 ok(lpProps[0].ulPropTag == CHANGE_PROP_TYPE(PR_IMPORTANCE,PT_ERROR),
1264 "GetProps(empty): Expected %x, got %x\n",
1265 CHANGE_PROP_TYPE(PR_IMPORTANCE,PT_ERROR), lpProps[0].ulPropTag);
1267 pMAPIFreeBuffer(lpProps);
1270 /* Add (NULL) - Can't add NULLs */
1271 lpProbs = NULL;
1272 pvs[0].ulPropTag = PROP_TAG(PT_NULL,0x01);
1273 sc = IPropData_SetProps(lpIProp, 1, pvs, &lpProbs);
1274 ok(sc == MAPI_E_INVALID_PARAMETER && !lpProbs,
1275 "SetProps(): Expected INVALID_PARAMETER, null, got 0x%08X,%p\n",
1276 sc, lpProbs);
1278 /* Add (OBJECT) - Can't add OBJECTs */
1279 lpProbs = NULL;
1280 pvs[0].ulPropTag = PROP_TAG(PT_OBJECT,0x01);
1281 sc = IPropData_SetProps(lpIProp, 1, pvs, &lpProbs);
1282 ok(sc == MAPI_E_INVALID_PARAMETER && !lpProbs,
1283 "SetProps(OBJECT): Expected INVALID_PARAMETER, null, got 0x%08X,%p\n",
1284 sc, lpProbs);
1286 /* Add - Adds value */
1287 lpProbs = NULL;
1288 pvs[0].ulPropTag = PR_IMPORTANCE;
1289 sc = IPropData_SetProps(lpIProp, 1, pvs, &lpProbs);
1290 ok(sc == S_OK && !lpProbs,
1291 "SetProps(ERROR): Expected S_OK, null, got 0x%08X,%p\n", sc, lpProbs);
1293 /* Get prop list - returns 1 item */
1294 lpTags = NULL;
1295 IPropData_GetPropList(lpIProp, 0, &lpTags);
1296 ok(sc == S_OK && lpTags && lpTags->cValues == 1,
1297 "GetPropList: Expected S_OK, non-null, 1, got 0x%08X,%p,%d\n",
1298 sc, lpTags, lpTags ? lpTags->cValues : 0);
1299 if (lpTags && lpTags->cValues > 0)
1301 ok(lpTags->aulPropTag[0] == PR_IMPORTANCE,
1302 "GetPropList: Expected %x, got %x\n",
1303 PR_IMPORTANCE, lpTags->aulPropTag[0]);
1304 pMAPIFreeBuffer(lpTags);
1307 /* Set access to read and write */
1308 sc = IPropData_HrSetObjAccess(lpIProp, IPROP_READWRITE);
1309 ok(sc == S_OK, "SetObjAcess(WRITE): Expected S_OK got 0x%08X\n", sc);
1311 tags.cValues = 1;
1312 tags.aulPropTag[0] = PR_IMPORTANCE;
1314 /* Set item access (bad access) - Fails */
1315 access[0] = 0;
1316 sc = IPropData_HrSetPropAccess(lpIProp, (LPSPropTagArray)&tags, access);
1317 ok(sc == MAPI_E_INVALID_PARAMETER,
1318 "SetPropAcess(0): Expected INVALID_PARAMETER got 0x%08X\n",sc);
1319 access[0] = IPROP_READWRITE;
1320 sc = IPropData_HrSetPropAccess(lpIProp, (LPSPropTagArray)&tags, access);
1321 ok(sc == MAPI_E_INVALID_PARAMETER,
1322 "SetPropAcess(RW): Expected INVALID_PARAMETER got 0x%08X\n",sc);
1323 access[0] = IPROP_CLEAN;
1324 sc = IPropData_HrSetPropAccess(lpIProp, (LPSPropTagArray)&tags, access);
1325 ok(sc == MAPI_E_INVALID_PARAMETER,
1326 "SetPropAcess(C): Expected INVALID_PARAMETER got 0x%08X\n",sc);
1328 /* Set item access to read/write/clean */
1329 tags.cValues = 1;
1330 tags.aulPropTag[0] = PR_IMPORTANCE;
1331 access[0] = IPROP_READWRITE|IPROP_CLEAN;
1332 sc = IPropData_HrSetPropAccess(lpIProp, (LPSPropTagArray)&tags, access);
1333 ok(sc == S_OK, "SetPropAcess(RW/C): Expected S_OK got 0x%08X\n",sc);
1335 /* Set object access to read only */
1336 sc = IPropData_HrSetObjAccess(lpIProp, IPROP_READONLY);
1337 ok(sc == S_OK, "SetObjAcess(READ): Expected S_OK got 0x%08X\n", sc);
1339 /* Set item access to read/write/dirty - doesn't care about RO object */
1340 access[0] = IPROP_READONLY|IPROP_DIRTY;
1341 sc = IPropData_HrSetPropAccess(lpIProp, (LPSPropTagArray)&tags, access);
1342 ok(sc == S_OK, "SetPropAcess(WRITE): Expected S_OK got 0x%08X\n", sc);
1344 /* Delete any item when set to read only - Error */
1345 lpProbs = NULL;
1346 tags.aulPropTag[0] = PR_RESPONSE_REQUESTED;
1347 sc = IPropData_DeleteProps(lpIProp, (LPSPropTagArray)&tags, &lpProbs);
1348 ok(sc == E_ACCESSDENIED && !lpProbs,
1349 "DeleteProps(nonexistent): Expected E_ACCESSDENIED null got 0x%08X %p\n",
1350 sc, lpProbs);
1352 /* Set access to read and write */
1353 sc = IPropData_HrSetObjAccess(lpIProp, IPROP_READWRITE);
1354 ok(sc == S_OK, "SetObjAcess(WRITE): Expected S_OK got 0x%08X\n", sc);
1356 /* Delete nonexistent item - No error */
1357 lpProbs = NULL;
1358 tags.aulPropTag[0] = PR_RESPONSE_REQUESTED;
1359 sc = IPropData_DeleteProps(lpIProp, (LPSPropTagArray)&tags, &lpProbs);
1360 ok(sc == S_OK && !lpProbs,
1361 "DeleteProps(nonexistent): Expected S_OK null got 0x%08X %p\n",
1362 sc, lpProbs);
1364 /* Delete existing item (r/o) - No error, but lpProbs populated */
1365 lpProbs = NULL;
1366 tags.aulPropTag[0] = PR_IMPORTANCE;
1367 sc = IPropData_DeleteProps(lpIProp, (LPSPropTagArray)&tags, &lpProbs);
1368 ok(sc == S_OK && lpProbs,
1369 "DeleteProps(RO): Expected S_OK non-null got 0x%08X %p\n", sc, lpProbs);
1371 if (lpProbs && lpProbs->cProblem > 0)
1373 ok(lpProbs->cProblem == 1 &&
1374 lpProbs->aProblem[0].ulIndex == 0 &&
1375 lpProbs->aProblem[0].ulPropTag == PR_IMPORTANCE &&
1376 lpProbs->aProblem[0].scode == E_ACCESSDENIED,
1377 "DeleteProps(RO): Expected (1,0,%x,%x) got (%d,%x,%x)\n",
1378 PR_IMPORTANCE, E_ACCESSDENIED,
1379 lpProbs->aProblem[0].ulIndex, lpProbs->aProblem[0].ulPropTag,
1380 lpProbs->aProblem[0].scode);
1381 pMAPIFreeBuffer(lpProbs);
1384 lpProbs = NULL;
1385 tags.cValues = 1;
1386 tags.aulPropTag[0] = PR_RESPONSE_REQUESTED;
1387 IPropData_HrAddObjProps(lpIProp, (LPSPropTagArray)&tags, &lpProbs);
1388 ok(sc == S_OK && !lpProbs,
1389 "AddObjProps(RO): Expected S_OK null got 0x%08X %p\n", sc, lpProbs);
1391 /* Get prop list - returns 1 item */
1392 lpTags = NULL;
1393 IPropData_GetPropList(lpIProp, 0, &lpTags);
1394 ok(sc == S_OK && lpTags && lpTags->cValues == 1,
1395 "GetPropList: Expected S_OK, non-null, 1, got 0x%08X,%p,%d\n",
1396 sc, lpTags, lpTags ? lpTags->cValues : 0);
1397 if (lpTags && lpTags->cValues > 0)
1399 ok(lpTags->aulPropTag[0] == PR_IMPORTANCE,
1400 "GetPropList: Expected %x, got %x\n",
1401 PR_IMPORTANCE, lpTags->aulPropTag[0]);
1402 pMAPIFreeBuffer(lpTags);
1405 /* Set item to r/w again */
1406 access[0] = IPROP_READWRITE|IPROP_DIRTY;
1407 sc = IPropData_HrSetPropAccess(lpIProp, (LPSPropTagArray)&tags, access);
1408 ok(sc == S_OK, "SetPropAcess(WRITE): Expected S_OK got 0x%08X\n", sc);
1410 /* Delete existing item (r/w) - No error, no problems */
1411 lpProbs = NULL;
1412 sc = IPropData_DeleteProps(lpIProp, (LPSPropTagArray)&tags, &lpProbs);
1413 ok(sc == S_OK && !lpProbs,
1414 "DeleteProps(RO): Expected S_OK null got 0x%08X %p\n", sc, lpProbs);
1416 /* Free the list */
1417 IPropData_Release(lpIProp);
1420 START_TEST(prop)
1422 SCODE ret;
1424 if (!HaveDefaultMailClient())
1426 win_skip("No default mail client installed\n");
1427 return;
1430 if(!InitFuncPtrs())
1432 win_skip("Needed functions are not available\n");
1433 return;
1436 SetLastError(0xdeadbeef);
1437 ret = pScInitMapiUtil(0);
1438 if ((ret != S_OK) && (GetLastError() == ERROR_PROC_NOT_FOUND))
1440 win_skip("ScInitMapiUtil is not implemented\n");
1441 FreeLibrary(hMapi32);
1442 return;
1444 else if ((ret == E_FAIL) && (GetLastError() == ERROR_INVALID_HANDLE))
1446 win_skip("ScInitMapiUtil doesn't work on some Win98 and WinME systems\n");
1447 FreeLibrary(hMapi32);
1448 return;
1451 test_PropCopyMore();
1452 test_UlPropSize();
1453 test_FPropContainsProp();
1454 test_FPropCompareProp();
1455 test_LPropCompareProp();
1456 test_PpropFindProp();
1457 test_ScCountProps();
1458 test_ScCopyRelocProps();
1459 test_LpValFindProp();
1460 test_FBadRglpszA();
1461 test_FBadRglpszW();
1462 test_FBadRowSet();
1463 test_FBadPropTag();
1464 test_FBadRow();
1465 test_FBadProp();
1466 test_FBadColumnSet();
1468 test_IProp();
1469 FreeLibrary(hMapi32);