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 } 679