Removed W->A from DEFWND_ImmIsUIMessageW.
[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 HRESULT WINAPI MAPIInitialize(LPVOID);
33
34 static HMODULE hMapi32 = 0;
35
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);
54
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,
58     PT_UNICODE
59 };
60
61 static inline int strcmpW(const WCHAR *str1, const WCHAR *str2)
62 {
63     while (*str1 && (*str1 == *str2)) { str1++; str2++; }
64     return *str1 - *str2;
65 }
66
67 static void test_PropCopyMore(void)
68 {
69     static const char *szHiA = "Hi!";
70     static const WCHAR szHiW[] = { 'H', 'i', '!', '\0' };
71     SPropValue *lpDest = NULL, *lpSrc = NULL;
72     ULONG i;
73     SCODE scode;
74     
75     pPropCopyMore = (void*)GetProcAddress(hMapi32, "PropCopyMore@16");
76
77     if (!pPropCopyMore)
78         return;
79
80     scode = MAPIAllocateBuffer(sizeof(LPSPropValue), (LPVOID *)lpDest);
81     if (FAILED(scode))
82         return;
83         
84     scode = MAPIAllocateMore(sizeof(LPSPropValue), lpDest, (LPVOID *)lpSrc);
85     if (FAILED(scode))
86         return;
87
88     for (i = 0; i < sizeof(ptTypes)/sizeof(ptTypes[0]); i++)
89     {
90         lpSrc->ulPropTag = ptTypes[i];
91         
92         switch (ptTypes[i])
93         {
94         case PT_STRING8:
95             lpSrc->Value.lpszA = (char*)szHiA;
96             break;
97         case PT_UNICODE:
98             lpSrc->Value.lpszW = (WCHAR*)szHiW;
99             break;
100         case PT_BINARY:
101             lpSrc->Value.bin.cb = 4;
102             lpSrc->Value.bin.lpb = (LPBYTE)szHiA;
103             break;
104         }
105
106         memset(lpDest, 0xff, sizeof(SPropValue));
107         
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))
113         {
114             switch (ptTypes[i])
115             {
116             case PT_STRING8:
117                 ok(lstrcmpA(lpDest->Value.lpszA, lpSrc->Value.lpszA) == 0,
118                    "PropCopyMore: Ascii string differs\n");
119                 break;
120             case PT_UNICODE:
121                 ok(strcmpW(lpDest->Value.lpszW, lpSrc->Value.lpszW) == 0,
122                    "PropCopyMore: Unicode string differs\n");
123                 break;
124             case PT_BINARY:
125                 ok(lpDest->Value.bin.cb == 4 && 
126                    !memcmp(lpSrc->Value.bin.lpb, lpDest->Value.bin.lpb, 4),
127                    "PropCopyMore: Binary array  differs\n");
128                 break;
129             }
130         }
131     }
132     
133     /* Since all allocations are linked, freeing lpDest frees everything */
134     MAPIFreeBuffer(lpDest);
135 }
136
137 static void test_UlPropSize(void)
138 {
139     static const char *szHiA = "Hi!";
140     static const WCHAR szHiW[] = { 'H', 'i', '!', '\0' };
141     LPSTR  buffa[2];
142     LPWSTR buffw[2];
143     SBinary buffbin[2];
144     ULONG pt, exp, res;
145
146     pUlPropSize = (void*)GetProcAddress(hMapi32, "UlPropSize@4");
147
148     if (!pUlPropSize)
149         return;
150
151     for (pt = 0; pt < PROP_ID_INVALID; pt++)
152     {
153         SPropValue pv;
154
155         memset(&pv, 0 ,sizeof(pv));
156         pv.ulPropTag = pt;
157         
158         exp = 1u; /* Default to one item for non-MV properties */
159         
160         switch (PROP_TYPE(pt))
161         {
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;
181 #if 0        
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.
185          */
186         case PT_MV_CLSID:    pv.Value.MVguid.cValues = exp = 2;
187 #endif
188         case PT_CLSID:       exp *= sizeof(GUID); break;
189         case PT_STRING8:
190             pv.Value.lpszA = (LPSTR)szHiA;
191             exp = 4;
192             break;
193         case PT_UNICODE:
194             pv.Value.lpszW = (LPWSTR)szHiW;
195             exp = 4 * sizeof(WCHAR);
196             break;
197         case PT_BINARY:
198             pv.Value.bin.cb = exp = 19;
199             break;
200         case PT_MV_STRING8:
201             pv.Value.MVszA.cValues = 2;
202             pv.Value.MVszA.lppszA = buffa;
203             buffa[0] = (LPSTR)szHiA;
204             buffa[1] = (LPSTR)szHiA;
205             exp = 8;
206             break;
207         case PT_MV_UNICODE:
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);
213             break;
214         case PT_MV_BINARY:
215             pv.Value.MVbin.cValues = 2;
216             pv.Value.MVbin.lpbin = buffbin;
217             buffbin[0].cb = 19;
218             buffbin[1].cb = 1;
219             exp = 20;
220             break;
221         default:
222             exp = 0;
223         }
224
225         res = pUlPropSize(&pv);
226         ok(res == exp, "pt= %ld: Expected %ld, got %ld\n", pt, exp, res);
227     }
228 }
229
230 static void test_FPropContainsProp(void)
231 {
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;
239     ULONG pt;
240     BOOL bRet;
241
242     pFPropContainsProp = (void*)GetProcAddress(hMapi32, "FPropContainsProp@12");
243
244     if (!pFPropContainsProp)
245         return;
246
247     /* Ensure that only PT_STRING8 and PT_BINARY are handled */
248     for (pt = 0; pt < PROP_ID_INVALID; pt++)
249     {
250         if (pt == PT_STRING8 || pt == PT_BINARY)
251             continue; /* test these later */
252
253         memset(&pvLeft, 0 ,sizeof(pvLeft));
254         memset(&pvRight, 0 ,sizeof(pvRight));
255         pvLeft.ulPropTag = pvRight.ulPropTag = pt;
256
257         bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
258         ok(bRet == FALSE, "pt= %ld: Expected FALSE, got %d\n", pt, bRet);
259     }
260
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;
265
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");
303
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);
308
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");
351 }
352
353 typedef struct tagFPropCompareProp_Result
354 {
355     SHORT lVal;
356     SHORT rVal;
357     ULONG relOp;
358     BOOL  bRet;
359 } FPropCompareProp_Result;
360
361 static const FPropCompareProp_Result FPCProp_Results[] =
362 {
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 }
378 };
379
380 static const char *relops[] = { "RELOP_LT", "RELOP_LE", "RELOP_GT", "RELOP_GE", "RELOP_EQ" };
381
382 static void test_FPropCompareProp(void)
383 {
384     SPropValue pvLeft, pvRight;
385     GUID lguid, rguid;
386     char lbuffa[2], rbuffa[2];
387     WCHAR lbuffw[2], rbuffw[2];
388     ULONG i, j;
389     BOOL bRet, bExp;
390
391     pFPropCompareProp = (void*)GetProcAddress(hMapi32, "FPropCompareProp@12");
392
393     if (!pFPropCompareProp)
394         return;
395
396     lbuffa[1] = '\0';
397     rbuffa[1] = '\0';
398     lbuffw[1] = '\0';
399     rbuffw[1] = '\0';
400
401     for (i = 0; i < sizeof(ptTypes)/sizeof(ptTypes[0]); i++)
402     {
403         pvLeft.ulPropTag = pvRight.ulPropTag = ptTypes[i];
404
405         for (j = 0; j < sizeof(FPCProp_Results)/sizeof(FPCProp_Results[0]); j++)
406         {
407             SHORT lVal = FPCProp_Results[j].lVal;
408             SHORT rVal = FPCProp_Results[j].rVal;
409
410             bExp = FPCProp_Results[j].bRet;
411
412             switch (ptTypes[i])
413             {
414             case PT_BOOLEAN:
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))
422                     bExp = !bExp;
423                     /* Fall through ... */
424             case PT_I2:
425                 pvLeft.Value.i = lVal;
426                 pvRight.Value.i = rVal;
427                 break;
428             case PT_ERROR:
429             case PT_I4:
430                 pvLeft.Value.l = lVal;
431                 pvRight.Value.l = rVal;
432                 break;
433             case PT_R4:
434                 pvLeft.Value.flt = lVal;
435                 pvRight.Value.flt = rVal;
436                 break;
437             case PT_APPTIME:
438             case PT_R8:
439                 pvLeft.Value.dbl = lVal;
440                 pvRight.Value.dbl = rVal;
441                 break;
442             case PT_CURRENCY:
443                 pvLeft.Value.cur.int64 = lVal;
444                 pvRight.Value.cur.int64 = rVal;
445                 break;
446             case PT_SYSTIME:
447                 pvLeft.Value.ft.dwLowDateTime = lVal;
448                 pvLeft.Value.ft.dwHighDateTime = 0;
449                 pvRight.Value.ft.dwLowDateTime = rVal;
450                 pvRight.Value.ft.dwHighDateTime = 0;
451                 break;
452             case PT_I8:
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;
457                 break;
458             case PT_CLSID:
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;
465                 break;
466             case PT_STRING8:
467                 pvLeft.Value.lpszA = lbuffa;
468                 pvRight.Value.lpszA = rbuffa;
469                 lbuffa[0] = '0' + lVal;
470                 rbuffa[0] = '0' + rVal;
471                 break;
472             case PT_UNICODE:
473                 pvLeft.Value.lpszW = lbuffw;
474                 pvRight.Value.lpszW = rbuffw;
475                 lbuffw[0] = '0' + lVal;
476                 rbuffw[0] = '0' + rVal;
477                 break;
478             case PT_BINARY:
479                 pvLeft.Value.bin.cb = 1;
480                 pvRight.Value.bin.cb = 1;
481                 pvLeft.Value.bin.lpb = lbuffa;
482                 pvRight.Value.bin.lpb = rbuffa;
483                 lbuffa[0] = lVal;
484                 rbuffa[0] = rVal;
485                 break;
486             }
487
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);
492         }
493     }
494 }
495
496 typedef struct tagLPropCompareProp_Result
497 {
498     SHORT lVal;
499     SHORT rVal;
500     INT   iRet;
501 } LPropCompareProp_Result;
502
503 static const LPropCompareProp_Result LPCProp_Results[] =
504 {
505     { 1, 2, -1 },
506     { 1, 1, 0 },
507     { 2, 1, 1 },
508 };
509
510 static void test_LPropCompareProp(void)
511 {
512     SPropValue pvLeft, pvRight;
513     GUID lguid, rguid;
514     char lbuffa[2], rbuffa[2];
515     WCHAR lbuffw[2], rbuffw[2];
516     ULONG i, j;
517     INT iRet, iExp;
518
519     pLPropCompareProp = (void*)GetProcAddress(hMapi32, "LPropCompareProp@8");
520
521     if (!pLPropCompareProp)
522         return;
523
524     lbuffa[1] = '\0';
525     rbuffa[1] = '\0';
526     lbuffw[1] = '\0';
527     rbuffw[1] = '\0';
528
529     for (i = 0; i < sizeof(ptTypes)/sizeof(ptTypes[0]); i++)
530     {
531         pvLeft.ulPropTag = pvRight.ulPropTag = ptTypes[i];
532
533         for (j = 0; j < sizeof(LPCProp_Results)/sizeof(LPCProp_Results[0]); j++)
534         {
535             SHORT lVal = LPCProp_Results[j].lVal;
536             SHORT rVal = LPCProp_Results[j].rVal;
537
538             iExp = LPCProp_Results[j].iRet;
539
540             switch (ptTypes[i])
541             {
542             case PT_BOOLEAN:
543                 /* Boolean values have no concept of less or greater than, only equality */
544                 if (lVal && rVal)
545                     iExp = 0;
546                     /* Fall through ... */
547             case PT_I2:
548                 pvLeft.Value.i = lVal;
549                 pvRight.Value.i = rVal;
550                 break;
551             case PT_ERROR:
552             case PT_I4:
553                 pvLeft.Value.l = lVal;
554                 pvRight.Value.l = rVal;
555                 break;
556             case PT_R4:
557                 pvLeft.Value.flt = lVal;
558                 pvRight.Value.flt = rVal;
559                 break;
560             case PT_APPTIME:
561             case PT_R8:
562                 pvLeft.Value.dbl = lVal;
563                 pvRight.Value.dbl = rVal;
564                 break;
565             case PT_CURRENCY:
566                 pvLeft.Value.cur.int64 = lVal;
567                 pvRight.Value.cur.int64 = rVal;
568                 break;
569             case PT_SYSTIME:
570                 pvLeft.Value.ft.dwLowDateTime = lVal;
571                 pvLeft.Value.ft.dwHighDateTime = 0;
572                 pvRight.Value.ft.dwLowDateTime = rVal;
573                 pvRight.Value.ft.dwHighDateTime = 0;
574                 break;
575             case PT_I8:
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;
580                 break;
581             case PT_CLSID:
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;
588                 break;
589             case PT_STRING8:
590                 pvLeft.Value.lpszA = lbuffa;
591                 pvRight.Value.lpszA = rbuffa;
592                 lbuffa[0] = '0' + lVal;
593                 rbuffa[0] = '0' + rVal;
594                 break;
595             case PT_UNICODE:
596                 pvLeft.Value.lpszW = lbuffw;
597                 pvRight.Value.lpszW = rbuffw;
598                 lbuffw[0] = '0' + lVal;
599                 rbuffw[0] = '0' + rVal;
600                 break;
601             case PT_BINARY:
602                 pvLeft.Value.bin.cb = 1;
603                 pvRight.Value.bin.cb = 1;
604                 pvLeft.Value.bin.lpb = lbuffa;
605                 pvRight.Value.bin.lpb = rbuffa;
606                 lbuffa[0] = lVal;
607                 rbuffa[0] = rVal;
608                 break;
609             }
610
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);
614         }
615     }
616 }
617
618 static void test_PpropFindProp(void)
619 {
620     SPropValue pvProp, *pRet;
621     ULONG i;
622
623     pPpropFindProp = (void*)GetProcAddress(hMapi32, "PpropFindProp@12");
624
625     if (!pPpropFindProp)
626         return;
627     
628     for (i = 0; i < sizeof(ptTypes)/sizeof(ptTypes[0]); i++)
629     {
630         pvProp.ulPropTag = ptTypes[i];
631
632         pRet = pPpropFindProp(&pvProp, 1u, ptTypes[i]);
633         ok(pRet == &pvProp, "PpropFindProp[%ld]: Didn't find existing propery\n",
634            ptTypes[i]);
635
636         pRet = pPpropFindProp(&pvProp, 1u, i ? ptTypes[i-1] : ptTypes[i+1]);
637         ok(pRet == NULL, "PpropFindProp[%ld]: Found non-existing propery\n",
638            ptTypes[i]);
639     }
640
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");
646 }
647
648 static void test_ScCountProps(void)
649 {
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 */
653     LPSTR  buffa[3];
654     LPWSTR buffw[3];
655     SBinary buffbin[3];
656     GUID iids[4], *iid = iids;
657     SCODE res;
658     ULONG pt, exp, ulRet;
659     int success = 1;
660
661     pScCountProps = (void*)GetProcAddress(hMapi32, "ScCountProps@12");
662
663     if (!pScCountProps)
664         return;
665
666     for (pt = 0; pt < PROP_ID_INVALID && success; pt++)
667     {
668         SPropValue pv;
669
670         memset(&pv, 0 ,sizeof(pv));
671         pv.ulPropTag = PROP_TAG(pt, 1u);
672
673         switch (PROP_TYPE(pt))
674         {
675         case PT_I2:       
676         case PT_I4:     
677         case PT_R4:       
678         case PT_R8:   
679         case PT_CURRENCY: 
680         case PT_APPTIME:  
681         case PT_SYSTIME:  
682         case PT_ERROR:    
683         case PT_BOOLEAN:  
684         case PT_OBJECT:   
685         case PT_I8:       
686             exp = sizeof(pv);
687             break;
688         case PT_CLSID:
689             pv.Value.lpguid = iid;
690             exp = sizeof(GUID) + sizeof(pv);
691             break;
692         case PT_STRING8:
693             pv.Value.lpszA = (LPSTR)szHiA;
694             exp = 4 + sizeof(pv);
695             break;
696         case PT_UNICODE:
697             pv.Value.lpszW = (LPWSTR)szHiW;
698             exp = 4 * sizeof(WCHAR) + sizeof(pv);
699             break;
700         case PT_BINARY:
701             pv.Value.bin.cb = 2;
702             pv.Value.bin.lpb = (LPBYTE)iid;
703             exp = 2 + sizeof(pv);
704             break;
705         case PT_MV_I2:
706             pv.Value.MVi.cValues = 3;
707             pv.Value.MVi.lpi = (SHORT*)iid;
708             exp = 3 * sizeof(SHORT) + sizeof(pv);
709             break;
710         case PT_MV_I4:
711             pv.Value.MVl.cValues = 3;
712             pv.Value.MVl.lpl = (LONG*)iid;
713             exp = 3 * sizeof(LONG) + sizeof(pv);
714             break;
715         case PT_MV_I8:
716             pv.Value.MVli.cValues = 3;
717             pv.Value.MVli.lpli = (LARGE_INTEGER*)iid;
718             exp = 3 * sizeof(LARGE_INTEGER) + sizeof(pv);
719             break;
720         case PT_MV_R4:
721             pv.Value.MVflt.cValues = 3;
722             pv.Value.MVflt.lpflt = (float*)iid;
723             exp = 3 * sizeof(float) + sizeof(pv);
724             break;
725         case PT_MV_APPTIME:
726         case PT_MV_R8:
727             pv.Value.MVdbl.cValues = 3;
728             pv.Value.MVdbl.lpdbl = (double*)iid;
729             exp = 3 * sizeof(double) + sizeof(pv);
730             break;
731         case PT_MV_CURRENCY:
732             pv.Value.MVcur.cValues = 3;
733             pv.Value.MVcur.lpcur = (CY*)iid;
734             exp = 3 * sizeof(CY) + sizeof(pv);
735             break;
736         case PT_MV_SYSTIME:
737             pv.Value.MVft.cValues = 3;
738             pv.Value.MVft.lpft = (FILETIME*)iid;
739             exp = 3 * sizeof(CY) + sizeof(pv);
740             break;
741             break;
742         case PT_MV_STRING8:
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);
749             break;
750         case PT_MV_UNICODE:
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);
757             break;
758         case PT_MV_BINARY:
759             pv.Value.MVbin.cValues = 3;
760             pv.Value.MVbin.lpbin = buffbin;
761             buffbin[0].cb = 17;
762             buffbin[0].lpb = (LPBYTE)&iid;
763             buffbin[1].cb = 2;
764             buffbin[1].lpb = (LPBYTE)&iid;
765             buffbin[2].cb = 1;
766             buffbin[2].lpb = (LPBYTE)&iid;
767             exp = 20 + sizeof(pv) + sizeof(SBinary) * 3;
768             break;
769         default:
770             exp = 0;
771         }
772
773         ulRet = 0xffffffff;
774         res = pScCountProps(1, &pv, &ulRet);
775         if (!exp) {
776             success = res == MAPI_E_INVALID_PARAMETER && ulRet == 0xffffffff;
777             ok(success, "pt= %ld: Expected failure, got %ld, ret=0x%08lX\n",
778                pt, ulRet, res);
779         }
780         else {
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);
784         }
785     }
786
787 }
788
789 static void test_ScCopyRelocProps(void)
790 {
791     static const char* szTestA = "Test";
792     char buffer[512], buffer2[512], *lppszA[1];
793     SPropValue pvProp, *lpResProp = (LPSPropValue)buffer;
794     ULONG ulCount;
795     SCODE sc;
796        
797     pScCopyProps = (void*)GetProcAddress(hMapi32, "ScCopyProps@16");
798     pScRelocProps = (void*)GetProcAddress(hMapi32, "ScRelocProps@20");
799
800     if (!pScCopyProps || !pScRelocProps)
801         return;
802
803     pvProp.ulPropTag = PROP_TAG(PT_MV_STRING8, 1u);
804         
805     lppszA[0] = (char *)szTestA;
806     pvProp.Value.MVszA.cValues = 1;
807     pvProp.Value.MVszA.lppszA = lppszA;
808     ulCount = 0;
809     
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);
821
822     memcpy(buffer2, buffer, sizeof(buffer));
823     
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).
827      */
828     memset(buffer, 0, sizeof(buffer));
829     ulCount = 0;
830        
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.
840         */
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);
847
848     /* Native crashes with lpNew or lpOld set to NULL so skip testing this */   
849 }
850
851 static void test_LpValFindProp(void)
852 {
853     SPropValue pvProp, *pRet;
854     ULONG i;
855
856     pLpValFindProp = (void*)GetProcAddress(hMapi32, "LpValFindProp@12");
857
858     if (!pLpValFindProp)
859         return;
860     
861     for (i = 0; i < sizeof(ptTypes)/sizeof(ptTypes[0]); i++)
862     {
863         pvProp.ulPropTag = PROP_TAG(ptTypes[i], 1u);
864
865         pRet = pLpValFindProp(PROP_TAG(ptTypes[i], 1u), 1u, &pvProp);
866         ok(pRet == &pvProp, "LpValFindProp[%ld]: Didn't find existing propery id/type\n",
867            ptTypes[i]);
868
869         pRet = pLpValFindProp(PROP_TAG(ptTypes[i], 0u), 1u, &pvProp);
870         ok(pRet == NULL, "LpValFindProp[%ld]: Found non-existing propery id\n",
871            ptTypes[i]);
872            
873         pRet = pLpValFindProp(PROP_TAG(PT_NULL, 0u), 1u, &pvProp);
874         ok(pRet == NULL, "LpValFindProp[%ld]: Found non-existing propery id/type\n",
875            ptTypes[i]);
876         
877         pRet = pLpValFindProp(PROP_TAG(PT_NULL, 1u), 1u, &pvProp);
878         ok(pRet == &pvProp, "LpValFindProp[%ld]: Didn't find existing propery id\n",
879            ptTypes[i]);
880     }
881 }
882
883 static void test_FBadRglpszA(void)
884 {
885     LPSTR lpStrs[4];
886     char *szString = "A String";
887     BOOL bRet;
888     
889     pFBadRglpszA = (void*)GetProcAddress(hMapi32, "FBadRglpszA@8");
890     if (!pFBadRglpszA)
891         return;
892     
893     bRet = pFBadRglpszA(NULL, 10);
894     ok(bRet == TRUE, "FBadRglpszA(Null): expected TRUE, got FALSE\n"); 
895     
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"); 
899
900     lpStrs[0] = lpStrs[1] = lpStrs[2] = szString;
901     bRet = pFBadRglpszA(lpStrs, 3);
902     ok(bRet == FALSE, "FBadRglpszA(valid): expected FALSE, got TRUE\n"); 
903     
904     bRet = pFBadRglpszA(lpStrs, 4);
905     ok(bRet == TRUE, "FBadRglpszA(1 invalid): expected TRUE, got FALSE\n"); 
906 }
907
908 static void test_FBadRglpszW(void)
909 {
910     LPWSTR lpStrs[4];
911     WCHAR szString[] = { 'A',' ','S','t','r','i','n','g','\0' };
912     BOOL bRet;
913     
914     pFBadRglpszW = (void*)GetProcAddress(hMapi32, "FBadRglpszW@8");
915     if (!pFBadRglpszW)
916         return;
917     
918     bRet = pFBadRglpszW(NULL, 10);
919     ok(bRet == TRUE, "FBadRglpszW(Null): expected TRUE, got FALSE\n"); 
920     
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"); 
924
925     lpStrs[0] = lpStrs[1] = lpStrs[2] = szString;
926     bRet = pFBadRglpszW(lpStrs, 3);
927     ok(bRet == FALSE, "FBadRglpszW(valid): expected FALSE, got TRUE\n"); 
928     
929     bRet = pFBadRglpszW(lpStrs, 4);
930     ok(bRet == TRUE, "FBadRglpszW(1 invalid): expected TRUE, got FALSE\n"); 
931 }
932
933 static void test_FBadRowSet(void)
934 {
935     ULONG ulRet;
936     
937     pFBadRowSet = (void*)GetProcAddress(hMapi32, "FBadRowSet@4");
938     if (!pFBadRowSet)
939         return;
940     
941     ulRet = pFBadRowSet(NULL);
942     ok(ulRet != 0, "FBadRow(null): Expected non-zero, got 0\n");
943     
944     /* FIXME */
945 }
946
947 static void test_FBadPropTag(void)
948 {
949     ULONG pt, res;
950
951     pFBadPropTag = (void*)GetProcAddress(hMapi32, "FBadPropTag@4");
952     if (!pFBadPropTag)
953         return;
954
955     for (pt = 0; pt < PROP_ID_INVALID; pt++)
956     {
957         BOOL bBad = TRUE;
958
959         switch (pt & (~MV_FLAG & PROP_TYPE_MASK))
960         {
961         case PT_UNSPECIFIED:
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:
967             bBad = FALSE;
968         }
969
970         res = pFBadPropTag(pt);
971         if (bBad)
972             ok(res != 0, "pt= %ld: Expected non-zero, got 0\n", pt);
973         else
974             ok(res == 0, "pt= %ld: Expected zero, got %ld\n", pt, res);
975     }
976 }
977
978 static void test_FBadRow(void)
979 {
980     ULONG ulRet;
981     
982     pFBadRow = (void*)GetProcAddress(hMapi32, "FBadRow@4");
983     if (!pFBadRow)
984         return;
985     
986     ulRet = pFBadRow(NULL);
987     ok(ulRet != 0, "FBadRow(null): Expected non-zero, got 0\n");
988
989     /* FIXME */
990 }
991
992 static void test_FBadProp(void)
993 {
994     WCHAR szEmpty[] = { '\0' };
995     GUID iid;
996     ULONG pt, res;
997     SPropValue pv;
998     
999     pFBadProp = (void*)GetProcAddress(hMapi32, "FBadProp@4");
1000     if (!pFBadProp)
1001         return;
1002
1003     for (pt = 0; pt < PROP_ID_INVALID; pt++)
1004     {
1005         BOOL bBad = TRUE;
1006
1007         memset(&pv, 0, sizeof(pv));
1008         pv.ulPropTag = pt;
1009
1010         /* Note that MV values are valid below because their array count is 0,
1011          * so no pointers are validated.
1012          */        
1013         switch (PROP_TYPE(pt))
1014         {
1015         case (MV_FLAG|PT_UNSPECIFIED):
1016         case PT_UNSPECIFIED:
1017         case (MV_FLAG|PT_NULL): 
1018         case PT_NULL: 
1019         case PT_MV_I2:
1020         case PT_I2:
1021         case PT_MV_I4:
1022         case PT_I4:
1023         case PT_MV_I8:
1024         case PT_I8:
1025         case PT_MV_R4:
1026         case PT_R4:
1027         case PT_MV_R8:
1028         case PT_R8:
1029         case PT_MV_CURRENCY:
1030         case PT_CURRENCY:
1031         case PT_MV_APPTIME:
1032         case PT_APPTIME:
1033         case (MV_FLAG|PT_ERROR):
1034         case PT_ERROR:
1035         case (MV_FLAG|PT_BOOLEAN):
1036         case PT_BOOLEAN:
1037         case (MV_FLAG|PT_OBJECT):
1038         case PT_OBJECT:
1039         case PT_MV_STRING8:
1040         case PT_MV_UNICODE:
1041         case PT_MV_SYSTIME:
1042         case PT_SYSTIME:
1043         case PT_MV_BINARY:
1044         case PT_BINARY:
1045         case PT_MV_CLSID:
1046             bBad = FALSE;
1047             break;
1048         case PT_STRING8:
1049         case PT_UNICODE:
1050             pv.Value.lpszW = szEmpty;
1051             bBad = FALSE;
1052             break;
1053         case PT_CLSID:
1054             pv.Value.lpguid = &iid;
1055             bBad = FALSE;
1056             break;
1057         }
1058
1059         res = pFBadProp(&pv);
1060         if (bBad)
1061             ok(res != 0, "pt= %ld: Expected non-zero, got 0\n", pt);
1062         else
1063             ok(res == 0, "pt= %ld: Expected zero, got %ld\n", pt, res);
1064     }
1065 }
1066
1067 static void test_FBadColumnSet(void)
1068 {
1069     SPropTagArray pta;
1070     ULONG pt, res;
1071
1072     pFBadColumnSet = (void*)GetProcAddress(hMapi32, "FBadColumnSet@4");
1073     if (!pFBadColumnSet)
1074         return;
1075
1076     res = pFBadColumnSet(NULL);
1077     ok(res != 0, "(null): Expected non-zero, got 0\n");
1078
1079     pta.cValues = 1;
1080
1081     for (pt = 0; pt < PROP_ID_INVALID; pt++)
1082     {
1083         BOOL bBad = TRUE;
1084
1085         pta.aulPropTag[0] = pt;
1086
1087         switch (pt & (~MV_FLAG & PROP_TYPE_MASK))
1088         {
1089         case PT_UNSPECIFIED:
1090         case PT_NULL:
1091         case PT_I2:
1092         case PT_I4:
1093         case PT_R4:
1094         case PT_R8:
1095         case PT_CURRENCY:
1096         case PT_APPTIME:
1097         case PT_BOOLEAN:
1098         case PT_OBJECT:
1099         case PT_I8:
1100         case PT_STRING8:
1101         case PT_UNICODE:
1102         case PT_SYSTIME:
1103         case PT_CLSID:
1104         case PT_BINARY:
1105             bBad = FALSE;
1106         }
1107         if (pt == (MV_FLAG|PT_ERROR))
1108             bBad = FALSE;
1109
1110         res = pFBadColumnSet(&pta);
1111         if (bBad)
1112             ok(res != 0, "pt= %ld: Expected non-zero, got 0\n", pt);
1113         else
1114             ok(res == 0, "pt= %ld: Expected zero, got %ld\n", pt, res);
1115     }
1116 }
1117
1118 START_TEST(prop)
1119 {  
1120     hMapi32 = LoadLibraryA("mapi32.dll");
1121     
1122     pScInitMapiUtil = (void*)GetProcAddress(hMapi32, "ScInitMapiUtil@4");
1123     if (!pScInitMapiUtil)
1124         return;
1125     pScInitMapiUtil(0);
1126
1127     test_PropCopyMore();
1128     test_UlPropSize();
1129     test_FPropContainsProp();
1130     test_FPropCompareProp();
1131     test_LPropCompareProp();
1132     test_PpropFindProp();
1133     test_ScCountProps();
1134     test_ScCopyRelocProps();
1135     test_LpValFindProp();
1136     test_FBadRglpszA();
1137     test_FBadRglpszW();
1138     test_FBadRowSet();
1139     test_FBadPropTag();
1140     test_FBadRow();
1141     test_FBadProp();
1142     test_FBadColumnSet();
1143 }