mapi32/tests: Centralize property function pointer initialization.
[wine/multimedia.git] / dlls / mapi32 / tests / prop.c
blob8c642453d4b713a643610513054bf30f8d274d5d
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 pPropCopyMore = (void*)GetProcAddress(hMapi32, "PropCopyMore@16");
63 pUlPropSize = (void*)GetProcAddress(hMapi32, "UlPropSize@4");
64 pFPropContainsProp = (void*)GetProcAddress(hMapi32, "FPropContainsProp@12");
65 pFPropCompareProp = (void*)GetProcAddress(hMapi32, "FPropCompareProp@12");
66 pLPropCompareProp = (void*)GetProcAddress(hMapi32, "LPropCompareProp@8");
67 pPpropFindProp = (void*)GetProcAddress(hMapi32, "PpropFindProp@12");
68 pScCountProps = (void*)GetProcAddress(hMapi32, "ScCountProps@12");
69 pScCopyProps = (void*)GetProcAddress(hMapi32, "ScCopyProps@16");
70 pScRelocProps = (void*)GetProcAddress(hMapi32, "ScRelocProps@20");
71 pLpValFindProp = (void*)GetProcAddress(hMapi32, "LpValFindProp@12");
72 pFBadRglpszA = (void*)GetProcAddress(hMapi32, "FBadRglpszA@8");
73 pFBadRglpszW = (void*)GetProcAddress(hMapi32, "FBadRglpszW@8");
74 pFBadRowSet = (void*)GetProcAddress(hMapi32, "FBadRowSet@4");
75 pFBadPropTag = (void*)GetProcAddress(hMapi32, "FBadPropTag@4");
76 pFBadRow = (void*)GetProcAddress(hMapi32, "FBadRow@4");
77 pFBadProp = (void*)GetProcAddress(hMapi32, "FBadProp@4");
78 pFBadColumnSet = (void*)GetProcAddress(hMapi32, "FBadColumnSet@4");
79 pCreateIProp = (void*)GetProcAddress(hMapi32, "CreateIProp@24");
81 pScInitMapiUtil = (void*)GetProcAddress(hMapi32, "ScInitMapiUtil@4");
82 pMAPIAllocateBuffer = (void*)GetProcAddress(hMapi32, "MAPIAllocateBuffer");
83 pMAPIAllocateMore = (void*)GetProcAddress(hMapi32, "MAPIAllocateMore");
84 pMAPIFreeBuffer = (void*)GetProcAddress(hMapi32, "MAPIFreeBuffer");
85 if(pScInitMapiUtil && pMAPIAllocateBuffer && pMAPIAllocateMore && pMAPIFreeBuffer)
86 return TRUE;
87 else
88 return FALSE;
91 /* FIXME: Test PT_I2, PT_I4, PT_R4, PT_R8, PT_CURRENCY, PT_APPTIME, PT_SYSTIME,
92 * PT_ERROR, PT_BOOLEAN, PT_I8, and PT_CLSID. */
93 static ULONG ptTypes[] = {
94 PT_STRING8, PT_BINARY, PT_UNICODE
97 static inline int strcmpW(const WCHAR *str1, const WCHAR *str2)
99 while (*str1 && (*str1 == *str2)) { str1++; str2++; }
100 return *str1 - *str2;
103 static void test_PropCopyMore(void)
105 static char szHiA[] = "Hi!";
106 static WCHAR szHiW[] = { 'H', 'i', '!', '\0' };
107 SPropValue *lpDest = NULL, *lpSrc = NULL;
108 ULONG i;
109 SCODE scode;
111 if (!pPropCopyMore)
113 win_skip("PropCopyMore is not available\n");
114 return;
117 scode = pMAPIAllocateBuffer(sizeof(SPropValue), &lpDest);
118 ok(scode == S_OK, "Expected MAPIAllocateBuffer to return S_OK, got 0x%x\n", scode);
119 if (FAILED(scode))
121 skip("MAPIAllocateBuffer failed\n");
122 return;
125 scode = pMAPIAllocateMore(sizeof(SPropValue), lpDest, &lpSrc);
126 ok(scode == S_OK, "Expected MAPIAllocateMore to return S_OK, got 0x%x\n", scode);
127 if (FAILED(scode))
129 skip("MAPIAllocateMore failed\n");
130 return;
133 for (i = 0; i < sizeof(ptTypes)/sizeof(ptTypes[0]); i++)
135 lpSrc->ulPropTag = ptTypes[i];
137 switch (ptTypes[i])
139 case PT_STRING8:
140 lpSrc->Value.lpszA = szHiA;
141 break;
142 case PT_UNICODE:
143 lpSrc->Value.lpszW = szHiW;
144 break;
145 case PT_BINARY:
146 lpSrc->Value.bin.cb = 4;
147 lpSrc->Value.bin.lpb = (LPBYTE)szHiA;
148 break;
151 memset(lpDest, 0xff, sizeof(SPropValue));
153 scode = pPropCopyMore(lpDest, lpSrc, (ALLOCATEMORE*)pMAPIAllocateMore, lpDest);
154 ok(!scode && lpDest->ulPropTag == lpSrc->ulPropTag,
155 "PropCopyMore: Expected 0x0,%d, got 0x%08x,%d\n",
156 lpSrc->ulPropTag, scode, lpDest->ulPropTag);
157 if (SUCCEEDED(scode))
159 switch (ptTypes[i])
161 case PT_STRING8:
162 ok(lstrcmpA(lpDest->Value.lpszA, lpSrc->Value.lpszA) == 0,
163 "PropCopyMore: Ascii string differs\n");
164 break;
165 case PT_UNICODE:
166 ok(strcmpW(lpDest->Value.lpszW, lpSrc->Value.lpszW) == 0,
167 "PropCopyMore: Unicode string differs\n");
168 break;
169 case PT_BINARY:
170 ok(lpDest->Value.bin.cb == 4 &&
171 !memcmp(lpSrc->Value.bin.lpb, lpDest->Value.bin.lpb, 4),
172 "PropCopyMore: Binary array differs\n");
173 break;
178 /* Since all allocations are linked, freeing lpDest frees everything */
179 scode = pMAPIFreeBuffer(lpDest);
180 ok(scode == S_OK, "Expected MAPIFreeBuffer to return S_OK, got 0x%x\n", scode);
183 static void test_UlPropSize(void)
185 static char szHiA[] = "Hi!";
186 static WCHAR szHiW[] = { 'H', 'i', '!', '\0' };
187 LPSTR buffa[2];
188 LPWSTR buffw[2];
189 SBinary buffbin[2];
190 ULONG pt, exp, res;
192 if (!pUlPropSize)
194 win_skip("UlPropSize is not available\n");
195 return;
198 for (pt = 0; pt < PROP_ID_INVALID; pt++)
200 SPropValue pv;
202 memset(&pv, 0 ,sizeof(pv));
203 pv.ulPropTag = pt;
205 exp = 1u; /* Default to one item for non-MV properties */
207 switch (PROP_TYPE(pt))
209 case PT_MV_I2: pv.Value.MVi.cValues = exp = 2;
210 case PT_I2: exp *= sizeof(USHORT); break;
211 case PT_MV_I4: pv.Value.MVl.cValues = exp = 2;
212 case PT_I4: exp *= sizeof(LONG); break;
213 case PT_MV_R4: pv.Value.MVflt.cValues = exp = 2;
214 case PT_R4: exp *= sizeof(float); break;
215 case PT_MV_DOUBLE: pv.Value.MVdbl.cValues = exp = 2;
216 case PT_R8: exp *= sizeof(double); break;
217 case PT_MV_CURRENCY: pv.Value.MVcur.cValues = exp = 2;
218 case PT_CURRENCY: exp *= sizeof(CY); break;
219 case PT_MV_APPTIME: pv.Value.MVat.cValues = exp = 2;
220 case PT_APPTIME: exp *= sizeof(double); break;
221 case PT_MV_SYSTIME: pv.Value.MVft.cValues = exp = 2;
222 case PT_SYSTIME: exp *= sizeof(FILETIME); break;
223 case PT_ERROR: exp = sizeof(SCODE); break;
224 case PT_BOOLEAN: exp = sizeof(USHORT); break;
225 case PT_OBJECT: exp = 0; break;
226 case PT_MV_I8: pv.Value.MVli.cValues = exp = 2;
227 case PT_I8: exp *= sizeof(LONG64); break;
228 #if 0
229 /* My version of native mapi returns 0 for PT_MV_CLSID even if a valid
230 * array is given. This _has_ to be a bug, so Wine does
231 * the right thing(tm) and we don't test it here.
233 case PT_MV_CLSID: pv.Value.MVguid.cValues = exp = 2;
234 #endif
235 case PT_CLSID: exp *= sizeof(GUID); break;
236 case PT_STRING8:
237 pv.Value.lpszA = szHiA;
238 exp = 4;
239 break;
240 case PT_UNICODE:
241 pv.Value.lpszW = szHiW;
242 exp = 4 * sizeof(WCHAR);
243 break;
244 case PT_BINARY:
245 pv.Value.bin.cb = exp = 19;
246 break;
247 case PT_MV_STRING8:
248 pv.Value.MVszA.cValues = 2;
249 pv.Value.MVszA.lppszA = buffa;
250 buffa[0] = szHiA;
251 buffa[1] = szHiA;
252 exp = 8;
253 break;
254 case PT_MV_UNICODE:
255 pv.Value.MVszW.cValues = 2;
256 pv.Value.MVszW.lppszW = buffw;
257 buffw[0] = szHiW;
258 buffw[1] = szHiW;
259 exp = 8 * sizeof(WCHAR);
260 break;
261 case PT_MV_BINARY:
262 pv.Value.MVbin.cValues = 2;
263 pv.Value.MVbin.lpbin = buffbin;
264 buffbin[0].cb = 19;
265 buffbin[1].cb = 1;
266 exp = 20;
267 break;
268 default:
269 exp = 0;
272 res = pUlPropSize(&pv);
273 ok(res == exp,
274 "pt= %d: Expected %d, got %d\n", pt, exp, res);
278 static void test_FPropContainsProp(void)
280 static char szFull[] = "Full String";
281 static char szFullLower[] = "full string";
282 static char szPrefix[] = "Full";
283 static char szPrefixLower[] = "full";
284 static char szSubstring[] = "ll St";
285 static char szSubstringLower[] = "ll st";
286 SPropValue pvLeft, pvRight;
287 ULONG pt;
288 BOOL bRet;
290 if (!pFPropContainsProp)
292 win_skip("FPropContainsProp is not available\n");
293 return;
296 /* Ensure that only PT_STRING8 and PT_BINARY are handled */
297 for (pt = 0; pt < PROP_ID_INVALID; pt++)
299 if (pt == PT_STRING8 || pt == PT_BINARY)
300 continue; /* test these later */
302 memset(&pvLeft, 0 ,sizeof(pvLeft));
303 memset(&pvRight, 0 ,sizeof(pvRight));
304 pvLeft.ulPropTag = pvRight.ulPropTag = pt;
306 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
307 ok(bRet == FALSE, "pt= %d: Expected FALSE, got %d\n", pt, bRet);
310 /* test the various flag combinations */
311 pvLeft.ulPropTag = pvRight.ulPropTag = PT_STRING8;
312 pvLeft.Value.lpszA = szFull;
313 pvRight.Value.lpszA = szFull;
315 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
316 ok(bRet == TRUE, "(full,full)[] match failed\n");
317 pvRight.Value.lpszA = szPrefix;
318 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
319 ok(bRet == FALSE, "(full,prefix)[] match failed\n");
320 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
321 ok(bRet == TRUE, "(full,prefix)[PREFIX] match failed\n");
322 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
323 ok(bRet == TRUE, "(full,prefix)[SUBSTRING] match failed\n");
324 pvRight.Value.lpszA = szPrefixLower;
325 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
326 ok(bRet == FALSE, "(full,prefixlow)[PREFIX] match failed\n");
327 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
328 ok(bRet == FALSE, "(full,prefixlow)[SUBSTRING] match failed\n");
329 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX|FL_IGNORECASE);
330 ok(bRet == TRUE, "(full,prefixlow)[PREFIX|IGNORECASE] match failed\n");
331 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING|FL_IGNORECASE);
332 ok(bRet == TRUE, "(full,prefixlow)[SUBSTRING|IGNORECASE] match failed\n");
333 pvRight.Value.lpszA = szSubstring;
334 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
335 ok(bRet == FALSE, "(full,substr)[] match failed\n");
336 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
337 ok(bRet == FALSE, "(full,substr)[PREFIX] match failed\n");
338 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
339 ok(bRet == TRUE, "(full,substr)[SUBSTRING] match failed\n");
340 pvRight.Value.lpszA = szSubstringLower;
341 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
342 ok(bRet == FALSE, "(full,substrlow)[PREFIX] match failed\n");
343 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
344 ok(bRet == FALSE, "(full,substrlow)[SUBSTRING] match failed\n");
345 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX|FL_IGNORECASE);
346 ok(bRet == FALSE, "(full,substrlow)[PREFIX|IGNORECASE] match failed\n");
347 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING|FL_IGNORECASE);
348 ok(bRet == TRUE, "(full,substrlow)[SUBSTRING|IGNORECASE] match failed\n");
349 pvRight.Value.lpszA = szFullLower;
350 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING|FL_IGNORECASE);
351 ok(bRet == TRUE, "(full,fulllow)[IGNORECASE] match failed\n");
353 pvLeft.ulPropTag = pvRight.ulPropTag = PT_BINARY;
354 pvLeft.Value.bin.lpb = (LPBYTE)szFull;
355 pvRight.Value.bin.lpb = (LPBYTE)szFull;
356 pvLeft.Value.bin.cb = pvRight.Value.bin.cb = strlen(szFull);
358 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
359 ok(bRet == TRUE, "bin(full,full)[] match failed\n");
360 pvRight.Value.bin.lpb = (LPBYTE)szPrefix;
361 pvRight.Value.bin.cb = strlen(szPrefix);
362 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
363 ok(bRet == FALSE, "bin(full,prefix)[] match failed\n");
364 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
365 ok(bRet == TRUE, "bin(full,prefix)[PREFIX] match failed\n");
366 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
367 ok(bRet == TRUE, "bin(full,prefix)[SUBSTRING] match failed\n");
368 pvRight.Value.bin.lpb = (LPBYTE)szPrefixLower;
369 pvRight.Value.bin.cb = strlen(szPrefixLower);
370 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
371 ok(bRet == FALSE, "bin(full,prefixlow)[PREFIX] match failed\n");
372 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
373 ok(bRet == FALSE, "bin(full,prefixlow)[SUBSTRING] match failed\n");
374 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX|FL_IGNORECASE);
375 ok(bRet == FALSE, "bin(full,prefixlow)[PREFIX|IGNORECASE] match failed\n");
376 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING|FL_IGNORECASE);
377 ok(bRet == FALSE, "bin(full,prefixlow)[SUBSTRING|IGNORECASE] match failed\n");
378 pvRight.Value.bin.lpb = (LPBYTE)szSubstring;
379 pvRight.Value.bin.cb = strlen(szSubstring);
380 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
381 ok(bRet == FALSE, "bin(full,substr)[] match failed\n");
382 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
383 ok(bRet == FALSE, "bin(full,substr)[PREFIX] match failed\n");
384 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
385 ok(bRet == TRUE, "bin(full,substr)[SUBSTRING] match failed\n");
386 pvRight.Value.bin.lpb = (LPBYTE)szSubstringLower;
387 pvRight.Value.bin.cb = strlen(szSubstringLower);
388 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
389 ok(bRet == FALSE, "bin(full,substrlow)[PREFIX] match failed\n");
390 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
391 ok(bRet == FALSE, "bin(full,substrlow)[SUBSTRING] match failed\n");
392 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX|FL_IGNORECASE);
393 ok(bRet == FALSE, "bin(full,substrlow)[PREFIX|IGNORECASE] match failed\n");
394 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING|FL_IGNORECASE);
395 ok(bRet == FALSE, "bin(full,substrlow)[SUBSTRING|IGNORECASE] match failed\n");
396 pvRight.Value.bin.lpb = (LPBYTE)szFullLower;
397 pvRight.Value.bin.cb = strlen(szFullLower);
398 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING|FL_IGNORECASE);
399 ok(bRet == FALSE, "bin(full,fulllow)[IGNORECASE] match failed\n");
402 typedef struct tagFPropCompareProp_Result
404 SHORT lVal;
405 SHORT rVal;
406 ULONG relOp;
407 BOOL bRet;
408 } FPropCompareProp_Result;
410 static const FPropCompareProp_Result FPCProp_Results[] =
412 { 1, 2, RELOP_LT, TRUE },
413 { 1, 1, RELOP_LT, FALSE },
414 { 2, 1, RELOP_LT, FALSE },
415 { 1, 2, RELOP_LE, TRUE },
416 { 1, 1, RELOP_LE, TRUE },
417 { 2, 1, RELOP_LE, FALSE },
418 { 1, 2, RELOP_GT, FALSE },
419 { 1, 1, RELOP_GT, FALSE },
420 { 2, 1, RELOP_GT, TRUE },
421 { 1, 2, RELOP_GE, FALSE },
422 { 1, 1, RELOP_GE, TRUE },
423 { 2, 1, RELOP_GE, TRUE },
424 { 1, 2, RELOP_EQ, FALSE },
425 { 1, 1, RELOP_EQ, TRUE },
426 { 2, 1, RELOP_EQ, FALSE }
429 static const char *relops[] = { "RELOP_LT", "RELOP_LE", "RELOP_GT", "RELOP_GE", "RELOP_EQ" };
431 static void test_FPropCompareProp(void)
433 SPropValue pvLeft, pvRight;
434 GUID lguid, rguid;
435 char lbuffa[2], rbuffa[2];
436 WCHAR lbuffw[2], rbuffw[2];
437 ULONG i, j;
438 BOOL bRet, bExp;
440 if (!pFPropCompareProp)
442 win_skip("FPropCompareProp is not available\n");
443 return;
446 lbuffa[1] = '\0';
447 rbuffa[1] = '\0';
448 lbuffw[1] = '\0';
449 rbuffw[1] = '\0';
451 for (i = 0; i < sizeof(ptTypes)/sizeof(ptTypes[0]); i++)
453 pvLeft.ulPropTag = pvRight.ulPropTag = ptTypes[i];
455 for (j = 0; j < sizeof(FPCProp_Results)/sizeof(FPCProp_Results[0]); j++)
457 SHORT lVal = FPCProp_Results[j].lVal;
458 SHORT rVal = FPCProp_Results[j].rVal;
460 bExp = FPCProp_Results[j].bRet;
462 switch (ptTypes[i])
464 case PT_BOOLEAN:
465 /* Boolean values have no concept of less or greater than, only equality */
466 if ((lVal == 1 && rVal == 2 && FPCProp_Results[j].relOp == RELOP_LT) ||
467 (lVal == 2 && rVal == 1 && FPCProp_Results[j].relOp == RELOP_LE)||
468 (lVal == 2 && rVal == 1 && FPCProp_Results[j].relOp == RELOP_GT)||
469 (lVal == 1 && rVal == 2 && FPCProp_Results[j].relOp == RELOP_GE)||
470 (lVal == 1 && rVal == 2 && FPCProp_Results[j].relOp == RELOP_EQ)||
471 (lVal == 2 && rVal == 1 && FPCProp_Results[j].relOp == RELOP_EQ))
472 bExp = !bExp;
473 /* Fall through ... */
474 case PT_I2:
475 pvLeft.Value.i = lVal;
476 pvRight.Value.i = rVal;
477 break;
478 case PT_ERROR:
479 case PT_I4:
480 pvLeft.Value.l = lVal;
481 pvRight.Value.l = rVal;
482 break;
483 case PT_R4:
484 pvLeft.Value.flt = lVal;
485 pvRight.Value.flt = rVal;
486 break;
487 case PT_APPTIME:
488 case PT_R8:
489 pvLeft.Value.dbl = lVal;
490 pvRight.Value.dbl = rVal;
491 break;
492 case PT_CURRENCY:
493 pvLeft.Value.cur.int64 = lVal;
494 pvRight.Value.cur.int64 = rVal;
495 break;
496 case PT_SYSTIME:
497 pvLeft.Value.ft.dwLowDateTime = lVal;
498 pvLeft.Value.ft.dwHighDateTime = 0;
499 pvRight.Value.ft.dwLowDateTime = rVal;
500 pvRight.Value.ft.dwHighDateTime = 0;
501 break;
502 case PT_I8:
503 pvLeft.Value.li.u.LowPart = lVal;
504 pvLeft.Value.li.u.HighPart = 0;
505 pvRight.Value.li.u.LowPart = rVal;
506 pvRight.Value.li.u.HighPart = 0;
507 break;
508 case PT_CLSID:
509 memset(&lguid, 0, sizeof(GUID));
510 memset(&rguid, 0, sizeof(GUID));
511 lguid.Data4[7] = lVal;
512 rguid.Data4[7] = rVal;
513 pvLeft.Value.lpguid = &lguid;
514 pvRight.Value.lpguid = &rguid;
515 break;
516 case PT_STRING8:
517 pvLeft.Value.lpszA = lbuffa;
518 pvRight.Value.lpszA = rbuffa;
519 lbuffa[0] = '0' + lVal;
520 rbuffa[0] = '0' + rVal;
521 break;
522 case PT_UNICODE:
523 pvLeft.Value.lpszW = lbuffw;
524 pvRight.Value.lpszW = rbuffw;
525 lbuffw[0] = '0' + lVal;
526 rbuffw[0] = '0' + rVal;
527 break;
528 case PT_BINARY:
529 pvLeft.Value.bin.cb = 1;
530 pvRight.Value.bin.cb = 1;
531 pvLeft.Value.bin.lpb = (LPBYTE)lbuffa;
532 pvRight.Value.bin.lpb = (LPBYTE)rbuffa;
533 lbuffa[0] = lVal;
534 rbuffa[0] = rVal;
535 break;
538 bRet = pFPropCompareProp(&pvLeft, FPCProp_Results[j].relOp, &pvRight);
539 ok(bRet == bExp,
540 "pt %d (%d,%d,%s): expected %d, got %d\n", ptTypes[i],
541 FPCProp_Results[j].lVal, FPCProp_Results[j].rVal,
542 relops[FPCProp_Results[j].relOp], bExp, bRet);
547 typedef struct tagLPropCompareProp_Result
549 SHORT lVal;
550 SHORT rVal;
551 INT iRet;
552 } LPropCompareProp_Result;
554 static const LPropCompareProp_Result LPCProp_Results[] =
556 { 1, 2, -1 },
557 { 1, 1, 0 },
558 { 2, 1, 1 },
561 static void test_LPropCompareProp(void)
563 SPropValue pvLeft, pvRight;
564 GUID lguid, rguid;
565 char lbuffa[2], rbuffa[2];
566 WCHAR lbuffw[2], rbuffw[2];
567 ULONG i, j;
568 INT iRet, iExp;
570 if (!pLPropCompareProp)
572 win_skip("LPropCompareProp is not available\n");
573 return;
576 lbuffa[1] = '\0';
577 rbuffa[1] = '\0';
578 lbuffw[1] = '\0';
579 rbuffw[1] = '\0';
581 for (i = 0; i < sizeof(ptTypes)/sizeof(ptTypes[0]); i++)
583 pvLeft.ulPropTag = pvRight.ulPropTag = ptTypes[i];
585 for (j = 0; j < sizeof(LPCProp_Results)/sizeof(LPCProp_Results[0]); j++)
587 SHORT lVal = LPCProp_Results[j].lVal;
588 SHORT rVal = LPCProp_Results[j].rVal;
590 iExp = LPCProp_Results[j].iRet;
592 switch (ptTypes[i])
594 case PT_BOOLEAN:
595 /* Boolean values have no concept of less or greater than, only equality */
596 if (lVal && rVal)
597 iExp = 0;
598 /* Fall through ... */
599 case PT_I2:
600 pvLeft.Value.i = lVal;
601 pvRight.Value.i = rVal;
602 break;
603 case PT_ERROR:
604 case PT_I4:
605 pvLeft.Value.l = lVal;
606 pvRight.Value.l = rVal;
607 break;
608 case PT_R4:
609 pvLeft.Value.flt = lVal;
610 pvRight.Value.flt = rVal;
611 break;
612 case PT_APPTIME:
613 case PT_R8:
614 pvLeft.Value.dbl = lVal;
615 pvRight.Value.dbl = rVal;
616 break;
617 case PT_CURRENCY:
618 pvLeft.Value.cur.int64 = lVal;
619 pvRight.Value.cur.int64 = rVal;
620 break;
621 case PT_SYSTIME:
622 pvLeft.Value.ft.dwLowDateTime = lVal;
623 pvLeft.Value.ft.dwHighDateTime = 0;
624 pvRight.Value.ft.dwLowDateTime = rVal;
625 pvRight.Value.ft.dwHighDateTime = 0;
626 break;
627 case PT_I8:
628 pvLeft.Value.li.u.LowPart = lVal;
629 pvLeft.Value.li.u.HighPart = 0;
630 pvRight.Value.li.u.LowPart = rVal;
631 pvRight.Value.li.u.HighPart = 0;
632 break;
633 case PT_CLSID:
634 memset(&lguid, 0, sizeof(GUID));
635 memset(&rguid, 0, sizeof(GUID));
636 lguid.Data4[7] = lVal;
637 rguid.Data4[7] = rVal;
638 pvLeft.Value.lpguid = &lguid;
639 pvRight.Value.lpguid = &rguid;
640 break;
641 case PT_STRING8:
642 pvLeft.Value.lpszA = lbuffa;
643 pvRight.Value.lpszA = rbuffa;
644 lbuffa[0] = '0' + lVal;
645 rbuffa[0] = '0' + rVal;
646 break;
647 case PT_UNICODE:
648 pvLeft.Value.lpszW = lbuffw;
649 pvRight.Value.lpszW = rbuffw;
650 lbuffw[0] = '0' + lVal;
651 rbuffw[0] = '0' + rVal;
652 break;
653 case PT_BINARY:
654 pvLeft.Value.bin.cb = 1;
655 pvRight.Value.bin.cb = 1;
656 pvLeft.Value.bin.lpb = (LPBYTE)lbuffa;
657 pvRight.Value.bin.lpb = (LPBYTE)rbuffa;
658 lbuffa[0] = lVal;
659 rbuffa[0] = rVal;
660 break;
663 iRet = pLPropCompareProp(&pvLeft, &pvRight);
664 ok(iRet == iExp,
665 "pt %d (%d,%d): expected %d, got %d\n", ptTypes[i],
666 LPCProp_Results[j].lVal, LPCProp_Results[j].rVal, iExp, iRet);
671 static void test_PpropFindProp(void)
673 SPropValue pvProp, *pRet;
674 ULONG i;
676 if (!pPpropFindProp)
678 win_skip("PpropFindProp is not available\n");
679 return;
682 for (i = 0; i < sizeof(ptTypes)/sizeof(ptTypes[0]); i++)
684 pvProp.ulPropTag = ptTypes[i];
686 pRet = pPpropFindProp(&pvProp, 1u, ptTypes[i]);
687 ok(pRet == &pvProp,
688 "PpropFindProp[%d]: Didn't find existing propery\n",
689 ptTypes[i]);
691 pRet = pPpropFindProp(&pvProp, 1u, i ? ptTypes[i-1] : ptTypes[i+1]);
692 ok(pRet == NULL, "PpropFindProp[%d]: Found nonexistent propery\n",
693 ptTypes[i]);
696 pvProp.ulPropTag = PROP_TAG(PT_I2, 1u);
697 pRet = pPpropFindProp(&pvProp, 1u, PROP_TAG(PT_UNSPECIFIED, 0u));
698 ok(pRet == NULL, "PpropFindProp[UNSPECIFIED]: Matched on different id\n");
699 pRet = pPpropFindProp(&pvProp, 1u, PROP_TAG(PT_UNSPECIFIED, 1u));
700 ok(pRet == &pvProp, "PpropFindProp[UNSPECIFIED]: Didn't match id\n");
703 static void test_ScCountProps(void)
705 static char szHiA[] = "Hi!";
706 static WCHAR szHiW[] = { 'H', 'i', '!', '\0' };
707 static const ULONG ULHILEN = 4; /* chars in szHiA/W incl. NUL */
708 LPSTR buffa[3];
709 LPWSTR buffw[3];
710 SBinary buffbin[3];
711 GUID iids[4], *iid = iids;
712 SCODE res;
713 ULONG pt, exp, ulRet;
714 int success = 1;
716 if (!pScCountProps)
718 win_skip("ScCountProps is not available\n");
719 return;
722 for (pt = 0; pt < PROP_ID_INVALID && success; pt++)
724 SPropValue pv;
726 memset(&pv, 0 ,sizeof(pv));
727 pv.ulPropTag = PROP_TAG(pt, 1u);
729 switch (PROP_TYPE(pt))
731 case PT_I2:
732 case PT_I4:
733 case PT_R4:
734 case PT_R8:
735 case PT_CURRENCY:
736 case PT_APPTIME:
737 case PT_SYSTIME:
738 case PT_ERROR:
739 case PT_BOOLEAN:
740 case PT_OBJECT:
741 case PT_I8:
742 exp = sizeof(pv);
743 break;
744 case PT_CLSID:
745 pv.Value.lpguid = iid;
746 exp = sizeof(GUID) + sizeof(pv);
747 break;
748 case PT_STRING8:
749 pv.Value.lpszA = szHiA;
750 exp = 4 + sizeof(pv);
751 break;
752 case PT_UNICODE:
753 pv.Value.lpszW = szHiW;
754 exp = 4 * sizeof(WCHAR) + sizeof(pv);
755 break;
756 case PT_BINARY:
757 pv.Value.bin.cb = 2;
758 pv.Value.bin.lpb = (LPBYTE)iid;
759 exp = 2 + sizeof(pv);
760 break;
761 case PT_MV_I2:
762 pv.Value.MVi.cValues = 3;
763 pv.Value.MVi.lpi = (SHORT*)iid;
764 exp = 3 * sizeof(SHORT) + sizeof(pv);
765 break;
766 case PT_MV_I4:
767 pv.Value.MVl.cValues = 3;
768 pv.Value.MVl.lpl = (LONG*)iid;
769 exp = 3 * sizeof(LONG) + sizeof(pv);
770 break;
771 case PT_MV_I8:
772 pv.Value.MVli.cValues = 3;
773 pv.Value.MVli.lpli = (LARGE_INTEGER*)iid;
774 exp = 3 * sizeof(LARGE_INTEGER) + sizeof(pv);
775 break;
776 case PT_MV_R4:
777 pv.Value.MVflt.cValues = 3;
778 pv.Value.MVflt.lpflt = (float*)iid;
779 exp = 3 * sizeof(float) + sizeof(pv);
780 break;
781 case PT_MV_APPTIME:
782 case PT_MV_R8:
783 pv.Value.MVdbl.cValues = 3;
784 pv.Value.MVdbl.lpdbl = (double*)iid;
785 exp = 3 * sizeof(double) + sizeof(pv);
786 break;
787 case PT_MV_CURRENCY:
788 pv.Value.MVcur.cValues = 3;
789 pv.Value.MVcur.lpcur = (CY*)iid;
790 exp = 3 * sizeof(CY) + sizeof(pv);
791 break;
792 case PT_MV_SYSTIME:
793 pv.Value.MVft.cValues = 3;
794 pv.Value.MVft.lpft = (FILETIME*)iid;
795 exp = 3 * sizeof(CY) + sizeof(pv);
796 break;
797 case PT_MV_STRING8:
798 pv.Value.MVszA.cValues = 3;
799 pv.Value.MVszA.lppszA = buffa;
800 buffa[0] = szHiA;
801 buffa[1] = szHiA;
802 buffa[2] = szHiA;
803 exp = ULHILEN * 3 + 3 * sizeof(char*) + sizeof(pv);
804 break;
805 case PT_MV_UNICODE:
806 pv.Value.MVszW.cValues = 3;
807 pv.Value.MVszW.lppszW = buffw;
808 buffw[0] = szHiW;
809 buffw[1] = szHiW;
810 buffw[2] = szHiW;
811 exp = ULHILEN * 3 * sizeof(WCHAR) + 3 * sizeof(WCHAR*) + sizeof(pv);
812 break;
813 case PT_MV_BINARY:
814 pv.Value.MVbin.cValues = 3;
815 pv.Value.MVbin.lpbin = buffbin;
816 buffbin[0].cb = 17;
817 buffbin[0].lpb = (LPBYTE)&iid;
818 buffbin[1].cb = 2;
819 buffbin[1].lpb = (LPBYTE)&iid;
820 buffbin[2].cb = 1;
821 buffbin[2].lpb = (LPBYTE)&iid;
822 exp = 20 + sizeof(pv) + sizeof(SBinary) * 3;
823 break;
824 default:
825 exp = 0;
828 ulRet = 0xffffffff;
829 res = pScCountProps(1, &pv, &ulRet);
830 if (!exp) {
831 success = res == MAPI_E_INVALID_PARAMETER && ulRet == 0xffffffff;
832 ok(success, "pt= %d: Expected failure, got %d, ret=0x%08X\n",
833 pt, ulRet, res);
835 else {
836 success = res == S_OK && ulRet == exp;
837 ok(success, "pt= %d: Expected %d, got %d, ret=0x%08X\n",
838 pt, exp, ulRet, res);
844 static void test_ScCopyRelocProps(void)
846 static char szTestA[] = "Test";
847 char buffer[512], buffer2[512], *lppszA[1];
848 SPropValue pvProp, *lpResProp = (LPSPropValue)buffer;
849 ULONG ulCount;
850 SCODE sc;
852 if (!pScCopyProps || !pScRelocProps)
854 win_skip("SPropValue copy functions are not available\n");
855 return;
858 pvProp.ulPropTag = PROP_TAG(PT_MV_STRING8, 1u);
860 lppszA[0] = szTestA;
861 pvProp.Value.MVszA.cValues = 1;
862 pvProp.Value.MVszA.lppszA = lppszA;
863 ulCount = 0;
865 sc = pScCopyProps(1, &pvProp, buffer, &ulCount);
866 ok(sc == S_OK, "wrong ret %d\n", sc);
867 if(sc == S_OK)
869 ok(lpResProp->ulPropTag == pvProp.ulPropTag, "wrong tag %x\n",lpResProp->ulPropTag);
870 ok(lpResProp->Value.MVszA.cValues == 1, "wrong cValues %d\n", lpResProp->Value.MVszA.cValues);
871 ok(lpResProp->Value.MVszA.lppszA[0] == buffer + sizeof(SPropValue) + sizeof(char*),
872 "wrong lppszA[0] %p\n",lpResProp->Value.MVszA.lppszA[0]);
873 ok(ulCount == sizeof(SPropValue) + sizeof(char*) + 5, "wrong count %d\n", ulCount);
874 ok(!strcmp(lpResProp->Value.MVszA.lppszA[0], szTestA),
875 "wrong string '%s'\n", lpResProp->Value.MVszA.lppszA[0]);
878 memcpy(buffer2, buffer, sizeof(buffer));
880 /* Clear the data in the source buffer. Since pointers in the copied buffer
881 * refer to the source buffer, this proves that native always assumes that
882 * the copied buffers pointers are bad (needing to be relocated first).
884 memset(buffer, 0, sizeof(buffer));
885 ulCount = 0;
887 sc = pScRelocProps(1, (LPSPropValue)buffer2, buffer, buffer2, &ulCount);
888 lpResProp = (LPSPropValue)buffer2;
890 ok(sc == S_OK, "wrong ret %d\n", sc);
891 if(sc == S_OK)
893 ok(lpResProp->ulPropTag == pvProp.ulPropTag, "wrong tag %x\n",lpResProp->ulPropTag);
894 ok(lpResProp->Value.MVszA.cValues == 1, "wrong cValues %d\n", lpResProp->Value.MVszA.cValues);
895 ok(lpResProp->Value.MVszA.lppszA[0] == buffer2 + sizeof(SPropValue) + sizeof(char*),
896 "wrong lppszA[0] %p\n",lpResProp->Value.MVszA.lppszA[0]);
897 /* Native has a bug whereby it calculates the size correctly when copying
898 * but when relocating does not (presumably it uses UlPropSize() which
899 * ignores multivalue pointers). Wine returns the correct value.
901 ok(ulCount == sizeof(SPropValue) + sizeof(char*) + 5 || ulCount == sizeof(SPropValue) + 5,
902 "wrong count %d\n", ulCount);
903 ok(!strcmp(lpResProp->Value.MVszA.lppszA[0], szTestA),
904 "wrong string '%s'\n", lpResProp->Value.MVszA.lppszA[0]);
907 /* Native crashes with lpNew or lpOld set to NULL so skip testing this */
910 static void test_LpValFindProp(void)
912 SPropValue pvProp, *pRet;
913 ULONG i;
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 if (!pFBadRglpszA)
953 win_skip("FBadRglpszA is not available\n");
954 return;
957 bRet = pFBadRglpszA(NULL, 10);
958 ok(bRet == TRUE, "FBadRglpszA(Null): expected TRUE, got FALSE\n");
960 lpStrs[0] = lpStrs[1] = lpStrs[2] = lpStrs[3] = NULL;
961 bRet = pFBadRglpszA(lpStrs, 4);
962 ok(bRet == TRUE, "FBadRglpszA(Nulls): expected TRUE, got FALSE\n");
964 lpStrs[0] = lpStrs[1] = lpStrs[2] = szString;
965 bRet = pFBadRglpszA(lpStrs, 3);
966 ok(bRet == FALSE, "FBadRglpszA(valid): expected FALSE, got TRUE\n");
968 bRet = pFBadRglpszA(lpStrs, 4);
969 ok(bRet == TRUE, "FBadRglpszA(1 invalid): expected TRUE, got FALSE\n");
972 static void test_FBadRglpszW(void)
974 LPWSTR lpStrs[4];
975 static WCHAR szString[] = { 'A',' ','S','t','r','i','n','g','\0' };
976 BOOL bRet;
978 if (!pFBadRglpszW)
980 win_skip("FBadRglpszW is not available\n");
981 return;
984 bRet = pFBadRglpszW(NULL, 10);
985 ok(bRet == TRUE, "FBadRglpszW(Null): expected TRUE, got FALSE\n");
987 lpStrs[0] = lpStrs[1] = lpStrs[2] = lpStrs[3] = NULL;
988 bRet = pFBadRglpszW(lpStrs, 4);
989 ok(bRet == TRUE, "FBadRglpszW(Nulls): expected TRUE, got FALSE\n");
991 lpStrs[0] = lpStrs[1] = lpStrs[2] = szString;
992 bRet = pFBadRglpszW(lpStrs, 3);
993 ok(bRet == FALSE, "FBadRglpszW(valid): expected FALSE, got TRUE\n");
995 bRet = pFBadRglpszW(lpStrs, 4);
996 ok(bRet == TRUE, "FBadRglpszW(1 invalid): expected TRUE, got FALSE\n");
999 static void test_FBadRowSet(void)
1001 ULONG ulRet;
1003 if (!pFBadRowSet)
1005 win_skip("FBadRowSet is not available\n");
1006 return;
1009 ulRet = pFBadRowSet(NULL);
1010 ok(ulRet != 0, "FBadRow(null): Expected non-zero, got 0\n");
1012 /* FIXME */
1015 static void test_FBadPropTag(void)
1017 ULONG pt, res;
1019 if (!pFBadPropTag)
1021 win_skip("FBadPropTag is not available\n");
1022 return;
1025 for (pt = 0; pt < PROP_ID_INVALID; pt++)
1027 BOOL bBad = TRUE;
1029 switch (pt & (~MV_FLAG & PROP_TYPE_MASK))
1031 case PT_UNSPECIFIED:
1032 case PT_NULL: case PT_I2: case PT_I4: case PT_R4:
1033 case PT_R8: case PT_CURRENCY: case PT_APPTIME:
1034 case PT_ERROR: case PT_BOOLEAN: case PT_OBJECT:
1035 case PT_I8: case PT_STRING8: case PT_UNICODE:
1036 case PT_SYSTIME: case PT_CLSID: case PT_BINARY:
1037 bBad = FALSE;
1040 res = pFBadPropTag(pt);
1041 if (bBad)
1042 ok(res != 0, "pt= %d: Expected non-zero, got 0\n", pt);
1043 else
1044 ok(res == 0,
1045 "pt= %d: Expected zero, got %d\n", pt, res);
1049 static void test_FBadRow(void)
1051 ULONG ulRet;
1053 if (!pFBadRow)
1055 win_skip("FBadRow is not available\n");
1056 return;
1059 ulRet = pFBadRow(NULL);
1060 ok(ulRet != 0, "FBadRow(null): Expected non-zero, got 0\n");
1062 /* FIXME */
1065 static void test_FBadProp(void)
1067 static WCHAR szEmpty[] = { '\0' };
1068 GUID iid;
1069 ULONG pt, res;
1070 SPropValue pv;
1072 if (!pFBadProp)
1074 win_skip("FBadProp is not available\n");
1075 return;
1078 for (pt = 0; pt < PROP_ID_INVALID; pt++)
1080 BOOL bBad = TRUE;
1082 memset(&pv, 0, sizeof(pv));
1083 pv.ulPropTag = pt;
1085 /* Note that MV values are valid below because their array count is 0,
1086 * so no pointers are validated.
1088 switch (PROP_TYPE(pt))
1090 case (MV_FLAG|PT_UNSPECIFIED):
1091 case PT_UNSPECIFIED:
1092 case (MV_FLAG|PT_NULL):
1093 case PT_NULL:
1094 case PT_MV_I2:
1095 case PT_I2:
1096 case PT_MV_I4:
1097 case PT_I4:
1098 case PT_MV_I8:
1099 case PT_I8:
1100 case PT_MV_R4:
1101 case PT_R4:
1102 case PT_MV_R8:
1103 case PT_R8:
1104 case PT_MV_CURRENCY:
1105 case PT_CURRENCY:
1106 case PT_MV_APPTIME:
1107 case PT_APPTIME:
1108 case (MV_FLAG|PT_ERROR):
1109 case PT_ERROR:
1110 case (MV_FLAG|PT_BOOLEAN):
1111 case PT_BOOLEAN:
1112 case (MV_FLAG|PT_OBJECT):
1113 case PT_OBJECT:
1114 case PT_MV_STRING8:
1115 case PT_MV_UNICODE:
1116 case PT_MV_SYSTIME:
1117 case PT_SYSTIME:
1118 case PT_MV_BINARY:
1119 case PT_BINARY:
1120 case PT_MV_CLSID:
1121 bBad = FALSE;
1122 break;
1123 case PT_STRING8:
1124 case PT_UNICODE:
1125 pv.Value.lpszW = szEmpty;
1126 bBad = FALSE;
1127 break;
1128 case PT_CLSID:
1129 pv.Value.lpguid = &iid;
1130 bBad = FALSE;
1131 break;
1134 res = pFBadProp(&pv);
1135 if (bBad)
1136 ok(res != 0, "pt= %d: Expected non-zero, got 0\n", pt);
1137 else
1138 ok(res == 0,
1139 "pt= %d: Expected zero, got %d\n", pt, res);
1143 static void test_FBadColumnSet(void)
1145 SPropTagArray pta;
1146 ULONG pt, res;
1148 if (!pFBadColumnSet)
1150 win_skip("FBadColumnSet is not available\n");
1151 return;
1154 res = pFBadColumnSet(NULL);
1155 ok(res != 0, "(null): Expected non-zero, got 0\n");
1157 pta.cValues = 1;
1159 for (pt = 0; pt < PROP_ID_INVALID; pt++)
1161 BOOL bBad = TRUE;
1163 pta.aulPropTag[0] = pt;
1165 switch (pt & (~MV_FLAG & PROP_TYPE_MASK))
1167 case PT_UNSPECIFIED:
1168 case PT_NULL:
1169 case PT_I2:
1170 case PT_I4:
1171 case PT_R4:
1172 case PT_R8:
1173 case PT_CURRENCY:
1174 case PT_APPTIME:
1175 case PT_BOOLEAN:
1176 case PT_OBJECT:
1177 case PT_I8:
1178 case PT_STRING8:
1179 case PT_UNICODE:
1180 case PT_SYSTIME:
1181 case PT_CLSID:
1182 case PT_BINARY:
1183 bBad = FALSE;
1185 if (pt == (MV_FLAG|PT_ERROR))
1186 bBad = FALSE;
1188 res = pFBadColumnSet(&pta);
1189 if (bBad)
1190 ok(res != 0, "pt= %d: Expected non-zero, got 0\n", pt);
1191 else
1192 ok(res == 0,
1193 "pt= %d: Expected zero, got %d\n", pt, res);
1198 static void test_IProp(void)
1200 IPropData *lpIProp;
1201 LPMAPIERROR lpError;
1202 LPSPropProblemArray lpProbs;
1203 LPSPropValue lpProps;
1204 LPSPropTagArray lpTags;
1205 SPropValue pvs[2];
1206 SizedSPropTagArray(2,tags);
1207 ULONG access[2], count;
1208 SCODE sc;
1210 if (!pCreateIProp)
1212 win_skip("CreateIProp is not available\n");
1213 return;
1216 memset(&tags, 0 , sizeof(tags));
1218 /* Create the object */
1219 lpIProp = NULL;
1220 sc = pCreateIProp(&IID_IMAPIPropData, (ALLOCATEBUFFER *)pMAPIAllocateBuffer, (ALLOCATEMORE*)pMAPIAllocateMore,
1221 (FREEBUFFER *)pMAPIFreeBuffer, NULL, &lpIProp);
1222 ok(sc == S_OK && lpIProp,
1223 "CreateIProp: expected S_OK, non-null, got 0x%08X,%p\n", sc, lpIProp);
1225 if (sc != S_OK || !lpIProp)
1226 return;
1228 /* GetLastError - No errors set */
1229 lpError = NULL;
1230 IPropData_GetLastError(lpIProp, E_INVALIDARG, 0, &lpError);
1231 ok(sc == S_OK && !lpError,
1232 "GetLastError: Expected S_OK, null, got 0x%08X,%p\n", sc, lpError);
1234 /* Get prop tags - succeeds returning 0 items */
1235 lpTags = NULL;
1236 sc = IPropData_GetPropList(lpIProp, 0, &lpTags);
1237 ok(sc == S_OK && lpTags && lpTags->cValues == 0,
1238 "GetPropList(empty): Expected S_OK, non-null, 0, got 0x%08X,%p,%d\n",
1239 sc, lpTags, lpTags ? lpTags->cValues : 0);
1240 if (lpTags)
1241 pMAPIFreeBuffer(lpTags);
1243 /* Get props - succeeds returning 0 items */
1244 lpProps = NULL;
1245 count = 0;
1246 tags.cValues = 1;
1247 tags.aulPropTag[0] = PR_IMPORTANCE;
1248 sc = IPropData_GetProps(lpIProp, (LPSPropTagArray)&tags, 0, &count, &lpProps);
1249 ok(sc == MAPI_W_ERRORS_RETURNED && lpProps && count == 1,
1250 "GetProps(empty): Expected ERRORS_RETURNED, non-null, 1, got 0x%08X,%p,%d\n",
1251 sc, lpProps, count);
1252 if (lpProps && count > 0)
1254 ok(lpProps[0].ulPropTag == CHANGE_PROP_TYPE(PR_IMPORTANCE,PT_ERROR),
1255 "GetProps(empty): Expected %x, got %x\n",
1256 CHANGE_PROP_TYPE(PR_IMPORTANCE,PT_ERROR), lpProps[0].ulPropTag);
1258 pMAPIFreeBuffer(lpProps);
1261 /* Add (NULL) - Can't add NULLs */
1262 lpProbs = NULL;
1263 pvs[0].ulPropTag = PROP_TAG(PT_NULL,0x01);
1264 sc = IPropData_SetProps(lpIProp, 1, pvs, &lpProbs);
1265 ok(sc == MAPI_E_INVALID_PARAMETER && !lpProbs,
1266 "SetProps(): Expected INVALID_PARAMETER, null, got 0x%08X,%p\n",
1267 sc, lpProbs);
1269 /* Add (OBJECT) - Can't add OBJECTs */
1270 lpProbs = NULL;
1271 pvs[0].ulPropTag = PROP_TAG(PT_OBJECT,0x01);
1272 sc = IPropData_SetProps(lpIProp, 1, pvs, &lpProbs);
1273 ok(sc == MAPI_E_INVALID_PARAMETER && !lpProbs,
1274 "SetProps(OBJECT): Expected INVALID_PARAMETER, null, got 0x%08X,%p\n",
1275 sc, lpProbs);
1277 /* Add - Adds value */
1278 lpProbs = NULL;
1279 pvs[0].ulPropTag = PR_IMPORTANCE;
1280 sc = IPropData_SetProps(lpIProp, 1, pvs, &lpProbs);
1281 ok(sc == S_OK && !lpProbs,
1282 "SetProps(ERROR): Expected S_OK, null, got 0x%08X,%p\n", sc, lpProbs);
1284 /* Get prop list - returns 1 item */
1285 lpTags = NULL;
1286 IPropData_GetPropList(lpIProp, 0, &lpTags);
1287 ok(sc == S_OK && lpTags && lpTags->cValues == 1,
1288 "GetPropList: Expected S_OK, non-null, 1, got 0x%08X,%p,%d\n",
1289 sc, lpTags, lpTags ? lpTags->cValues : 0);
1290 if (lpTags && lpTags->cValues > 0)
1292 ok(lpTags->aulPropTag[0] == PR_IMPORTANCE,
1293 "GetPropList: Expected %x, got %x\n",
1294 PR_IMPORTANCE, lpTags->aulPropTag[0]);
1295 pMAPIFreeBuffer(lpTags);
1298 /* Set access to read and write */
1299 sc = IPropData_HrSetObjAccess(lpIProp, IPROP_READWRITE);
1300 ok(sc == S_OK, "SetObjAcess(WRITE): Expected S_OK got 0x%08X\n", sc);
1302 tags.cValues = 1;
1303 tags.aulPropTag[0] = PR_IMPORTANCE;
1305 /* Set item access (bad access) - Fails */
1306 access[0] = 0;
1307 sc = IPropData_HrSetPropAccess(lpIProp, (LPSPropTagArray)&tags, access);
1308 ok(sc == MAPI_E_INVALID_PARAMETER,
1309 "SetPropAcess(0): Expected INVALID_PARAMETER got 0x%08X\n",sc);
1310 access[0] = IPROP_READWRITE;
1311 sc = IPropData_HrSetPropAccess(lpIProp, (LPSPropTagArray)&tags, access);
1312 ok(sc == MAPI_E_INVALID_PARAMETER,
1313 "SetPropAcess(RW): Expected INVALID_PARAMETER got 0x%08X\n",sc);
1314 access[0] = IPROP_CLEAN;
1315 sc = IPropData_HrSetPropAccess(lpIProp, (LPSPropTagArray)&tags, access);
1316 ok(sc == MAPI_E_INVALID_PARAMETER,
1317 "SetPropAcess(C): Expected INVALID_PARAMETER got 0x%08X\n",sc);
1319 /* Set item access to read/write/clean */
1320 tags.cValues = 1;
1321 tags.aulPropTag[0] = PR_IMPORTANCE;
1322 access[0] = IPROP_READWRITE|IPROP_CLEAN;
1323 sc = IPropData_HrSetPropAccess(lpIProp, (LPSPropTagArray)&tags, access);
1324 ok(sc == S_OK, "SetPropAcess(RW/C): Expected S_OK got 0x%08X\n",sc);
1326 /* Set object access to read only */
1327 sc = IPropData_HrSetObjAccess(lpIProp, IPROP_READONLY);
1328 ok(sc == S_OK, "SetObjAcess(READ): Expected S_OK got 0x%08X\n", sc);
1330 /* Set item access to read/write/dirty - doesn't care about RO object */
1331 access[0] = IPROP_READONLY|IPROP_DIRTY;
1332 sc = IPropData_HrSetPropAccess(lpIProp, (LPSPropTagArray)&tags, access);
1333 ok(sc == S_OK, "SetPropAcess(WRITE): Expected S_OK got 0x%08X\n", sc);
1335 /* Delete any item when set to read only - Error */
1336 lpProbs = NULL;
1337 tags.aulPropTag[0] = PR_RESPONSE_REQUESTED;
1338 sc = IPropData_DeleteProps(lpIProp, (LPSPropTagArray)&tags, &lpProbs);
1339 ok(sc == E_ACCESSDENIED && !lpProbs,
1340 "DeleteProps(nonexistent): Expected E_ACCESSDENIED null got 0x%08X %p\n",
1341 sc, lpProbs);
1343 /* Set access to read and write */
1344 sc = IPropData_HrSetObjAccess(lpIProp, IPROP_READWRITE);
1345 ok(sc == S_OK, "SetObjAcess(WRITE): Expected S_OK got 0x%08X\n", sc);
1347 /* Delete nonexistent item - No error */
1348 lpProbs = NULL;
1349 tags.aulPropTag[0] = PR_RESPONSE_REQUESTED;
1350 sc = IPropData_DeleteProps(lpIProp, (LPSPropTagArray)&tags, &lpProbs);
1351 ok(sc == S_OK && !lpProbs,
1352 "DeleteProps(nonexistent): Expected S_OK null got 0x%08X %p\n",
1353 sc, lpProbs);
1355 /* Delete existing item (r/o) - No error, but lpProbs populated */
1356 lpProbs = NULL;
1357 tags.aulPropTag[0] = PR_IMPORTANCE;
1358 sc = IPropData_DeleteProps(lpIProp, (LPSPropTagArray)&tags, &lpProbs);
1359 ok(sc == S_OK && lpProbs,
1360 "DeleteProps(RO): Expected S_OK non-null got 0x%08X %p\n", sc, lpProbs);
1362 if (lpProbs && lpProbs->cProblem > 0)
1364 ok(lpProbs->cProblem == 1 &&
1365 lpProbs->aProblem[0].ulIndex == 0 &&
1366 lpProbs->aProblem[0].ulPropTag == PR_IMPORTANCE &&
1367 lpProbs->aProblem[0].scode == E_ACCESSDENIED,
1368 "DeleteProps(RO): Expected (1,0,%x,%x) got (%d,%x,%x)\n",
1369 PR_IMPORTANCE, E_ACCESSDENIED,
1370 lpProbs->aProblem[0].ulIndex, lpProbs->aProblem[0].ulPropTag,
1371 lpProbs->aProblem[0].scode);
1372 pMAPIFreeBuffer(lpProbs);
1375 lpProbs = NULL;
1376 tags.cValues = 1;
1377 tags.aulPropTag[0] = PR_RESPONSE_REQUESTED;
1378 IPropData_HrAddObjProps(lpIProp, (LPSPropTagArray)&tags, &lpProbs);
1379 ok(sc == S_OK && !lpProbs,
1380 "AddObjProps(RO): Expected S_OK null got 0x%08X %p\n", sc, lpProbs);
1382 /* Get prop list - returns 1 item */
1383 lpTags = NULL;
1384 IPropData_GetPropList(lpIProp, 0, &lpTags);
1385 ok(sc == S_OK && lpTags && lpTags->cValues == 1,
1386 "GetPropList: Expected S_OK, non-null, 1, got 0x%08X,%p,%d\n",
1387 sc, lpTags, lpTags ? lpTags->cValues : 0);
1388 if (lpTags && lpTags->cValues > 0)
1390 ok(lpTags->aulPropTag[0] == PR_IMPORTANCE,
1391 "GetPropList: Expected %x, got %x\n",
1392 PR_IMPORTANCE, lpTags->aulPropTag[0]);
1393 pMAPIFreeBuffer(lpTags);
1396 /* Set item to r/w again */
1397 access[0] = IPROP_READWRITE|IPROP_DIRTY;
1398 sc = IPropData_HrSetPropAccess(lpIProp, (LPSPropTagArray)&tags, access);
1399 ok(sc == S_OK, "SetPropAcess(WRITE): Expected S_OK got 0x%08X\n", sc);
1401 /* Delete existing item (r/w) - No error, no problems */
1402 lpProbs = NULL;
1403 sc = IPropData_DeleteProps(lpIProp, (LPSPropTagArray)&tags, &lpProbs);
1404 ok(sc == S_OK && !lpProbs,
1405 "DeleteProps(RO): Expected S_OK null got 0x%08X %p\n", sc, lpProbs);
1407 /* Free the list */
1408 IPropData_Release(lpIProp);
1411 START_TEST(prop)
1413 SCODE ret;
1415 if (!HaveDefaultMailClient())
1417 win_skip("No default mail client installed\n");
1418 return;
1421 if(!InitFuncPtrs())
1423 win_skip("Needed functions are not available\n");
1424 return;
1427 SetLastError(0xdeadbeef);
1428 ret = pScInitMapiUtil(0);
1429 if ((ret != S_OK) && (GetLastError() == ERROR_PROC_NOT_FOUND))
1431 win_skip("ScInitMapiUtil is not implemented\n");
1432 FreeLibrary(hMapi32);
1433 return;
1435 else if ((ret == E_FAIL) && (GetLastError() == ERROR_INVALID_HANDLE))
1437 win_skip("ScInitMapiUtil doesn't work on some Win98 and WinME systems\n");
1438 FreeLibrary(hMapi32);
1439 return;
1442 test_PropCopyMore();
1443 test_UlPropSize();
1444 test_FPropContainsProp();
1445 test_FPropCompareProp();
1446 test_LPropCompareProp();
1447 test_PpropFindProp();
1448 test_ScCountProps();
1449 test_ScCopyRelocProps();
1450 test_LpValFindProp();
1451 test_FBadRglpszA();
1452 test_FBadRglpszW();
1453 test_FBadRowSet();
1454 test_FBadPropTag();
1455 test_FBadRow();
1456 test_FBadProp();
1457 test_FBadColumnSet();
1459 test_IProp();
1460 FreeLibrary(hMapi32);