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