[OLE32_WINETEST] Sync with Wine Staging 4.0. CORE-15682
[reactos.git] / modules / rostests / winetests / ole32 / stg_prop.c
1 /* IPropertyStorage unit tests
2 * Copyright 2005 Juan Lang
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18 #include <stdio.h>
19 #define COBJMACROS
20 #include "objbase.h"
21 #include "wine/test.h"
22
23 #ifndef PID_BEHAVIOR
24 #define PID_BEHAVIOR 0x80000003
25 #endif
26
27 static HRESULT (WINAPI *pFmtIdToPropStgName)(const FMTID *, LPOLESTR);
28 static HRESULT (WINAPI *pPropStgNameToFmtId)(const LPOLESTR, FMTID *);
29 static HRESULT (WINAPI *pStgCreatePropSetStg)(IStorage *, DWORD, IPropertySetStorage **);
30 static HRESULT (WINAPI *pStgCreatePropStg)(IUnknown *, REFFMTID, const CLSID *, DWORD, DWORD, IPropertyStorage **);
31 static HRESULT (WINAPI *pStgOpenPropStg)(IUnknown *, REFFMTID, DWORD, DWORD, IPropertyStorage **);
32
33 static void init_function_pointers(void)
34 {
35 HMODULE hmod = GetModuleHandleA("ole32.dll");
36 pFmtIdToPropStgName = (void*)GetProcAddress(hmod, "FmtIdToPropStgName");
37 pPropStgNameToFmtId = (void*)GetProcAddress(hmod, "PropStgNameToFmtId");
38 pStgCreatePropSetStg = (void*)GetProcAddress(hmod, "StgCreatePropSetStg");
39 pStgCreatePropStg = (void*)GetProcAddress(hmod, "StgCreatePropStg");
40 pStgOpenPropStg = (void*)GetProcAddress(hmod, "StgOpenPropStg");
41 }
42
43 /* FIXME: this creates an ANSI storage, try to find conditions under which
44 * Unicode translation fails
45 */
46 static void testPropsHelper(IPropertySetStorage **propSetStorage)
47 {
48 static const WCHAR szDot[] = { '.',0 };
49 static const WCHAR szPrefix[] = { 's','t','g',0 };
50 static const WCHAR szSummaryInfo[] = { 5,'S','u','m','m','a','r','y',
51 'I','n','f','o','r','m','a','t','i','o','n',0 };
52 static WCHAR propName[] = { 'p','r','o','p',0 };
53 static char val[] = "l33t auth0r";
54 WCHAR filename[MAX_PATH];
55 HRESULT hr;
56 IStorage *storage = NULL;
57 IStream *stream = NULL;
58 IPropertyStorage *propertyStorage = NULL;
59 PROPSPEC spec;
60 PROPVARIANT var;
61 CLIPDATA clipdata;
62 unsigned char clipcontent[] = "foobar";
63 GUID anyOldGuid = { 0x12345678,0xdead,0xbeef, {
64 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 } };
65
66 if(propSetStorage)
67 trace("Testing property storage with a set...\n");
68 else
69 trace("Testing property storage without a set...\n");
70
71 if(!GetTempFileNameW(szDot, szPrefix, 0, filename))
72 return;
73
74 DeleteFileW(filename);
75
76 hr = StgCreateDocfile(filename,
77 STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE, 0, &storage);
78 ok(hr == S_OK, "StgCreateDocfile failed: 0x%08x\n", hr);
79
80 if(propSetStorage)
81 {
82 if(!pStgCreatePropSetStg)
83 {
84 IStorage_Release(storage);
85 DeleteFileW(filename);
86 return;
87 }
88 hr = pStgCreatePropSetStg(storage, 0, propSetStorage);
89 ok(hr == S_OK, "StgCreatePropSetStg failed: 0x%08x\n", hr);
90
91 hr = IPropertySetStorage_Create(*propSetStorage,
92 &FMTID_SummaryInformation, NULL, PROPSETFLAG_ANSI,
93 STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE,
94 &propertyStorage);
95 ok(hr == S_OK, "IPropertySetStorage_Create failed: 0x%08x\n", hr);
96 }
97 else
98 {
99 hr = IStorage_CreateStream(storage, szSummaryInfo,
100 STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stream);
101 ok(hr == S_OK, "IStorage_CreateStream failed: 0x%08x\n", hr);
102
103 if(!pStgCreatePropStg)
104 {
105 IStorage_Release(storage);
106 IUnknown_Release(stream);
107 DeleteFileW(filename);
108 return;
109 }
110 hr = pStgCreatePropStg((IUnknown *)stream, &FMTID_SummaryInformation,
111 NULL, PROPSETFLAG_ANSI, 0, &propertyStorage);
112 ok(hr == S_OK, "StgCreatePropStg failed: 0x%08x\n", hr);
113 }
114
115 hr = IPropertyStorage_WriteMultiple(propertyStorage, 0, NULL, NULL, 0);
116 ok(hr == S_OK, "WriteMultiple with 0 args failed: 0x%08x\n", hr);
117 hr = IPropertyStorage_WriteMultiple(propertyStorage, 1, NULL, NULL, 0);
118 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got 0x%08x\n", hr);
119
120 /* test setting one that I can't set */
121 spec.ulKind = PRSPEC_PROPID;
122 U(spec).propid = PID_DICTIONARY;
123 var.vt = VT_I4;
124 U(var).lVal = 1;
125 hr = IPropertyStorage_WriteMultiple(propertyStorage, 1, &spec, &var, 0);
126 ok(hr == STG_E_INVALIDPARAMETER,
127 "Expected STG_E_INVALIDPARAMETER, got 0x%08x\n", hr);
128
129 /* test setting one by name with an invalid propidNameFirst */
130 spec.ulKind = PRSPEC_LPWSTR;
131 U(spec).lpwstr = propName;
132 hr = IPropertyStorage_WriteMultiple(propertyStorage, 1, &spec, &var,
133 PID_DICTIONARY);
134 ok(hr == STG_E_INVALIDPARAMETER,
135 "Expected STG_E_INVALIDPARAMETER, got 0x%08x\n", hr);
136
137 /* test setting behavior (case-sensitive) */
138 spec.ulKind = PRSPEC_PROPID;
139 U(spec).propid = PID_BEHAVIOR;
140 U(var).lVal = 1;
141 hr = IPropertyStorage_WriteMultiple(propertyStorage, 1, &spec, &var, 0);
142 ok(hr == STG_E_INVALIDPARAMETER,
143 "Expected STG_E_INVALIDPARAMETER, got 0x%08x\n", hr);
144
145 /* set one by value.. */
146 spec.ulKind = PRSPEC_PROPID;
147 U(spec).propid = PID_FIRST_USABLE;
148 U(var).lVal = 1;
149 hr = IPropertyStorage_WriteMultiple(propertyStorage, 1, &spec, &var, 0);
150 ok(hr == S_OK, "WriteMultiple failed: 0x%08x\n", hr);
151
152 /* set one by name */
153 spec.ulKind = PRSPEC_LPWSTR;
154 U(spec).lpwstr = propName;
155 U(var).lVal = 2;
156 hr = IPropertyStorage_WriteMultiple(propertyStorage, 1, &spec, &var,
157 PID_FIRST_USABLE);
158 ok(hr == S_OK, "WriteMultiple failed: 0x%08x\n", hr);
159
160 /* set a string value */
161 spec.ulKind = PRSPEC_PROPID;
162 U(spec).propid = PIDSI_AUTHOR;
163 var.vt = VT_LPSTR;
164 U(var).pszVal = val;
165 hr = IPropertyStorage_WriteMultiple(propertyStorage, 1, &spec, &var, 0);
166 ok(hr == S_OK, "WriteMultiple failed: 0x%08x\n", hr);
167
168 /* set a clipboard value */
169 spec.ulKind = PRSPEC_PROPID;
170 U(spec).propid = PIDSI_THUMBNAIL;
171 var.vt = VT_CF;
172 clipdata.cbSize = sizeof clipcontent + sizeof (ULONG);
173 clipdata.ulClipFmt = CF_ENHMETAFILE;
174 clipdata.pClipData = clipcontent;
175 U(var).pclipdata = &clipdata;
176 hr = IPropertyStorage_WriteMultiple(propertyStorage, 1, &spec, &var, 0);
177 ok(hr == S_OK, "WriteMultiple failed: 0x%08x\n", hr);
178
179
180 /* check reading */
181 hr = IPropertyStorage_ReadMultiple(propertyStorage, 0, NULL, NULL);
182 ok(hr == S_FALSE, "ReadMultiple with 0 args failed: 0x%08x\n", hr);
183 hr = IPropertyStorage_ReadMultiple(propertyStorage, 1, NULL, NULL);
184 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got 0x%08x\n", hr);
185 /* read by propid */
186 spec.ulKind = PRSPEC_PROPID;
187 U(spec).propid = PID_FIRST_USABLE;
188 hr = IPropertyStorage_ReadMultiple(propertyStorage, 1, &spec, &var);
189 ok(hr == S_OK, "ReadMultiple failed: 0x%08x\n", hr);
190 ok(var.vt == VT_I4 && U(var).lVal == 1,
191 "Didn't get expected type or value for property (got type %d, value %d)\n",
192 var.vt, U(var).lVal);
193 /* read by name */
194 spec.ulKind = PRSPEC_LPWSTR;
195 U(spec).lpwstr = propName;
196 hr = IPropertyStorage_ReadMultiple(propertyStorage, 1, &spec, &var);
197 ok(hr == S_OK, "ReadMultiple failed: 0x%08x\n", hr);
198 ok(var.vt == VT_I4 && U(var).lVal == 2,
199 "Didn't get expected type or value for property (got type %d, value %d)\n",
200 var.vt, U(var).lVal);
201 /* read string value */
202 spec.ulKind = PRSPEC_PROPID;
203 U(spec).propid = PIDSI_AUTHOR;
204 hr = IPropertyStorage_ReadMultiple(propertyStorage, 1, &spec, &var);
205 ok(hr == S_OK, "ReadMultiple failed: 0x%08x\n", hr);
206 ok(var.vt == VT_LPSTR && !lstrcmpA(U(var).pszVal, val),
207 "Didn't get expected type or value for property (got type %d, value %s)\n",
208 var.vt, U(var).pszVal);
209 PropVariantClear(&var);
210
211 /* read clipboard format */
212 spec.ulKind = PRSPEC_PROPID;
213 U(spec).propid = PIDSI_THUMBNAIL;
214 hr = IPropertyStorage_ReadMultiple(propertyStorage, 1, &spec, &var);
215 ok(hr == S_OK, "ReadMultiple failed: 0x%08x\n", hr);
216 ok(var.vt == VT_CF, "variant type wrong\n");
217 ok(U(var).pclipdata->ulClipFmt == CF_ENHMETAFILE,
218 "clipboard type wrong\n");
219 ok(U(var).pclipdata->cbSize == sizeof clipcontent + sizeof (ULONG),
220 "clipboard size wrong\n");
221 ok(!memcmp(U(var).pclipdata->pClipData, clipcontent, sizeof clipcontent),
222 "clipboard contents wrong\n");
223 ok(S_OK == PropVariantClear(&var), "failed to clear variant\n");
224
225 /* check deleting */
226 hr = IPropertyStorage_DeleteMultiple(propertyStorage, 0, NULL);
227 ok(hr == S_OK, "DeleteMultiple with 0 args failed: 0x%08x\n", hr);
228 hr = IPropertyStorage_DeleteMultiple(propertyStorage, 1, NULL);
229 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got 0x%08x\n", hr);
230 /* contrary to what the docs say, you can't delete the dictionary */
231 spec.ulKind = PRSPEC_PROPID;
232 U(spec).propid = PID_DICTIONARY;
233 hr = IPropertyStorage_DeleteMultiple(propertyStorage, 1, &spec);
234 ok(hr == STG_E_INVALIDPARAMETER,
235 "Expected STG_E_INVALIDPARAMETER, got 0x%08x\n", hr);
236 /* now delete the first value.. */
237 U(spec).propid = PID_FIRST_USABLE;
238 hr = IPropertyStorage_DeleteMultiple(propertyStorage, 1, &spec);
239 ok(hr == S_OK, "DeleteMultiple failed: 0x%08x\n", hr);
240 /* and check that it's no longer readable */
241 hr = IPropertyStorage_ReadMultiple(propertyStorage, 1, &spec, &var);
242 ok(hr == S_FALSE, "Expected S_FALSE, got 0x%08x\n", hr);
243
244 hr = IPropertyStorage_Commit(propertyStorage, STGC_DEFAULT);
245 ok(hr == S_OK, "Commit failed: 0x%08x\n", hr);
246
247 /* check reverting */
248 spec.ulKind = PRSPEC_PROPID;
249 U(spec).propid = PID_FIRST_USABLE;
250 hr = IPropertyStorage_WriteMultiple(propertyStorage, 1, &spec, &var, 0);
251 ok(hr == S_OK, "WriteMultiple failed: 0x%08x\n", hr);
252 hr = IPropertyStorage_Revert(propertyStorage);
253 ok(hr == S_OK, "Revert failed: 0x%08x\n", hr);
254 /* now check that it's still not there */
255 hr = IPropertyStorage_ReadMultiple(propertyStorage, 1, &spec, &var);
256 ok(hr == S_FALSE, "Expected S_FALSE, got 0x%08x\n", hr);
257 /* set an integer value again */
258 spec.ulKind = PRSPEC_PROPID;
259 U(spec).propid = PID_FIRST_USABLE;
260 var.vt = VT_I4;
261 U(var).lVal = 1;
262 hr = IPropertyStorage_WriteMultiple(propertyStorage, 1, &spec, &var, 0);
263 ok(hr == S_OK, "WriteMultiple failed: 0x%08x\n", hr);
264 /* commit it */
265 hr = IPropertyStorage_Commit(propertyStorage, STGC_DEFAULT);
266 ok(hr == S_OK, "Commit failed: 0x%08x\n", hr);
267 /* set it to a string value */
268 var.vt = VT_LPSTR;
269 U(var).pszVal = val;
270 hr = IPropertyStorage_WriteMultiple(propertyStorage, 1, &spec, &var, 0);
271 ok(hr == S_OK, "WriteMultiple failed: 0x%08x\n", hr);
272 /* revert it */
273 hr = IPropertyStorage_Revert(propertyStorage);
274 ok(hr == S_OK, "Revert failed: 0x%08x\n", hr);
275 /* Oddly enough, there's no guarantee that a successful revert actually
276 * implies the value wasn't saved. Maybe transactional mode needs to be
277 * used for that?
278 */
279
280 IPropertyStorage_Release(propertyStorage);
281 if(propSetStorage) IPropertySetStorage_Release(*propSetStorage);
282 IStorage_Release(storage);
283 if(stream) IUnknown_Release(stream);
284
285 /* now open it again */
286 hr = StgOpenStorage(filename, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
287 NULL, 0, &storage);
288 ok(hr == S_OK, "StgOpenStorage failed: 0x%08x\n", hr);
289
290 if(propSetStorage)
291 {
292 hr = pStgCreatePropSetStg(storage, 0, propSetStorage);
293 ok(hr == S_OK, "StgCreatePropSetStg failed: 0x%08x\n", hr);
294
295 hr = IPropertySetStorage_Open(*propSetStorage, &FMTID_SummaryInformation,
296 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, &propertyStorage);
297 ok(hr == S_OK, "IPropertySetStorage_Open failed: 0x%08x\n", hr);
298 }
299 else
300 {
301 hr = IStorage_OpenStream(storage, szSummaryInfo,
302 0, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &stream);
303 ok(hr == S_OK, "IStorage_OpenStream failed: 0x%08x\n", hr);
304
305 if(!pStgOpenPropStg)
306 {
307 IStorage_Release(storage);
308 IUnknown_Release(stream);
309 DeleteFileW(filename);
310 return;
311 }
312 hr = pStgOpenPropStg((IUnknown *)stream, &FMTID_SummaryInformation,
313 PROPSETFLAG_DEFAULT, 0, &propertyStorage);
314 ok(hr == S_OK, "StgOpenPropStg failed: 0x%08x\n", hr);
315 }
316
317 /* check properties again */
318 spec.ulKind = PRSPEC_LPWSTR;
319 U(spec).lpwstr = propName;
320 hr = IPropertyStorage_ReadMultiple(propertyStorage, 1, &spec, &var);
321 ok(hr == S_OK, "ReadMultiple failed: 0x%08x\n", hr);
322 ok(var.vt == VT_I4 && U(var).lVal == 2,
323 "Didn't get expected type or value for property (got type %d, value %d)\n",
324 var.vt, U(var).lVal);
325 spec.ulKind = PRSPEC_PROPID;
326 U(spec).propid = PIDSI_AUTHOR;
327 hr = IPropertyStorage_ReadMultiple(propertyStorage, 1, &spec, &var);
328 ok(hr == S_OK, "ReadMultiple failed: 0x%08x\n", hr);
329 ok(var.vt == VT_LPSTR && !lstrcmpA(U(var).pszVal, val),
330 "Didn't get expected type or value for property (got type %d, value %s)\n",
331 var.vt, U(var).pszVal);
332 PropVariantClear(&var);
333
334 IPropertyStorage_Release(propertyStorage);
335 if(propSetStorage) IPropertySetStorage_Release(*propSetStorage);
336 IStorage_Release(storage);
337 if(stream) IUnknown_Release(stream);
338
339 DeleteFileW(filename);
340
341 /* Test creating a property set storage with a random GUID */
342 hr = StgCreateDocfile(filename,
343 STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE, 0, &storage);
344 ok(hr == S_OK, "StgCreateDocfile failed: 0x%08x\n", hr);
345
346 if(propSetStorage)
347 {
348 hr = pStgCreatePropSetStg(storage, 0, propSetStorage);
349 ok(hr == S_OK, "StgCreatePropSetStg failed: 0x%08x\n", hr);
350
351 hr = IPropertySetStorage_Create(*propSetStorage,
352 &anyOldGuid, NULL, PROPSETFLAG_ANSI,
353 STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE,
354 &propertyStorage);
355 ok(hr == S_OK, "IPropertySetStorage_Create failed: 0x%08x\n", hr);
356 }
357 else
358 {
359 hr = IStorage_CreateStream(storage, szSummaryInfo,
360 STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stream);
361 ok(hr == S_OK, "IStorage_CreateStream failed: 0x%08x\n", hr);
362
363 hr = pStgCreatePropStg((IUnknown *)stream, &anyOldGuid, NULL,
364 PROPSETFLAG_DEFAULT, 0, &propertyStorage);
365 ok(hr == S_OK, "StgCreatePropStg failed: 0x%08x\n", hr);
366 }
367
368 spec.ulKind = PRSPEC_PROPID;
369 U(spec).propid = PID_FIRST_USABLE;
370 var.vt = VT_I4;
371 U(var).lVal = 1;
372 hr = IPropertyStorage_WriteMultiple(propertyStorage, 1, &spec, &var, 0);
373 ok(hr == S_OK, "WriteMultiple failed: 0x%08x\n", hr);
374
375 hr = IPropertyStorage_Commit(propertyStorage, STGC_DEFAULT);
376 ok(hr == S_OK, "Commit failed: 0x%08x\n", hr);
377
378 IPropertyStorage_Release(propertyStorage);
379 if(propSetStorage) IPropertySetStorage_Release(*propSetStorage);
380 IStorage_Release(storage);
381 if(stream) IUnknown_Release(stream);
382
383 /* now open it again */
384 hr = StgOpenStorage(filename, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
385 NULL, 0, &storage);
386 ok(hr == S_OK, "StgOpenStorage failed: 0x%08x\n", hr);
387
388 if(propSetStorage)
389 {
390 hr = pStgCreatePropSetStg(storage, 0, propSetStorage);
391 ok(hr == S_OK, "StgCreatePropSetStg failed: 0x%08x\n", hr);
392
393 hr = IPropertySetStorage_Open(*propSetStorage, &anyOldGuid,
394 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, &propertyStorage);
395 ok(hr == S_OK, "IPropertySetStorage_Open failed: 0x%08x\n", hr);
396 }
397 else
398 {
399 hr = IStorage_OpenStream(storage, szSummaryInfo,
400 0, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &stream);
401 ok(hr == S_OK, "IStorage_OpenStream failed: 0x%08x\n", hr);
402
403 hr = pStgOpenPropStg((IUnknown *)stream, &anyOldGuid,
404 PROPSETFLAG_DEFAULT, 0, &propertyStorage);
405 ok(hr == S_OK, "StgOpenPropStg failed: 0x%08x\n", hr);
406 }
407
408 spec.ulKind = PRSPEC_PROPID;
409 U(spec).propid = PID_FIRST_USABLE;
410 hr = IPropertyStorage_ReadMultiple(propertyStorage, 1, &spec, &var);
411 ok(hr == S_OK, "ReadMultiple failed: 0x%08x\n", hr);
412
413 ok(var.vt == VT_I4 && U(var).lVal == 1,
414 "Didn't get expected type or value for property (got type %d, value %d)\n",
415 var.vt, U(var).lVal);
416
417 IPropertyStorage_Release(propertyStorage);
418 if(propSetStorage) IPropertySetStorage_Release(*propSetStorage);
419 IStorage_Release(storage);
420 if(stream) IUnknown_Release(stream);
421
422 DeleteFileW(filename);
423 }
424
425 static void testProps(void)
426 {
427 IPropertySetStorage *propSetStorage = NULL;
428
429 testPropsHelper(&propSetStorage);
430 testPropsHelper(NULL);
431 }
432
433 static void testCodepage(void)
434 {
435 static const WCHAR szDot[] = { '.',0 };
436 static const WCHAR szPrefix[] = { 's','t','g',0 };
437 static CHAR aval[] = "hi";
438 static WCHAR wval[] = { 'h','i',0 };
439 HRESULT hr;
440 IStorage *storage = NULL;
441 IPropertySetStorage *propSetStorage = NULL;
442 IPropertyStorage *propertyStorage = NULL;
443 PROPSPEC spec;
444 PROPVARIANT var;
445 WCHAR fileName[MAX_PATH];
446
447 if(!GetTempFileNameW(szDot, szPrefix, 0, fileName))
448 return;
449
450 hr = StgCreateDocfile(fileName,
451 STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE, 0, &storage);
452 ok(hr == S_OK, "StgCreateDocfile failed: 0x%08x\n", hr);
453
454 if(!pStgCreatePropSetStg)
455 {
456 IStorage_Release(storage);
457 DeleteFileW(fileName);
458 return;
459 }
460 hr = pStgCreatePropSetStg(storage, 0, &propSetStorage);
461 ok(hr == S_OK, "StgCreatePropSetStg failed: 0x%08x\n", hr);
462
463 hr = IPropertySetStorage_Create(propSetStorage,
464 &FMTID_SummaryInformation, NULL, PROPSETFLAG_DEFAULT,
465 STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE,
466 &propertyStorage);
467 ok(hr == S_OK, "IPropertySetStorage_Create failed: 0x%08x\n", hr);
468
469 PropVariantInit(&var);
470 spec.ulKind = PRSPEC_PROPID;
471 U(spec).propid = PID_CODEPAGE;
472 /* check code page before it's been explicitly set */
473 hr = IPropertyStorage_ReadMultiple(propertyStorage, 1, &spec, &var);
474 ok(hr == S_OK, "ReadMultiple failed: 0x%08x\n", hr);
475 ok(var.vt == VT_I2 && U(var).iVal == 1200,
476 "Didn't get expected type or value for property\n");
477 /* Set the code page to ascii */
478 var.vt = VT_I2;
479 U(var).iVal = 1252;
480 hr = IPropertyStorage_WriteMultiple(propertyStorage, 1, &spec, &var, 0);
481 ok(hr == S_OK, "WriteMultiple failed: 0x%08x\n", hr);
482 /* check code page */
483 hr = IPropertyStorage_ReadMultiple(propertyStorage, 1, &spec, &var);
484 ok(hr == S_OK, "ReadMultiple failed: 0x%08x\n", hr);
485 ok(var.vt == VT_I2 && U(var).iVal == 1252,
486 "Didn't get expected type or value for property\n");
487 /* Set code page to Unicode */
488 U(var).iVal = 1200;
489 hr = IPropertyStorage_WriteMultiple(propertyStorage, 1, &spec, &var, 0);
490 ok(hr == S_OK, "WriteMultiple failed: 0x%08x\n", hr);
491 /* check code page */
492 hr = IPropertyStorage_ReadMultiple(propertyStorage, 1, &spec, &var);
493 ok(hr == S_OK, "ReadMultiple failed: 0x%08x\n", hr);
494 ok(var.vt == VT_I2 && U(var).iVal == 1200,
495 "Didn't get expected type or value for property\n");
496 /* Set a string value */
497 spec.ulKind = PRSPEC_PROPID;
498 U(spec).propid = PID_FIRST_USABLE;
499 var.vt = VT_LPSTR;
500 U(var).pszVal = aval;
501 hr = IPropertyStorage_WriteMultiple(propertyStorage, 1, &spec, &var, 0);
502 ok(hr == S_OK, "WriteMultiple failed: 0x%08x\n", hr);
503 hr = IPropertyStorage_ReadMultiple(propertyStorage, 1, &spec, &var);
504 ok(hr == S_OK, "ReadMultiple failed: 0x%08x\n", hr);
505 ok(var.vt == VT_LPSTR && !strcmp(U(var).pszVal, "hi"),
506 "Didn't get expected type or value for property\n");
507 PropVariantClear(&var);
508 /* This seemingly non-sensical test is to show that the string is indeed
509 * interpreted according to the current system code page, not according to
510 * the property set's code page. (If the latter were true, the whole
511 * string would be maintained. As it is, only the first character is.)
512 */
513 var.vt = VT_LPSTR;
514 U(var).pszVal = (LPSTR)wval;
515 hr = IPropertyStorage_WriteMultiple(propertyStorage, 1, &spec, &var, 0);
516 ok(hr == S_OK, "WriteMultiple failed: 0x%08x\n", hr);
517 hr = IPropertyStorage_ReadMultiple(propertyStorage, 1, &spec, &var);
518 ok(hr == S_OK, "ReadMultiple failed: 0x%08x\n", hr);
519 ok(var.vt == VT_LPSTR && !strcmp(U(var).pszVal, "h"),
520 "Didn't get expected type or value for property\n");
521 PropVariantClear(&var);
522
523 /* now that a property's been set, you can't change the code page */
524 spec.ulKind = PRSPEC_PROPID;
525 U(spec).propid = PID_CODEPAGE;
526 var.vt = VT_I2;
527 U(var).iVal = 1200;
528 hr = IPropertyStorage_WriteMultiple(propertyStorage, 1, &spec, &var, 0);
529 ok(hr == STG_E_INVALIDPARAMETER,
530 "Expected STG_E_INVALIDPARAMETER, got 0x%08x\n", hr);
531
532 IPropertyStorage_Release(propertyStorage);
533 IPropertySetStorage_Release(propSetStorage);
534 IStorage_Release(storage);
535
536 DeleteFileW(fileName);
537
538 /* same tests, but with PROPSETFLAG_ANSI */
539 hr = StgCreateDocfile(fileName,
540 STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE, 0, &storage);
541 ok(hr == S_OK, "StgCreateDocfile failed: 0x%08x\n", hr);
542
543 hr = pStgCreatePropSetStg(storage, 0, &propSetStorage);
544 ok(hr == S_OK, "StgCreatePropSetStg failed: 0x%08x\n", hr);
545
546 hr = IPropertySetStorage_Create(propSetStorage,
547 &FMTID_SummaryInformation, NULL, PROPSETFLAG_ANSI,
548 STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE,
549 &propertyStorage);
550 ok(hr == S_OK, "IPropertySetStorage_Create failed: 0x%08x\n", hr);
551
552 /* check code page before it's been explicitly set */
553 hr = IPropertyStorage_ReadMultiple(propertyStorage, 1, &spec, &var);
554 ok(hr == S_OK, "ReadMultiple failed: 0x%08x\n", hr);
555 ok(var.vt == VT_I2, "Didn't get expected type for property (%u)\n", var.vt);
556 /* Set code page to Unicode */
557 U(var).iVal = 1200;
558 hr = IPropertyStorage_WriteMultiple(propertyStorage, 1, &spec, &var, 0);
559 ok(hr == S_OK, "WriteMultiple failed: 0x%08x\n", hr);
560 /* check code page */
561 hr = IPropertyStorage_ReadMultiple(propertyStorage, 1, &spec, &var);
562 ok(hr == S_OK, "ReadMultiple failed: 0x%08x\n", hr);
563 ok(var.vt == VT_I2 && U(var).iVal == 1200,
564 "Didn't get expected type or value for property\n");
565 /* This test is commented out for documentation. It fails under Wine,
566 * and I expect it would under Windows as well, yet it succeeds. There's
567 * obviously something about string conversion I don't understand.
568 */
569 if(0) {
570 static unsigned char strVal[] = { 0x81, 0xff, 0x04, 0 };
571 /* Set code page to 950 (Traditional Chinese) */
572 U(var).iVal = 950;
573 hr = IPropertyStorage_WriteMultiple(propertyStorage, 1, &spec, &var, 0);
574 ok(hr == S_OK, "WriteMultiple failed: 0x%08x\n", hr);
575 /* Try writing an invalid string: lead byte 0x81 is unused in Traditional
576 * Chinese.
577 */
578 spec.ulKind = PRSPEC_PROPID;
579 U(spec).propid = PID_FIRST_USABLE;
580 var.vt = VT_LPSTR;
581 U(var).pszVal = (LPSTR)strVal;
582 hr = IPropertyStorage_WriteMultiple(propertyStorage, 1, &spec, &var, 0);
583 ok(hr == S_OK, "WriteMultiple failed: 0x%08x\n", hr);
584 /* Check returned string */
585 hr = IPropertyStorage_ReadMultiple(propertyStorage, 1, &spec, &var);
586 ok(hr == S_OK, "ReadMultiple failed: 0x%08x\n", hr);
587 ok(var.vt == VT_LPSTR && !strcmp(U(var).pszVal, (LPCSTR)strVal),
588 "Didn't get expected type or value for property\n");
589 }
590
591 IPropertyStorage_Release(propertyStorage);
592 IPropertySetStorage_Release(propSetStorage);
593 IStorage_Release(storage);
594
595 DeleteFileW(fileName);
596 }
597
598 static void testFmtId(void)
599 {
600 WCHAR szSummaryInfo[] = { 5,'S','u','m','m','a','r','y',
601 'I','n','f','o','r','m','a','t','i','o','n',0 };
602 WCHAR szDocSummaryInfo[] = { 5,'D','o','c','u','m','e','n','t',
603 'S','u','m','m','a','r','y','I','n','f','o','r','m','a','t','i','o','n',
604 0 };
605 WCHAR szIID_IPropSetStg[] = { 5,'0','j','a','a','a','a','a',
606 'a','A','a','a','a','a','a','d','a','A','a','a','a','a','a','a','a','G',
607 'c',0 };
608 WCHAR name[32];
609 FMTID fmtid;
610 HRESULT hr;
611
612 if (pFmtIdToPropStgName) {
613 hr = pFmtIdToPropStgName(NULL, name);
614 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got 0x%08x\n", hr);
615 hr = pFmtIdToPropStgName(&FMTID_SummaryInformation, NULL);
616 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got 0x%08x\n", hr);
617 hr = pFmtIdToPropStgName(&FMTID_SummaryInformation, name);
618 ok(hr == S_OK, "FmtIdToPropStgName failed: 0x%08x\n", hr);
619 ok(!memcmp(name, szSummaryInfo, (lstrlenW(szSummaryInfo) + 1) *
620 sizeof(WCHAR)), "Got wrong name for FMTID_SummaryInformation\n");
621 hr = pFmtIdToPropStgName(&FMTID_DocSummaryInformation, name);
622 ok(hr == S_OK, "FmtIdToPropStgName failed: 0x%08x\n", hr);
623 ok(!memcmp(name, szDocSummaryInfo, (lstrlenW(szDocSummaryInfo) + 1) *
624 sizeof(WCHAR)), "Got wrong name for FMTID_DocSummaryInformation\n");
625 hr = pFmtIdToPropStgName(&FMTID_UserDefinedProperties, name);
626 ok(hr == S_OK, "FmtIdToPropStgName failed: 0x%08x\n", hr);
627 ok(!memcmp(name, szDocSummaryInfo, (lstrlenW(szDocSummaryInfo) + 1) *
628 sizeof(WCHAR)), "Got wrong name for FMTID_DocSummaryInformation\n");
629 hr = pFmtIdToPropStgName(&IID_IPropertySetStorage, name);
630 ok(hr == S_OK, "FmtIdToPropStgName failed: 0x%08x\n", hr);
631 ok(!memcmp(name, szIID_IPropSetStg, (lstrlenW(szIID_IPropSetStg) + 1) *
632 sizeof(WCHAR)), "Got wrong name for IID_IPropertySetStorage\n");
633 }
634
635 if(pPropStgNameToFmtId) {
636 /* test args first */
637 hr = pPropStgNameToFmtId(NULL, NULL);
638 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got 0x%08x\n", hr);
639 hr = pPropStgNameToFmtId(NULL, &fmtid);
640 ok(hr == STG_E_INVALIDNAME, "Expected STG_E_INVALIDNAME, got 0x%08x\n",
641 hr);
642 hr = pPropStgNameToFmtId(szDocSummaryInfo, NULL);
643 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got 0x%08x\n", hr);
644 /* test the known format IDs */
645 hr = pPropStgNameToFmtId(szSummaryInfo, &fmtid);
646 ok(hr == S_OK, "PropStgNameToFmtId failed: 0x%08x\n", hr);
647 ok(!memcmp(&fmtid, &FMTID_SummaryInformation, sizeof(fmtid)),
648 "Got unexpected FMTID, expected FMTID_SummaryInformation\n");
649 hr = pPropStgNameToFmtId(szDocSummaryInfo, &fmtid);
650 ok(hr == S_OK, "PropStgNameToFmtId failed: 0x%08x\n", hr);
651 ok(!memcmp(&fmtid, &FMTID_DocSummaryInformation, sizeof(fmtid)),
652 "Got unexpected FMTID, expected FMTID_DocSummaryInformation\n");
653 /* test another GUID */
654 hr = pPropStgNameToFmtId(szIID_IPropSetStg, &fmtid);
655 ok(hr == S_OK, "PropStgNameToFmtId failed: 0x%08x\n", hr);
656 ok(!memcmp(&fmtid, &IID_IPropertySetStorage, sizeof(fmtid)),
657 "Got unexpected FMTID, expected IID_IPropertySetStorage\n");
658 /* now check case matching */
659 CharUpperW(szDocSummaryInfo + 1);
660 hr = pPropStgNameToFmtId(szDocSummaryInfo, &fmtid);
661 ok(hr == S_OK, "PropStgNameToFmtId failed: 0x%08x\n", hr);
662 ok(!memcmp(&fmtid, &FMTID_DocSummaryInformation, sizeof(fmtid)),
663 "Got unexpected FMTID, expected FMTID_DocSummaryInformation\n");
664 CharUpperW(szIID_IPropSetStg + 1);
665 hr = pPropStgNameToFmtId(szIID_IPropSetStg, &fmtid);
666 ok(hr == S_OK, "PropStgNameToFmtId failed: 0x%08x\n", hr);
667 ok(!memcmp(&fmtid, &IID_IPropertySetStorage, sizeof(fmtid)),
668 "Got unexpected FMTID, expected IID_IPropertySetStorage\n");
669 }
670 }
671
672 START_TEST(stg_prop)
673 {
674 init_function_pointers();
675 testProps();
676 testCodepage();
677 testFmtId();
678 }