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