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