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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #define NONAMELESSUNION
22 #define NONAMELESSSTRUCT
23 #include "wine/test.h"
32 HRESULT WINAPI MAPIInitialize(LPVOID);
34 static HMODULE hMapi32 = 0;
36 static SCODE (WINAPI *pScInitMapiUtil)(ULONG);
37 static SCODE (WINAPI *pPropCopyMore)(LPSPropValue,LPSPropValue,ALLOCATEMORE*,LPVOID);
38 static ULONG (WINAPI *pUlPropSize)(LPSPropValue);
39 static BOOL (WINAPI *pFPropContainsProp)(LPSPropValue,LPSPropValue,ULONG);
40 static BOOL (WINAPI *pFPropCompareProp)(LPSPropValue,ULONG,LPSPropValue);
41 static LONG (WINAPI *pLPropCompareProp)(LPSPropValue,LPSPropValue);
42 static LPSPropValue (WINAPI *pPpropFindProp)(LPSPropValue,ULONG,ULONG);
43 static SCODE (WINAPI *pScCountProps)(INT,LPSPropValue,ULONG*);
44 static SCODE (WINAPI *pScCopyProps)(int,LPSPropValue,LPVOID,ULONG*);
45 static SCODE (WINAPI *pScRelocProps)(int,LPSPropValue,LPVOID,LPVOID,ULONG*);
46 static LPSPropValue (WINAPI *pLpValFindProp)(ULONG,ULONG,LPSPropValue);
47 static BOOL (WINAPI *pFBadRglpszA)(LPSTR*,ULONG);
48 static BOOL (WINAPI *pFBadRglpszW)(LPWSTR*,ULONG);
49 static BOOL (WINAPI *pFBadRowSet)(LPSRowSet);
50 static ULONG (WINAPI *pFBadPropTag)(ULONG);
51 static ULONG (WINAPI *pFBadRow)(LPSRow);
52 static ULONG (WINAPI *pFBadProp)(LPSPropValue);
53 static ULONG (WINAPI *pFBadColumnSet)(LPSPropTagArray);
55 static ULONG ptTypes[] = {
56 PT_I2, PT_I4, PT_R4, PT_R8, PT_CURRENCY, PT_APPTIME, PT_SYSTIME,
57 PT_ERROR, PT_BOOLEAN, PT_I8, PT_CLSID, PT_STRING8, PT_BINARY,
61 static inline int strcmpW(const WCHAR *str1, const WCHAR *str2)
63 while (*str1 && (*str1 == *str2)) { str1++; str2++; }
67 static void test_PropCopyMore(void)
69 static const char *szHiA = "Hi!";
70 static const WCHAR szHiW[] = { 'H', 'i', '!', '\0' };
71 SPropValue *lpDest = NULL, *lpSrc = NULL;
75 pPropCopyMore = (void*)GetProcAddress(hMapi32, "PropCopyMore@16");
80 scode = MAPIAllocateBuffer(sizeof(LPSPropValue), (LPVOID *)lpDest);
84 scode = MAPIAllocateMore(sizeof(LPSPropValue), lpDest, (LPVOID *)lpSrc);
88 for (i = 0; i < sizeof(ptTypes)/sizeof(ptTypes[0]); i++)
90 lpSrc->ulPropTag = ptTypes[i];
95 lpSrc->Value.lpszA = (char*)szHiA;
98 lpSrc->Value.lpszW = (WCHAR*)szHiW;
101 lpSrc->Value.bin.cb = 4;
102 lpSrc->Value.bin.lpb = (LPBYTE)szHiA;
106 memset(lpDest, 0xff, sizeof(SPropValue));
108 scode = pPropCopyMore(lpDest, lpSrc, MAPIAllocateMore, lpDest);
109 ok(!scode && lpDest->ulPropTag == lpSrc->ulPropTag,
110 "PropCopyMore: Expected 0x0,%ld, got 0x%08lx,%ld\n",
111 lpSrc->ulPropTag, scode, lpDest->ulPropTag);
112 if (SUCCEEDED(scode))
117 ok(lstrcmpA(lpDest->Value.lpszA, lpSrc->Value.lpszA) == 0,
118 "PropCopyMore: Ascii string differs\n");
121 ok(strcmpW(lpDest->Value.lpszW, lpSrc->Value.lpszW) == 0,
122 "PropCopyMore: Unicode string differs\n");
125 ok(lpDest->Value.bin.cb == 4 &&
126 !memcmp(lpSrc->Value.bin.lpb, lpDest->Value.bin.lpb, 4),
127 "PropCopyMore: Binary array differs\n");
133 /* Since all allocations are linked, freeing lpDest frees everything */
134 MAPIFreeBuffer(lpDest);
137 static void test_UlPropSize(void)
139 static const char *szHiA = "Hi!";
140 static const WCHAR szHiW[] = { 'H', 'i', '!', '\0' };
146 pUlPropSize = (void*)GetProcAddress(hMapi32, "UlPropSize@4");
151 for (pt = 0; pt < PROP_ID_INVALID; pt++)
155 memset(&pv, 0 ,sizeof(pv));
158 exp = 1u; /* Default to one item for non-MV properties */
160 switch (PROP_TYPE(pt))
162 case PT_MV_I2: pv.Value.MVi.cValues = exp = 2;
163 case PT_I2: exp *= sizeof(USHORT); break;
164 case PT_MV_I4: pv.Value.MVl.cValues = exp = 2;
165 case PT_I4: exp *= sizeof(LONG); break;
166 case PT_MV_R4: pv.Value.MVflt.cValues = exp = 2;
167 case PT_R4: exp *= sizeof(float); break;
168 case PT_MV_DOUBLE: pv.Value.MVdbl.cValues = exp = 2;
169 case PT_R8: exp *= sizeof(double); break;
170 case PT_MV_CURRENCY: pv.Value.MVcur.cValues = exp = 2;
171 case PT_CURRENCY: exp *= sizeof(CY); break;
172 case PT_MV_APPTIME: pv.Value.MVat.cValues = exp = 2;
173 case PT_APPTIME: exp *= sizeof(double); break;
174 case PT_MV_SYSTIME: pv.Value.MVft.cValues = exp = 2;
175 case PT_SYSTIME: exp *= sizeof(FILETIME); break;
176 case PT_ERROR: exp = sizeof(SCODE); break;
177 case PT_BOOLEAN: exp = sizeof(USHORT); break;
178 case PT_OBJECT: exp = 0; break;
179 case PT_MV_I8: pv.Value.MVli.cValues = exp = 2;
180 case PT_I8: exp *= sizeof(LONG64); break;
182 /* My version of native mapi returns 0 for PT_MV_CLSID even if a valid
183 * array is given. This _has_ to be a bug, so Wine does
184 * the right thing(tm) and we don't test it here.
186 case PT_MV_CLSID: pv.Value.MVguid.cValues = exp = 2;
188 case PT_CLSID: exp *= sizeof(GUID); break;
190 pv.Value.lpszA = (LPSTR)szHiA;
194 pv.Value.lpszW = (LPWSTR)szHiW;
195 exp = 4 * sizeof(WCHAR);
198 pv.Value.bin.cb = exp = 19;
201 pv.Value.MVszA.cValues = 2;
202 pv.Value.MVszA.lppszA = buffa;
203 buffa[0] = (LPSTR)szHiA;
204 buffa[1] = (LPSTR)szHiA;
208 pv.Value.MVszW.cValues = 2;
209 pv.Value.MVszW.lppszW = buffw;
210 buffw[0] = (LPWSTR)szHiW;
211 buffw[1] = (LPWSTR)szHiW;
212 exp = 8 * sizeof(WCHAR);
215 pv.Value.MVbin.cValues = 2;
216 pv.Value.MVbin.lpbin = buffbin;
225 res = pUlPropSize(&pv);
226 ok(res == exp, "pt= %ld: Expected %ld, got %ld\n", pt, exp, res);
230 static void test_FPropContainsProp(void)
232 static const char *szFull = "Full String";
233 static const char *szFullLower = "full string";
234 static const char *szPrefix = "Full";
235 static const char *szPrefixLower = "full";
236 static const char *szSubstring = "ll St";
237 static const char *szSubstringLower = "ll st";
238 SPropValue pvLeft, pvRight;
242 pFPropContainsProp = (void*)GetProcAddress(hMapi32, "FPropContainsProp@12");
244 if (!pFPropContainsProp)
247 /* Ensure that only PT_STRING8 and PT_BINARY are handled */
248 for (pt = 0; pt < PROP_ID_INVALID; pt++)
250 if (pt == PT_STRING8 || pt == PT_BINARY)
251 continue; /* test these later */
253 memset(&pvLeft, 0 ,sizeof(pvLeft));
254 memset(&pvRight, 0 ,sizeof(pvRight));
255 pvLeft.ulPropTag = pvRight.ulPropTag = pt;
257 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
258 ok(bRet == FALSE, "pt= %ld: Expected FALSE, got %d\n", pt, bRet);
261 /* test the various flag combinations */
262 pvLeft.ulPropTag = pvRight.ulPropTag = PT_STRING8;
263 pvLeft.Value.lpszA = (LPSTR)szFull;
264 pvRight.Value.lpszA = (LPSTR)szFull;
266 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
267 ok(bRet == TRUE, "(full,full)[] match failed\n");
268 pvRight.Value.lpszA = (LPSTR)szPrefix;
269 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
270 ok(bRet == FALSE, "(full,prefix)[] match failed\n");
271 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
272 ok(bRet == TRUE, "(full,prefix)[PREFIX] match failed\n");
273 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
274 ok(bRet == TRUE, "(full,prefix)[SUBSTRING] match failed\n");
275 pvRight.Value.lpszA = (LPSTR)szPrefixLower;
276 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
277 ok(bRet == FALSE, "(full,prefixlow)[PREFIX] match failed\n");
278 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
279 ok(bRet == FALSE, "(full,prefixlow)[SUBSTRING] match failed\n");
280 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX|FL_IGNORECASE);
281 ok(bRet == TRUE, "(full,prefixlow)[PREFIX|IGNORECASE] match failed\n");
282 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING|FL_IGNORECASE);
283 ok(bRet == TRUE, "(full,prefixlow)[SUBSTRING|IGNORECASE] match failed\n");
284 pvRight.Value.lpszA = (LPSTR)szSubstring;
285 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
286 ok(bRet == FALSE, "(full,substr)[] match failed\n");
287 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
288 ok(bRet == FALSE, "(full,substr)[PREFIX] match failed\n");
289 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
290 ok(bRet == TRUE, "(full,substr)[SUBSTRING] match failed\n");
291 pvRight.Value.lpszA = (LPSTR)szSubstringLower;
292 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
293 ok(bRet == FALSE, "(full,substrlow)[PREFIX] match failed\n");
294 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
295 ok(bRet == FALSE, "(full,substrlow)[SUBSTRING] match failed\n");
296 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX|FL_IGNORECASE);
297 ok(bRet == FALSE, "(full,substrlow)[PREFIX|IGNORECASE] match failed\n");
298 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING|FL_IGNORECASE);
299 ok(bRet == TRUE, "(full,substrlow)[SUBSTRING|IGNORECASE] match failed\n");
300 pvRight.Value.lpszA = (LPSTR)szFullLower;
301 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING|FL_IGNORECASE);
302 ok(bRet == TRUE, "(full,fulllow)[IGNORECASE] match failed\n");
304 pvLeft.ulPropTag = pvRight.ulPropTag = PT_BINARY;
305 pvLeft.Value.bin.lpb = (LPBYTE)szFull;
306 pvRight.Value.bin.lpb = (LPBYTE)szFull;
307 pvLeft.Value.bin.cb = pvRight.Value.bin.cb = strlen(szFull);
309 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
310 ok(bRet == TRUE, "bin(full,full)[] match failed\n");
311 pvRight.Value.bin.lpb = (LPBYTE)szPrefix;
312 pvRight.Value.bin.cb = strlen(szPrefix);
313 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
314 ok(bRet == FALSE, "bin(full,prefix)[] match failed\n");
315 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
316 ok(bRet == TRUE, "bin(full,prefix)[PREFIX] match failed\n");
317 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
318 ok(bRet == TRUE, "bin(full,prefix)[SUBSTRING] match failed\n");
319 pvRight.Value.bin.lpb = (LPBYTE)szPrefixLower;
320 pvRight.Value.bin.cb = strlen(szPrefixLower);
321 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
322 ok(bRet == FALSE, "bin(full,prefixlow)[PREFIX] match failed\n");
323 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
324 ok(bRet == FALSE, "bin(full,prefixlow)[SUBSTRING] match failed\n");
325 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX|FL_IGNORECASE);
326 ok(bRet == FALSE, "bin(full,prefixlow)[PREFIX|IGNORECASE] match failed\n");
327 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING|FL_IGNORECASE);
328 ok(bRet == FALSE, "bin(full,prefixlow)[SUBSTRING|IGNORECASE] match failed\n");
329 pvRight.Value.bin.lpb = (LPBYTE)szSubstring;
330 pvRight.Value.bin.cb = strlen(szSubstring);
331 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
332 ok(bRet == FALSE, "bin(full,substr)[] match failed\n");
333 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
334 ok(bRet == FALSE, "bin(full,substr)[PREFIX] match failed\n");
335 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
336 ok(bRet == TRUE, "bin(full,substr)[SUBSTRING] match failed\n");
337 pvRight.Value.bin.lpb = (LPBYTE)szSubstringLower;
338 pvRight.Value.bin.cb = strlen(szSubstringLower);
339 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
340 ok(bRet == FALSE, "bin(full,substrlow)[PREFIX] match failed\n");
341 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
342 ok(bRet == FALSE, "bin(full,substrlow)[SUBSTRING] match failed\n");
343 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX|FL_IGNORECASE);
344 ok(bRet == FALSE, "bin(full,substrlow)[PREFIX|IGNORECASE] match failed\n");
345 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING|FL_IGNORECASE);
346 ok(bRet == FALSE, "bin(full,substrlow)[SUBSTRING|IGNORECASE] match failed\n");
347 pvRight.Value.bin.lpb = (LPBYTE)szFullLower;
348 pvRight.Value.bin.cb = strlen(szFullLower);
349 bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING|FL_IGNORECASE);
350 ok(bRet == FALSE, "bin(full,fulllow)[IGNORECASE] match failed\n");
353 typedef struct tagFPropCompareProp_Result
359 } FPropCompareProp_Result;
361 static const FPropCompareProp_Result FPCProp_Results[] =
363 { 1, 2, RELOP_LT, TRUE },
364 { 1, 1, RELOP_LT, FALSE },
365 { 2, 1, RELOP_LT, FALSE },
366 { 1, 2, RELOP_LE, TRUE },
367 { 1, 1, RELOP_LE, TRUE },
368 { 2, 1, RELOP_LE, FALSE },
369 { 1, 2, RELOP_GT, FALSE },
370 { 1, 1, RELOP_GT, FALSE },
371 { 2, 1, RELOP_GT, TRUE },
372 { 1, 2, RELOP_GE, FALSE },
373 { 1, 1, RELOP_GE, TRUE },
374 { 2, 1, RELOP_GE, TRUE },
375 { 1, 2, RELOP_EQ, FALSE },
376 { 1, 1, RELOP_EQ, TRUE },
377 { 2, 1, RELOP_EQ, FALSE }
380 static const char *relops[] = { "RELOP_LT", "RELOP_LE", "RELOP_GT", "RELOP_GE", "RELOP_EQ" };
382 static void test_FPropCompareProp(void)
384 SPropValue pvLeft, pvRight;
386 char lbuffa[2], rbuffa[2];
387 WCHAR lbuffw[2], rbuffw[2];
391 pFPropCompareProp = (void*)GetProcAddress(hMapi32, "FPropCompareProp@12");
393 if (!pFPropCompareProp)
401 for (i = 0; i < sizeof(ptTypes)/sizeof(ptTypes[0]); i++)
403 pvLeft.ulPropTag = pvRight.ulPropTag = ptTypes[i];
405 for (j = 0; j < sizeof(FPCProp_Results)/sizeof(FPCProp_Results[0]); j++)
407 SHORT lVal = FPCProp_Results[j].lVal;
408 SHORT rVal = FPCProp_Results[j].rVal;
410 bExp = FPCProp_Results[j].bRet;
415 /* Boolean values have no concept of less or greater than, only equality */
416 if ((lVal == 1 && rVal == 2 && FPCProp_Results[j].relOp == RELOP_LT) ||
417 (lVal == 2 && rVal == 1 && FPCProp_Results[j].relOp == RELOP_LE)||
418 (lVal == 2 && rVal == 1 && FPCProp_Results[j].relOp == RELOP_GT)||
419 (lVal == 1 && rVal == 2 && FPCProp_Results[j].relOp == RELOP_GE)||
420 (lVal == 1 && rVal == 2 && FPCProp_Results[j].relOp == RELOP_EQ)||
421 (lVal == 2 && rVal == 1 && FPCProp_Results[j].relOp == RELOP_EQ))
423 /* Fall through ... */
425 pvLeft.Value.i = lVal;
426 pvRight.Value.i = rVal;
430 pvLeft.Value.l = lVal;
431 pvRight.Value.l = rVal;
434 pvLeft.Value.flt = lVal;
435 pvRight.Value.flt = rVal;
439 pvLeft.Value.dbl = lVal;
440 pvRight.Value.dbl = rVal;
443 pvLeft.Value.cur.int64 = lVal;
444 pvRight.Value.cur.int64 = rVal;
447 pvLeft.Value.ft.dwLowDateTime = lVal;
448 pvLeft.Value.ft.dwHighDateTime = 0;
449 pvRight.Value.ft.dwLowDateTime = rVal;
450 pvRight.Value.ft.dwHighDateTime = 0;
453 pvLeft.Value.li.u.LowPart = lVal;
454 pvLeft.Value.li.u.HighPart = 0;
455 pvRight.Value.li.u.LowPart = rVal;
456 pvRight.Value.li.u.HighPart = 0;
459 memset(&lguid, 0, sizeof(GUID));
460 memset(&rguid, 0, sizeof(GUID));
461 lguid.Data4[7] = lVal;
462 rguid.Data4[7] = rVal;
463 pvLeft.Value.lpguid = &lguid;
464 pvRight.Value.lpguid = &rguid;
467 pvLeft.Value.lpszA = lbuffa;
468 pvRight.Value.lpszA = rbuffa;
469 lbuffa[0] = '0' + lVal;
470 rbuffa[0] = '0' + rVal;
473 pvLeft.Value.lpszW = lbuffw;
474 pvRight.Value.lpszW = rbuffw;
475 lbuffw[0] = '0' + lVal;
476 rbuffw[0] = '0' + rVal;
479 pvLeft.Value.bin.cb = 1;
480 pvRight.Value.bin.cb = 1;
481 pvLeft.Value.bin.lpb = lbuffa;
482 pvRight.Value.bin.lpb = rbuffa;
488 bRet = pFPropCompareProp(&pvLeft, FPCProp_Results[j].relOp, &pvRight);
489 ok(bRet == bExp, "pt %ld (%d,%d,%s): expected %d, got %d\n", ptTypes[i],
490 FPCProp_Results[j].lVal, FPCProp_Results[j].rVal,
491 relops[FPCProp_Results[j].relOp], bExp, bRet);
496 typedef struct tagLPropCompareProp_Result
501 } LPropCompareProp_Result;
503 static const LPropCompareProp_Result LPCProp_Results[] =
510 static void test_LPropCompareProp(void)
512 SPropValue pvLeft, pvRight;
514 char lbuffa[2], rbuffa[2];
515 WCHAR lbuffw[2], rbuffw[2];
519 pLPropCompareProp = (void*)GetProcAddress(hMapi32, "LPropCompareProp@8");
521 if (!pLPropCompareProp)
529 for (i = 0; i < sizeof(ptTypes)/sizeof(ptTypes[0]); i++)
531 pvLeft.ulPropTag = pvRight.ulPropTag = ptTypes[i];
533 for (j = 0; j < sizeof(LPCProp_Results)/sizeof(LPCProp_Results[0]); j++)
535 SHORT lVal = LPCProp_Results[j].lVal;
536 SHORT rVal = LPCProp_Results[j].rVal;
538 iExp = LPCProp_Results[j].iRet;
543 /* Boolean values have no concept of less or greater than, only equality */
546 /* Fall through ... */
548 pvLeft.Value.i = lVal;
549 pvRight.Value.i = rVal;
553 pvLeft.Value.l = lVal;
554 pvRight.Value.l = rVal;
557 pvLeft.Value.flt = lVal;
558 pvRight.Value.flt = rVal;
562 pvLeft.Value.dbl = lVal;
563 pvRight.Value.dbl = rVal;
566 pvLeft.Value.cur.int64 = lVal;
567 pvRight.Value.cur.int64 = rVal;
570 pvLeft.Value.ft.dwLowDateTime = lVal;
571 pvLeft.Value.ft.dwHighDateTime = 0;
572 pvRight.Value.ft.dwLowDateTime = rVal;
573 pvRight.Value.ft.dwHighDateTime = 0;
576 pvLeft.Value.li.u.LowPart = lVal;
577 pvLeft.Value.li.u.HighPart = 0;
578 pvRight.Value.li.u.LowPart = rVal;
579 pvRight.Value.li.u.HighPart = 0;
582 memset(&lguid, 0, sizeof(GUID));
583 memset(&rguid, 0, sizeof(GUID));
584 lguid.Data4[7] = lVal;
585 rguid.Data4[7] = rVal;
586 pvLeft.Value.lpguid = &lguid;
587 pvRight.Value.lpguid = &rguid;
590 pvLeft.Value.lpszA = lbuffa;
591 pvRight.Value.lpszA = rbuffa;
592 lbuffa[0] = '0' + lVal;
593 rbuffa[0] = '0' + rVal;
596 pvLeft.Value.lpszW = lbuffw;
597 pvRight.Value.lpszW = rbuffw;
598 lbuffw[0] = '0' + lVal;
599 rbuffw[0] = '0' + rVal;
602 pvLeft.Value.bin.cb = 1;
603 pvRight.Value.bin.cb = 1;
604 pvLeft.Value.bin.lpb = lbuffa;
605 pvRight.Value.bin.lpb = rbuffa;
611 iRet = pLPropCompareProp(&pvLeft, &pvRight);
612 ok(iRet == iExp, "pt %ld (%d,%d): expected %d, got %d\n", ptTypes[i],
613 LPCProp_Results[j].lVal, LPCProp_Results[j].rVal, iExp, iRet);
618 static void test_PpropFindProp(void)
620 SPropValue pvProp, *pRet;
623 pPpropFindProp = (void*)GetProcAddress(hMapi32, "PpropFindProp@12");
628 for (i = 0; i < sizeof(ptTypes)/sizeof(ptTypes[0]); i++)
630 pvProp.ulPropTag = ptTypes[i];
632 pRet = pPpropFindProp(&pvProp, 1u, ptTypes[i]);
633 ok(pRet == &pvProp, "PpropFindProp[%ld]: Didn't find existing propery\n",
636 pRet = pPpropFindProp(&pvProp, 1u, i ? ptTypes[i-1] : ptTypes[i+1]);
637 ok(pRet == NULL, "PpropFindProp[%ld]: Found non-existing propery\n",
641 pvProp.ulPropTag = PROP_TAG(PT_I2, 1u);
642 pRet = pPpropFindProp(&pvProp, 1u, PROP_TAG(PT_UNSPECIFIED, 0u));
643 ok(pRet == NULL, "PpropFindProp[UNSPECIFIED]: Matched on different id\n");
644 pRet = pPpropFindProp(&pvProp, 1u, PROP_TAG(PT_UNSPECIFIED, 1u));
645 ok(pRet == &pvProp, "PpropFindProp[UNSPECIFIED]: Didn't match id\n");
648 static void test_ScCountProps(void)
650 static const char *szHiA = "Hi!";
651 static const WCHAR szHiW[] = { 'H', 'i', '!', '\0' };
652 static const ULONG ULHILEN = 4; /* chars in szHiA/W incl. NUL */
656 GUID iids[4], *iid = iids;
658 ULONG pt, exp, ulRet;
661 pScCountProps = (void*)GetProcAddress(hMapi32, "ScCountProps@12");
666 for (pt = 0; pt < PROP_ID_INVALID && success; pt++)
670 memset(&pv, 0 ,sizeof(pv));
671 pv.ulPropTag = PROP_TAG(pt, 1u);
673 switch (PROP_TYPE(pt))
689 pv.Value.lpguid = iid;
690 exp = sizeof(GUID) + sizeof(pv);
693 pv.Value.lpszA = (LPSTR)szHiA;
694 exp = 4 + sizeof(pv);
697 pv.Value.lpszW = (LPWSTR)szHiW;
698 exp = 4 * sizeof(WCHAR) + sizeof(pv);
702 pv.Value.bin.lpb = (LPBYTE)iid;
703 exp = 2 + sizeof(pv);
706 pv.Value.MVi.cValues = 3;
707 pv.Value.MVi.lpi = (SHORT*)iid;
708 exp = 3 * sizeof(SHORT) + sizeof(pv);
711 pv.Value.MVl.cValues = 3;
712 pv.Value.MVl.lpl = (LONG*)iid;
713 exp = 3 * sizeof(LONG) + sizeof(pv);
716 pv.Value.MVli.cValues = 3;
717 pv.Value.MVli.lpli = (LARGE_INTEGER*)iid;
718 exp = 3 * sizeof(LARGE_INTEGER) + sizeof(pv);
721 pv.Value.MVflt.cValues = 3;
722 pv.Value.MVflt.lpflt = (float*)iid;
723 exp = 3 * sizeof(float) + sizeof(pv);
727 pv.Value.MVdbl.cValues = 3;
728 pv.Value.MVdbl.lpdbl = (double*)iid;
729 exp = 3 * sizeof(double) + sizeof(pv);
732 pv.Value.MVcur.cValues = 3;
733 pv.Value.MVcur.lpcur = (CY*)iid;
734 exp = 3 * sizeof(CY) + sizeof(pv);
737 pv.Value.MVft.cValues = 3;
738 pv.Value.MVft.lpft = (FILETIME*)iid;
739 exp = 3 * sizeof(CY) + sizeof(pv);
743 pv.Value.MVszA.cValues = 3;
744 pv.Value.MVszA.lppszA = buffa;
745 buffa[0] = (LPSTR)szHiA;
746 buffa[1] = (LPSTR)szHiA;
747 buffa[2] = (LPSTR)szHiA;
748 exp = ULHILEN * 3 + 3 * sizeof(char*) + sizeof(pv);
751 pv.Value.MVszW.cValues = 3;
752 pv.Value.MVszW.lppszW = buffw;
753 buffw[0] = (LPWSTR)szHiW;
754 buffw[1] = (LPWSTR)szHiW;
755 buffw[2] = (LPWSTR)szHiW;
756 exp = ULHILEN * 3 * sizeof(WCHAR) + 3 * sizeof(WCHAR*) + sizeof(pv);
759 pv.Value.MVbin.cValues = 3;
760 pv.Value.MVbin.lpbin = buffbin;
762 buffbin[0].lpb = (LPBYTE)&iid;
764 buffbin[1].lpb = (LPBYTE)&iid;
766 buffbin[2].lpb = (LPBYTE)&iid;
767 exp = 20 + sizeof(pv) + sizeof(SBinary) * 3;
774 res = pScCountProps(1, &pv, &ulRet);
776 success = res == MAPI_E_INVALID_PARAMETER && ulRet == 0xffffffff;
777 ok(success, "pt= %ld: Expected failure, got %ld, ret=0x%08lX\n",
781 success = res == S_OK && ulRet == exp;
782 ok(success, "pt= %ld: Expected %ld, got %ld, ret=0x%08lX\n",
783 pt, exp, ulRet, res);
789 static void test_ScCopyRelocProps(void)
791 static const char* szTestA = "Test";
792 char buffer[512], buffer2[512], *lppszA[1];
793 SPropValue pvProp, *lpResProp = (LPSPropValue)buffer;
797 pScCopyProps = (void*)GetProcAddress(hMapi32, "ScCopyProps@16");
798 pScRelocProps = (void*)GetProcAddress(hMapi32, "ScRelocProps@20");
800 if (!pScCopyProps || !pScRelocProps)
803 pvProp.ulPropTag = PROP_TAG(PT_MV_STRING8, 1u);
805 lppszA[0] = (char *)szTestA;
806 pvProp.Value.MVszA.cValues = 1;
807 pvProp.Value.MVszA.lppszA = lppszA;
810 sc = pScCopyProps(1, &pvProp, buffer, &ulCount);
811 ok(sc == S_OK && lpResProp->ulPropTag == pvProp.ulPropTag &&
812 lpResProp->Value.MVszA.cValues == 1 &&
813 lpResProp->Value.MVszA.lppszA[0] == buffer + sizeof(SPropValue) + sizeof(char*) &&
814 !strcmp(lpResProp->Value.MVszA.lppszA[0], szTestA) &&
815 ulCount == sizeof(SPropValue) + sizeof(char*) + 5,
816 "CopyProps(str): Expected 0 {1,%lx,%p,%s} %d got 0x%08lx {%ld,%lx,%p,%s} %ld\n",
817 pvProp.ulPropTag, buffer + sizeof(SPropValue) + sizeof(char*),
818 szTestA, sizeof(SPropValue) + sizeof(char*) + 5, sc,
819 lpResProp->Value.MVszA.cValues, lpResProp->ulPropTag,
820 lpResProp->Value.MVszA.lppszA[0], sc==S_OK?lpResProp->Value.MVszA.lppszA[0]:NULL, ulCount);
822 memcpy(buffer2, buffer, sizeof(buffer));
824 /* Clear the data in the source buffer. Since pointers in the copied buffer
825 * refer to the source buffer, this proves that native always assumes that
826 * the copied buffers pointers are bad (needing to be relocated first).
828 memset(buffer, 0, sizeof(buffer));
831 sc = pScRelocProps(1, (LPSPropValue)buffer2, buffer, buffer2, &ulCount);
832 lpResProp = (LPSPropValue)buffer2;
833 ok(sc == S_OK && lpResProp->ulPropTag == pvProp.ulPropTag &&
834 lpResProp->Value.MVszA.cValues == 1 &&
835 lpResProp->Value.MVszA.lppszA[0] == buffer2 + sizeof(SPropValue) + sizeof(char*) &&
836 !strcmp(lpResProp->Value.MVszA.lppszA[0], szTestA) &&
837 /* Native has a bug whereby it calculates the size correctly when copying
838 * but when relocating does not (presumably it uses UlPropSize() which
839 * ignores multivalue pointers). Wine returns the correct value.
841 (ulCount == sizeof(SPropValue) + sizeof(char*) + 5 || ulCount == sizeof(SPropValue) + 5),
842 "RelocProps(str): Expected 0 {1,%lx,%p,%s} %d got 0x%08lx {%ld,%lx,%p,%s} %ld\n",
843 pvProp.ulPropTag, buffer2 + sizeof(SPropValue) + sizeof(char*),
844 szTestA, sizeof(SPropValue) + sizeof(char*) + 5, sc,
845 lpResProp->Value.MVszA.cValues, lpResProp->ulPropTag,
846 lpResProp->Value.MVszA.lppszA[0], sc==S_OK?lpResProp->Value.MVszA.lppszA[0]:NULL, ulCount);
848 /* Native crashes with lpNew or lpOld set to NULL so skip testing this */
851 static void test_LpValFindProp(void)
853 SPropValue pvProp, *pRet;
856 pLpValFindProp = (void*)GetProcAddress(hMapi32, "LpValFindProp@12");
861 for (i = 0; i < sizeof(ptTypes)/sizeof(ptTypes[0]); i++)
863 pvProp.ulPropTag = PROP_TAG(ptTypes[i], 1u);
865 pRet = pLpValFindProp(PROP_TAG(ptTypes[i], 1u), 1u, &pvProp);
866 ok(pRet == &pvProp, "LpValFindProp[%ld]: Didn't find existing propery id/type\n",
869 pRet = pLpValFindProp(PROP_TAG(ptTypes[i], 0u), 1u, &pvProp);
870 ok(pRet == NULL, "LpValFindProp[%ld]: Found non-existing propery id\n",
873 pRet = pLpValFindProp(PROP_TAG(PT_NULL, 0u), 1u, &pvProp);
874 ok(pRet == NULL, "LpValFindProp[%ld]: Found non-existing propery id/type\n",
877 pRet = pLpValFindProp(PROP_TAG(PT_NULL, 1u), 1u, &pvProp);
878 ok(pRet == &pvProp, "LpValFindProp[%ld]: Didn't find existing propery id\n",
883 static void test_FBadRglpszA(void)
886 char *szString = "A String";
889 pFBadRglpszA = (void*)GetProcAddress(hMapi32, "FBadRglpszA@8");
893 bRet = pFBadRglpszA(NULL, 10);
894 ok(bRet == TRUE, "FBadRglpszA(Null): expected TRUE, got FALSE\n");
896 lpStrs[0] = lpStrs[1] = lpStrs[2] = lpStrs[3] = NULL;
897 bRet = pFBadRglpszA(lpStrs, 4);
898 ok(bRet == TRUE, "FBadRglpszA(Nulls): expected TRUE, got FALSE\n");
900 lpStrs[0] = lpStrs[1] = lpStrs[2] = szString;
901 bRet = pFBadRglpszA(lpStrs, 3);
902 ok(bRet == FALSE, "FBadRglpszA(valid): expected FALSE, got TRUE\n");
904 bRet = pFBadRglpszA(lpStrs, 4);
905 ok(bRet == TRUE, "FBadRglpszA(1 invalid): expected TRUE, got FALSE\n");
908 static void test_FBadRglpszW(void)
911 WCHAR szString[] = { 'A',' ','S','t','r','i','n','g','\0' };
914 pFBadRglpszW = (void*)GetProcAddress(hMapi32, "FBadRglpszW@8");
918 bRet = pFBadRglpszW(NULL, 10);
919 ok(bRet == TRUE, "FBadRglpszW(Null): expected TRUE, got FALSE\n");
921 lpStrs[0] = lpStrs[1] = lpStrs[2] = lpStrs[3] = NULL;
922 bRet = pFBadRglpszW(lpStrs, 4);
923 ok(bRet == TRUE, "FBadRglpszW(Nulls): expected TRUE, got FALSE\n");
925 lpStrs[0] = lpStrs[1] = lpStrs[2] = szString;
926 bRet = pFBadRglpszW(lpStrs, 3);
927 ok(bRet == FALSE, "FBadRglpszW(valid): expected FALSE, got TRUE\n");
929 bRet = pFBadRglpszW(lpStrs, 4);
930 ok(bRet == TRUE, "FBadRglpszW(1 invalid): expected TRUE, got FALSE\n");
933 static void test_FBadRowSet(void)
937 pFBadRowSet = (void*)GetProcAddress(hMapi32, "FBadRowSet@4");
941 ulRet = pFBadRowSet(NULL);
942 ok(ulRet != 0, "FBadRow(null): Expected non-zero, got 0\n");
947 static void test_FBadPropTag(void)
951 pFBadPropTag = (void*)GetProcAddress(hMapi32, "FBadPropTag@4");
955 for (pt = 0; pt < PROP_ID_INVALID; pt++)
959 switch (pt & (~MV_FLAG & PROP_TYPE_MASK))
962 case PT_NULL: case PT_I2: case PT_I4: case PT_R4:
963 case PT_R8: case PT_CURRENCY: case PT_APPTIME:
964 case PT_ERROR: case PT_BOOLEAN: case PT_OBJECT:
965 case PT_I8: case PT_STRING8: case PT_UNICODE:
966 case PT_SYSTIME: case PT_CLSID: case PT_BINARY:
970 res = pFBadPropTag(pt);
972 ok(res != 0, "pt= %ld: Expected non-zero, got 0\n", pt);
974 ok(res == 0, "pt= %ld: Expected zero, got %ld\n", pt, res);
978 static void test_FBadRow(void)
982 pFBadRow = (void*)GetProcAddress(hMapi32, "FBadRow@4");
986 ulRet = pFBadRow(NULL);
987 ok(ulRet != 0, "FBadRow(null): Expected non-zero, got 0\n");
992 static void test_FBadProp(void)
994 WCHAR szEmpty[] = { '\0' };
999 pFBadProp = (void*)GetProcAddress(hMapi32, "FBadProp@4");
1003 for (pt = 0; pt < PROP_ID_INVALID; pt++)
1007 memset(&pv, 0, sizeof(pv));
1010 /* Note that MV values are valid below because their array count is 0,
1011 * so no pointers are validated.
1013 switch (PROP_TYPE(pt))
1015 case (MV_FLAG|PT_UNSPECIFIED):
1016 case PT_UNSPECIFIED:
1017 case (MV_FLAG|PT_NULL):
1029 case PT_MV_CURRENCY:
1033 case (MV_FLAG|PT_ERROR):
1035 case (MV_FLAG|PT_BOOLEAN):
1037 case (MV_FLAG|PT_OBJECT):
1050 pv.Value.lpszW = szEmpty;
1054 pv.Value.lpguid = &iid;
1059 res = pFBadProp(&pv);
1061 ok(res != 0, "pt= %ld: Expected non-zero, got 0\n", pt);
1063 ok(res == 0, "pt= %ld: Expected zero, got %ld\n", pt, res);
1067 static void test_FBadColumnSet(void)
1072 pFBadColumnSet = (void*)GetProcAddress(hMapi32, "FBadColumnSet@4");
1073 if (!pFBadColumnSet)
1076 res = pFBadColumnSet(NULL);
1077 ok(res != 0, "(null): Expected non-zero, got 0\n");
1081 for (pt = 0; pt < PROP_ID_INVALID; pt++)
1085 pta.aulPropTag[0] = pt;
1087 switch (pt & (~MV_FLAG & PROP_TYPE_MASK))
1089 case PT_UNSPECIFIED:
1107 if (pt == (MV_FLAG|PT_ERROR))
1110 res = pFBadColumnSet(&pta);
1112 ok(res != 0, "pt= %ld: Expected non-zero, got 0\n", pt);
1114 ok(res == 0, "pt= %ld: Expected zero, got %ld\n", pt, res);
1120 hMapi32 = LoadLibraryA("mapi32.dll");
1122 pScInitMapiUtil = (void*)GetProcAddress(hMapi32, "ScInitMapiUtil@4");
1123 if (!pScInitMapiUtil)
1127 test_PropCopyMore();
1129 test_FPropContainsProp();
1130 test_FPropCompareProp();
1131 test_LPropCompareProp();
1132 test_PpropFindProp();
1133 test_ScCountProps();
1134 test_ScCopyRelocProps();
1135 test_LpValFindProp();
1142 test_FBadColumnSet();