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