Implement A->W call for GetNamedSecurityInfo.
[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
660     pScCountProps = (void*)GetProcAddress(hMapi32, "ScCountProps@12");
661
662     if (!pScCountProps)
663         return;
664
665     for (pt = 0; pt < PROP_ID_INVALID; pt++)
666     {
667         SPropValue pv;
668
669         memset(&pv, 0 ,sizeof(pv));
670         pv.ulPropTag = PROP_TAG(pt, 1u);
671
672         switch (PROP_TYPE(pt))
673         {
674         case PT_I2:       
675         case PT_I4:     
676         case PT_R4:       
677         case PT_R8:   
678         case PT_CURRENCY: 
679         case PT_APPTIME:  
680         case PT_SYSTIME:  
681         case PT_ERROR:    
682         case PT_BOOLEAN:  
683         case PT_OBJECT:   
684         case PT_I8:       
685             exp = sizeof(pv);
686             break;
687         case PT_CLSID:
688             pv.Value.lpguid = iid;
689             exp = sizeof(GUID) + sizeof(pv);
690             break;
691         case PT_STRING8:
692             pv.Value.lpszA = (LPSTR)szHiA;
693             exp = 4 + sizeof(pv);
694             break;
695         case PT_UNICODE:
696             pv.Value.lpszW = (LPWSTR)szHiW;
697             exp = 4 * sizeof(WCHAR) + sizeof(pv);
698             break;
699         case PT_BINARY:
700             pv.Value.bin.cb = 2;
701             pv.Value.bin.lpb = (LPBYTE)iid;
702             exp = 2 + sizeof(pv);
703             break;
704         case PT_MV_I2:
705             pv.Value.MVi.cValues = 3;
706             pv.Value.MVi.lpi = (SHORT*)iid;
707             exp = 3 * sizeof(SHORT) + sizeof(pv);
708             break;
709         case PT_MV_I4:
710             pv.Value.MVl.cValues = 3;
711             pv.Value.MVl.lpl = (LONG*)iid;
712             exp = 3 * sizeof(LONG) + sizeof(pv);
713             break;
714         case PT_MV_I8:
715             pv.Value.MVli.cValues = 3;
716             pv.Value.MVli.lpli = (LARGE_INTEGER*)iid;
717             exp = 3 * sizeof(LARGE_INTEGER) + sizeof(pv);
718             break;
719         case PT_MV_R4:
720             pv.Value.MVflt.cValues = 3;
721             pv.Value.MVflt.lpflt = (float*)iid;
722             exp = 3 * sizeof(float) + sizeof(pv);
723             break;
724         case PT_MV_APPTIME:
725         case PT_MV_R8:
726             pv.Value.MVdbl.cValues = 3;
727             pv.Value.MVdbl.lpdbl = (double*)iid;
728             exp = 3 * sizeof(double) + sizeof(pv);
729             break;
730         case PT_MV_CURRENCY:
731             pv.Value.MVcur.cValues = 3;
732             pv.Value.MVcur.lpcur = (CY*)iid;
733             exp = 3 * sizeof(CY) + sizeof(pv);
734             break;
735         case PT_MV_SYSTIME:
736             pv.Value.MVft.cValues = 3;
737             pv.Value.MVft.lpft = (FILETIME*)iid;
738             exp = 3 * sizeof(CY) + sizeof(pv);
739             break;
740             break;
741         case PT_MV_STRING8:
742             pv.Value.MVszA.cValues = 3;
743             pv.Value.MVszA.lppszA = buffa;
744             buffa[0] = (LPSTR)szHiA;
745             buffa[1] = (LPSTR)szHiA;
746             buffa[2] = (LPSTR)szHiA;
747             exp = ULHILEN * 3 + 3 * sizeof(char*) + sizeof(pv);
748             break;
749         case PT_MV_UNICODE:
750             pv.Value.MVszW.cValues = 3;
751             pv.Value.MVszW.lppszW = buffw;
752             buffw[0] = (LPWSTR)szHiW;
753             buffw[1] = (LPWSTR)szHiW;
754             buffw[2] = (LPWSTR)szHiW;
755             exp = ULHILEN * 3 * sizeof(WCHAR) + 3 * sizeof(WCHAR*) + sizeof(pv);
756             break;
757         case PT_MV_BINARY:
758             pv.Value.MVbin.cValues = 3;
759             pv.Value.MVbin.lpbin = buffbin;
760             buffbin[0].cb = 17;
761             buffbin[0].lpb = (LPBYTE)&iid;
762             buffbin[1].cb = 2;
763             buffbin[1].lpb = (LPBYTE)&iid;
764             buffbin[2].cb = 1;
765             buffbin[2].lpb = (LPBYTE)&iid;
766             exp = 20 + sizeof(pv) + sizeof(SBinary) * 3;
767             break;
768         default:
769             exp = 0;
770         }
771
772         ulRet = 0xffffffff;
773         res = pScCountProps(1, &pv, &ulRet);
774         if (!exp)
775             ok(res == MAPI_E_INVALID_PARAMETER && ulRet == 0xffffffff,
776                "pt= %ld: Expected failure, got %ld, ret=0x%08lX\n", pt, ulRet, res);
777         else
778             ok(res == S_OK && ulRet == exp, "pt= %ld: Expected %ld, got %ld, ret=0x%08lX\n", 
779                pt, exp, ulRet, res);
780     }
781
782 }
783
784 static void test_ScCopyRelocProps(void)
785 {
786     static const char* szTestA = "Test";
787     char buffer[512], buffer2[512], *lppszA[1];
788     SPropValue pvProp, *lpResProp = (LPSPropValue)buffer;
789     ULONG ulCount;
790     SCODE sc;
791        
792     pScCopyProps = (void*)GetProcAddress(hMapi32, "ScCopyProps@16");
793     pScRelocProps = (void*)GetProcAddress(hMapi32, "ScRelocProps@20");
794
795     if (!pScCopyProps || !pScRelocProps)
796         return;
797
798     pvProp.ulPropTag = PROP_TAG(PT_MV_STRING8, 1u);
799         
800     lppszA[0] = (char *)szTestA;
801     pvProp.Value.MVszA.cValues = 1;
802     pvProp.Value.MVszA.lppszA = lppszA;
803     ulCount = 0;
804     
805     sc = pScCopyProps(1, &pvProp, buffer, &ulCount);    
806     ok(sc == S_OK && lpResProp->ulPropTag == pvProp.ulPropTag &&
807        lpResProp->Value.MVszA.cValues == 1 && 
808        lpResProp->Value.MVszA.lppszA[0] == buffer + sizeof(SPropValue) + sizeof(char*) &&
809        !strcmp(lpResProp->Value.MVszA.lppszA[0], szTestA) &&
810        ulCount == sizeof(SPropValue) + sizeof(char*) + 5,
811        "CopyProps(str): Expected 0 {1,%lx,%p,%s} %d got 0x%08lx {%ld,%lx,%p,%s} %ld\n",
812        pvProp.ulPropTag, buffer + sizeof(SPropValue) + sizeof(char*),
813        szTestA, sizeof(SPropValue) + sizeof(char*) + 5, sc, 
814        lpResProp->Value.MVszA.cValues, lpResProp->ulPropTag,
815        lpResProp->Value.MVszA.lppszA[0], sc==S_OK?lpResProp->Value.MVszA.lppszA[0]:NULL, ulCount);
816
817     memcpy(buffer2, buffer, sizeof(buffer));
818     
819     /* Clear the data in the source buffer. Since pointers in the copied buffer
820      * refer to the source buffer, this proves that native always assumes that
821      * the copied buffers pointers are bad (needing to be relocated first).
822      */
823     memset(buffer, 0, sizeof(buffer));
824     ulCount = 0;
825        
826     sc = pScRelocProps(1, (LPSPropValue)buffer2, buffer, buffer2, &ulCount);
827     lpResProp = (LPSPropValue)buffer2;
828     ok(sc == S_OK && lpResProp->ulPropTag == pvProp.ulPropTag &&
829        lpResProp->Value.MVszA.cValues == 1 && 
830        lpResProp->Value.MVszA.lppszA[0] == buffer2 + sizeof(SPropValue) + sizeof(char*) &&
831        !strcmp(lpResProp->Value.MVszA.lppszA[0], szTestA) &&
832        /* Native has a bug whereby it calculates the size correctly when copying
833         * but when relocating does not (presumably it uses UlPropSize() which
834         * ignores multivalue pointers). Wine returns the correct value.
835         */
836        (ulCount == sizeof(SPropValue) + sizeof(char*) + 5 || ulCount == sizeof(SPropValue) + 5),
837        "RelocProps(str): Expected 0 {1,%lx,%p,%s} %d got 0x%08lx {%ld,%lx,%p,%s} %ld\n",
838        pvProp.ulPropTag, buffer2 + sizeof(SPropValue) + sizeof(char*),
839        szTestA, sizeof(SPropValue) + sizeof(char*) + 5, sc, 
840        lpResProp->Value.MVszA.cValues, lpResProp->ulPropTag,
841        lpResProp->Value.MVszA.lppszA[0], sc==S_OK?lpResProp->Value.MVszA.lppszA[0]:NULL, ulCount);
842
843     /* Native crashes with lpNew or lpOld set to NULL so skip testing this */   
844 }
845
846 static void test_LpValFindProp(void)
847 {
848     SPropValue pvProp, *pRet;
849     ULONG i;
850
851     pLpValFindProp = (void*)GetProcAddress(hMapi32, "LpValFindProp@12");
852
853     if (!pLpValFindProp)
854         return;
855     
856     for (i = 0; i < sizeof(ptTypes)/sizeof(ptTypes[0]); i++)
857     {
858         pvProp.ulPropTag = PROP_TAG(ptTypes[i], 1u);
859
860         pRet = pLpValFindProp(PROP_TAG(ptTypes[i], 1u), 1u, &pvProp);
861         ok(pRet == &pvProp, "LpValFindProp[%ld]: Didn't find existing propery id/type\n",
862            ptTypes[i]);
863
864         pRet = pLpValFindProp(PROP_TAG(ptTypes[i], 0u), 1u, &pvProp);
865         ok(pRet == NULL, "LpValFindProp[%ld]: Found non-existing propery id\n",
866            ptTypes[i]);
867            
868         pRet = pLpValFindProp(PROP_TAG(PT_NULL, 0u), 1u, &pvProp);
869         ok(pRet == NULL, "LpValFindProp[%ld]: Found non-existing propery id/type\n",
870            ptTypes[i]);
871         
872         pRet = pLpValFindProp(PROP_TAG(PT_NULL, 1u), 1u, &pvProp);
873         ok(pRet == &pvProp, "LpValFindProp[%ld]: Didn't find existing propery id\n",
874            ptTypes[i]);
875     }
876 }
877
878 static void test_FBadRglpszA(void)
879 {
880     LPSTR lpStrs[4];
881     char *szString = "A String";
882     BOOL bRet;
883     
884     pFBadRglpszA = (void*)GetProcAddress(hMapi32, "FBadRglpszA@8");
885     if (!pFBadRglpszA)
886         return;
887     
888     bRet = pFBadRglpszA(NULL, 10);
889     ok(bRet == TRUE, "FBadRglpszA(Null): expected TRUE, got FALSE\n"); 
890     
891     lpStrs[0] = lpStrs[1] = lpStrs[2] = lpStrs[3] = NULL;
892     bRet = pFBadRglpszA(lpStrs, 4);
893     ok(bRet == TRUE, "FBadRglpszA(Nulls): expected TRUE, got FALSE\n"); 
894
895     lpStrs[0] = lpStrs[1] = lpStrs[2] = szString;
896     bRet = pFBadRglpszA(lpStrs, 3);
897     ok(bRet == FALSE, "FBadRglpszA(valid): expected FALSE, got TRUE\n"); 
898     
899     bRet = pFBadRglpszA(lpStrs, 4);
900     ok(bRet == TRUE, "FBadRglpszA(1 invalid): expected TRUE, got FALSE\n"); 
901 }
902
903 static void test_FBadRglpszW(void)
904 {
905     LPWSTR lpStrs[4];
906     WCHAR szString[] = { 'A',' ','S','t','r','i','n','g','\0' };
907     BOOL bRet;
908     
909     pFBadRglpszW = (void*)GetProcAddress(hMapi32, "FBadRglpszW@8");
910     if (!pFBadRglpszW)
911         return;
912     
913     bRet = pFBadRglpszW(NULL, 10);
914     ok(bRet == TRUE, "FBadRglpszW(Null): expected TRUE, got FALSE\n"); 
915     
916     lpStrs[0] = lpStrs[1] = lpStrs[2] = lpStrs[3] = NULL;
917     bRet = pFBadRglpszW(lpStrs, 4);
918     ok(bRet == TRUE, "FBadRglpszW(Nulls): expected TRUE, got FALSE\n"); 
919
920     lpStrs[0] = lpStrs[1] = lpStrs[2] = szString;
921     bRet = pFBadRglpszW(lpStrs, 3);
922     ok(bRet == FALSE, "FBadRglpszW(valid): expected FALSE, got TRUE\n"); 
923     
924     bRet = pFBadRglpszW(lpStrs, 4);
925     ok(bRet == TRUE, "FBadRglpszW(1 invalid): expected TRUE, got FALSE\n"); 
926 }
927
928 static void test_FBadRowSet(void)
929 {
930     ULONG ulRet;
931     
932     pFBadRowSet = (void*)GetProcAddress(hMapi32, "FBadRowSet@4");
933     if (!pFBadRowSet)
934         return;
935     
936     ulRet = pFBadRowSet(NULL);
937     ok(ulRet != 0, "FBadRow(null): Expected non-zero, got 0\n");
938     
939     /* FIXME */
940 }
941
942 static void test_FBadPropTag(void)
943 {
944     ULONG pt, res;
945
946     pFBadPropTag = (void*)GetProcAddress(hMapi32, "FBadPropTag@4");
947     if (!pFBadPropTag)
948         return;
949
950     for (pt = 0; pt < PROP_ID_INVALID; pt++)
951     {
952         BOOL bBad = TRUE;
953
954         switch (pt & (~MV_FLAG & PROP_TYPE_MASK))
955         {
956         case PT_UNSPECIFIED:
957         case PT_NULL: case PT_I2: case PT_I4: case PT_R4:
958         case PT_R8: case PT_CURRENCY: case PT_APPTIME:
959         case PT_ERROR: case PT_BOOLEAN: case PT_OBJECT:
960         case PT_I8: case PT_STRING8: case PT_UNICODE:
961         case PT_SYSTIME: case PT_CLSID: case PT_BINARY:
962             bBad = FALSE;
963         }
964
965         res = pFBadPropTag(pt);
966         if (bBad)
967             ok(res != 0, "pt= %ld: Expected non-zero, got 0\n", pt);
968         else
969             ok(res == 0, "pt= %ld: Expected zero, got %ld\n", pt, res);
970     }
971 }
972
973 static void test_FBadRow(void)
974 {
975     ULONG ulRet;
976     
977     pFBadRow = (void*)GetProcAddress(hMapi32, "FBadRow@4");
978     if (!pFBadRow)
979         return;
980     
981     ulRet = pFBadRow(NULL);
982     ok(ulRet != 0, "FBadRow(null): Expected non-zero, got 0\n");
983
984     /* FIXME */
985 }
986
987 static void test_FBadProp(void)
988 {
989     WCHAR szEmpty[] = { '\0' };
990     GUID iid;
991     ULONG pt, res;
992     SPropValue pv;
993     
994     pFBadProp = (void*)GetProcAddress(hMapi32, "FBadProp@4");
995     if (!pFBadProp)
996         return;
997
998     for (pt = 0; pt < PROP_ID_INVALID; pt++)
999     {
1000         BOOL bBad = TRUE;
1001
1002         memset(&pv, 0, sizeof(pv));
1003         pv.ulPropTag = pt;
1004
1005         /* Note that MV values are valid below because their array count is 0,
1006          * so no pointers are validated.
1007          */        
1008         switch (PROP_TYPE(pt))
1009         {
1010         case (MV_FLAG|PT_UNSPECIFIED):
1011         case PT_UNSPECIFIED:
1012         case (MV_FLAG|PT_NULL): 
1013         case PT_NULL: 
1014         case PT_MV_I2:
1015         case PT_I2:
1016         case PT_MV_I4:
1017         case PT_I4:
1018         case PT_MV_I8:
1019         case PT_I8:
1020         case PT_MV_R4:
1021         case PT_R4:
1022         case PT_MV_R8:
1023         case PT_R8:
1024         case PT_MV_CURRENCY:
1025         case PT_CURRENCY:
1026         case PT_MV_APPTIME:
1027         case PT_APPTIME:
1028         case (MV_FLAG|PT_ERROR):
1029         case PT_ERROR:
1030         case (MV_FLAG|PT_BOOLEAN):
1031         case PT_BOOLEAN:
1032         case (MV_FLAG|PT_OBJECT):
1033         case PT_OBJECT:
1034         case PT_MV_STRING8:
1035         case PT_MV_UNICODE:
1036         case PT_MV_SYSTIME:
1037         case PT_SYSTIME:
1038         case PT_MV_BINARY:
1039         case PT_BINARY:
1040         case PT_MV_CLSID:
1041             bBad = FALSE;
1042             break;
1043         case PT_STRING8:
1044         case PT_UNICODE:
1045             pv.Value.lpszW = szEmpty;
1046             bBad = FALSE;
1047             break;
1048         case PT_CLSID:
1049             pv.Value.lpguid = &iid;
1050             bBad = FALSE;
1051             break;
1052         }
1053
1054         res = pFBadProp(&pv);
1055         if (bBad)
1056             ok(res != 0, "pt= %ld: Expected non-zero, got 0\n", pt);
1057         else
1058             ok(res == 0, "pt= %ld: Expected zero, got %ld\n", pt, res);
1059     }
1060 }
1061
1062 static void test_FBadColumnSet(void)
1063 {
1064     SPropTagArray pta;
1065     ULONG pt, res;
1066
1067     pFBadColumnSet = (void*)GetProcAddress(hMapi32, "FBadColumnSet@4");
1068     if (!pFBadColumnSet)
1069         return;
1070
1071     res = pFBadColumnSet(NULL);
1072     ok(res != 0, "(null): Expected non-zero, got 0\n");
1073
1074     pta.cValues = 1;
1075
1076     for (pt = 0; pt < PROP_ID_INVALID; pt++)
1077     {
1078         BOOL bBad = TRUE;
1079
1080         pta.aulPropTag[0] = pt;
1081
1082         switch (pt & (~MV_FLAG & PROP_TYPE_MASK))
1083         {
1084         case PT_UNSPECIFIED:
1085         case PT_NULL:
1086         case PT_I2:
1087         case PT_I4:
1088         case PT_R4:
1089         case PT_R8:
1090         case PT_CURRENCY:
1091         case PT_APPTIME:
1092         case PT_BOOLEAN:
1093         case PT_OBJECT:
1094         case PT_I8:
1095         case PT_STRING8:
1096         case PT_UNICODE:
1097         case PT_SYSTIME:
1098         case PT_CLSID:
1099         case PT_BINARY:
1100             bBad = FALSE;
1101         }
1102         if (pt == (MV_FLAG|PT_ERROR))
1103             bBad = FALSE;
1104
1105         res = pFBadColumnSet(&pta);
1106         if (bBad)
1107             ok(res != 0, "pt= %ld: Expected non-zero, got 0\n", pt);
1108         else
1109             ok(res == 0, "pt= %ld: Expected zero, got %ld\n", pt, res);
1110     }
1111 }
1112
1113 START_TEST(prop)
1114 {  
1115     hMapi32 = LoadLibraryA("mapi32.dll");
1116     
1117     pScInitMapiUtil = (void*)GetProcAddress(hMapi32, "ScInitMapiUtil@4");
1118     if (!pScInitMapiUtil)
1119         return;
1120     pScInitMapiUtil(0);
1121
1122     test_PropCopyMore();
1123     test_UlPropSize();
1124     test_FPropContainsProp();
1125     test_FPropCompareProp();
1126     test_LPropCompareProp();
1127     test_PpropFindProp();
1128     test_ScCountProps();
1129     test_ScCopyRelocProps();
1130     test_LpValFindProp();
1131     test_FBadRglpszA();
1132     test_FBadRglpszW();
1133     test_FBadRowSet();
1134     test_FBadPropTag();
1135     test_FBadRow();
1136     test_FBadProp();
1137     test_FBadColumnSet();
1138 }