[OLE32_WINETEST] Sync with Wine Staging 4.0. CORE-15682
[reactos.git] / modules / rostests / winetests / ole32 / storage32.c
1 /*
2 * Unit tests for OLE storage
3 *
4 * Copyright (c) 2004 Mike McCormack
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 <stdio.h>
22
23 #define COBJMACROS
24 #ifdef __REACTOS__
25 #define CONST_VTABLE
26 #else
27 #define NONAMELESSUNION
28 #define NONAMELESSSTRUCT
29 #endif
30
31 #include <windows.h>
32 #include "wine/test.h"
33
34 #include "ole2.h"
35 #include "objidl.h"
36 #include "initguid.h"
37
38 DEFINE_GUID( test_stg_cls, 0x88888888, 0x0425, 0x0000, 0,0,0,0,0,0,0,0);
39
40 #define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08x\n", hr)
41
42 static CHAR filenameA[MAX_PATH];
43 static WCHAR filename[MAX_PATH];
44
45 static const char file1_nameA[] = {'c','o','p','y','t','e','s','t','A',0};
46 static const WCHAR file1_name[] = {'c','o','p','y','t','e','s','t','A',0};
47 static const char file2_nameA[] = {'c','o','p','y','t','e','s','t','B',0};
48 static const WCHAR file2_name[] = {'c','o','p','y','t','e','s','t','B',0};
49 static const WCHAR stgA_name[] = {'S','t','o','r','a','g','e','A',0};
50 static const WCHAR stgB_name[] = {'S','t','o','r','a','g','e','B',0};
51 static const WCHAR strmA_name[] = {'S','t','r','e','a','m','A',0};
52 static const WCHAR strmB_name[] = {'S','t','r','e','a','m','B',0};
53 static const WCHAR strmC_name[] = {'S','t','r','e','a','m','C',0};
54
55 /* Win9x and WinMe don't have lstrcmpW */
56 static int strcmp_ww(LPCWSTR strw1, LPCWSTR strw2)
57 {
58 CHAR stra1[512], stra2[512];
59 WideCharToMultiByte(CP_ACP, 0, strw1, -1, stra1, sizeof(stra1), NULL, NULL);
60 WideCharToMultiByte(CP_ACP, 0, strw2, -1, stra2, sizeof(stra2), NULL, NULL);
61 return lstrcmpA(stra1, stra2);
62 }
63
64 typedef struct TestLockBytes {
65 ILockBytes ILockBytes_iface;
66 LONG ref;
67 BYTE* contents;
68 ULONG size;
69 ULONG buffer_size;
70 HRESULT lock_hr;
71 ULONG locks_supported;
72 ULONG lock_called;
73 } TestLockBytes;
74
75 static inline TestLockBytes *impl_from_ILockBytes(ILockBytes *iface)
76 {
77 return CONTAINING_RECORD(iface, TestLockBytes, ILockBytes_iface);
78 }
79
80 static HRESULT WINAPI TestLockBytes_QueryInterface(ILockBytes *iface, REFIID iid,
81 void **ppv)
82 {
83 TestLockBytes *This = impl_from_ILockBytes(iface);
84
85 if (!ppv) return E_INVALIDARG;
86
87 if (IsEqualIID(&IID_IUnknown, iid) ||
88 IsEqualIID(&IID_ILockBytes, iid))
89 *ppv = &This->ILockBytes_iface;
90 else
91 return E_NOINTERFACE;
92
93 IUnknown_AddRef((IUnknown*)*ppv);
94 return S_OK;
95 }
96
97 static ULONG WINAPI TestLockBytes_AddRef(ILockBytes *iface)
98 {
99 TestLockBytes *This = impl_from_ILockBytes(iface);
100 ULONG ref = InterlockedIncrement(&This->ref);
101 return ref;
102 }
103
104 static ULONG WINAPI TestLockBytes_Release(ILockBytes *iface)
105 {
106 TestLockBytes *This = impl_from_ILockBytes(iface);
107 ULONG ref = InterlockedDecrement(&This->ref);
108 return ref;
109 }
110
111 static HRESULT WINAPI TestLockBytes_ReadAt(ILockBytes *iface,
112 ULARGE_INTEGER ulOffset, void *pv, ULONG cb, ULONG *pcbRead)
113 {
114 TestLockBytes *This = impl_from_ILockBytes(iface);
115 ULONG dummy;
116
117 if (!pv) return E_INVALIDARG;
118
119 if (!pcbRead) pcbRead = &dummy;
120
121 if (ulOffset.QuadPart >= This->size)
122 {
123 *pcbRead = 0;
124 return S_OK;
125 }
126
127 cb = min(cb, This->size - ulOffset.QuadPart);
128
129 *pcbRead = cb;
130 memcpy(pv, &This->contents[ulOffset.QuadPart], cb);
131
132 return S_OK;
133 }
134
135 static HRESULT WINAPI TestLockBytes_WriteAt(ILockBytes *iface,
136 ULARGE_INTEGER ulOffset, const void *pv, ULONG cb, ULONG *pcbWritten)
137 {
138 TestLockBytes *This = impl_from_ILockBytes(iface);
139 HRESULT hr;
140 ULONG dummy;
141
142 if (!pv) return E_INVALIDARG;
143
144 if (!pcbWritten) pcbWritten = &dummy;
145
146 if (ulOffset.QuadPart + cb > This->size)
147 {
148 ULARGE_INTEGER new_size;
149 new_size.QuadPart = ulOffset.QuadPart + cb;
150 hr = ILockBytes_SetSize(iface, new_size);
151 if (FAILED(hr)) return hr;
152 }
153
154 *pcbWritten = cb;
155 memcpy(&This->contents[ulOffset.QuadPart], pv, cb);
156
157 return S_OK;
158 }
159
160 static HRESULT WINAPI TestLockBytes_Flush(ILockBytes *iface)
161 {
162 return S_OK;
163 }
164
165 static HRESULT WINAPI TestLockBytes_SetSize(ILockBytes *iface,
166 ULARGE_INTEGER cb)
167 {
168 TestLockBytes *This = impl_from_ILockBytes(iface);
169
170 if (This->buffer_size < cb.QuadPart)
171 {
172 ULONG new_buffer_size = max(This->buffer_size * 2, cb.QuadPart);
173 BYTE* new_buffer = HeapAlloc(GetProcessHeap(), 0, new_buffer_size);
174 if (!new_buffer) return E_OUTOFMEMORY;
175 memcpy(new_buffer, This->contents, This->size);
176 HeapFree(GetProcessHeap(), 0, This->contents);
177 This->contents = new_buffer;
178 }
179
180 if (cb.QuadPart > This->size)
181 memset(&This->contents[This->size], 0, cb.QuadPart - This->size);
182
183 This->size = cb.QuadPart;
184
185 return S_OK;
186 }
187
188 static HRESULT WINAPI TestLockBytes_LockRegion(ILockBytes *iface,
189 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
190 {
191 TestLockBytes *This = impl_from_ILockBytes(iface);
192 This->lock_called++;
193 return This->lock_hr;
194 }
195
196 static HRESULT WINAPI TestLockBytes_UnlockRegion(ILockBytes *iface,
197 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
198 {
199 TestLockBytes *This = impl_from_ILockBytes(iface);
200 return This->lock_hr;
201 }
202
203 static HRESULT WINAPI TestLockBytes_Stat(ILockBytes *iface,
204 STATSTG *pstatstg, DWORD grfStatFlag)
205 {
206 TestLockBytes *This = impl_from_ILockBytes(iface);
207 static const WCHAR dummy_name[] = {'d','u','m','m','y',0};
208
209 if (!pstatstg) return E_INVALIDARG;
210
211 memset(pstatstg, 0, sizeof(STATSTG));
212
213 if (!(grfStatFlag & STATFLAG_NONAME))
214 {
215 pstatstg->pwcsName = CoTaskMemAlloc(sizeof(dummy_name));
216 if (!pstatstg->pwcsName) return E_OUTOFMEMORY;
217 memcpy(pstatstg->pwcsName, dummy_name, sizeof(dummy_name));
218 }
219
220 pstatstg->type = STGTY_LOCKBYTES;
221 pstatstg->cbSize.QuadPart = This->size;
222 pstatstg->grfLocksSupported = This->locks_supported;
223
224 return S_OK;
225 }
226
227 static const ILockBytesVtbl TestLockBytes_Vtbl = {
228 TestLockBytes_QueryInterface,
229 TestLockBytes_AddRef,
230 TestLockBytes_Release,
231 TestLockBytes_ReadAt,
232 TestLockBytes_WriteAt,
233 TestLockBytes_Flush,
234 TestLockBytes_SetSize,
235 TestLockBytes_LockRegion,
236 TestLockBytes_UnlockRegion,
237 TestLockBytes_Stat
238 };
239
240 static void CreateTestLockBytes(TestLockBytes **This)
241 {
242 *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(**This));
243
244 if (*This)
245 {
246 (*This)->ILockBytes_iface.lpVtbl = &TestLockBytes_Vtbl;
247 (*This)->ref = 1;
248 }
249 }
250
251 static void DeleteTestLockBytes(TestLockBytes *This)
252 {
253 ok(This->ILockBytes_iface.lpVtbl == &TestLockBytes_Vtbl, "test lock bytes %p deleted with incorrect vtable\n", This);
254 ok(This->ref == 1, "test lock bytes %p deleted with %i references instead of 1\n", This, This->ref);
255 HeapFree(GetProcessHeap(), 0, This->contents);
256 HeapFree(GetProcessHeap(), 0, This);
257 }
258
259 static void test_hglobal_storage_stat(void)
260 {
261 ILockBytes *ilb = NULL;
262 IStorage *stg = NULL;
263 HRESULT r;
264 STATSTG stat;
265 DWORD mode, refcount;
266
267 r = CreateILockBytesOnHGlobal( NULL, TRUE, &ilb );
268 ok( r == S_OK, "CreateILockBytesOnHGlobal failed\n");
269
270 r = StgIsStorageILockBytes( ilb );
271 ok( r == S_FALSE, "StgIsStorageILockBytes should have failed\n");
272
273 mode = STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE;/*0x1012*/
274 r = StgCreateDocfileOnILockBytes( ilb, mode, 0, &stg );
275 ok( r == S_OK, "StgCreateDocfileOnILockBytes failed\n");
276
277 r = WriteClassStg( stg, &test_stg_cls );
278 ok( r == S_OK, "WriteClassStg failed\n");
279
280 r = StgIsStorageILockBytes( ilb );
281 ok( r == S_OK, "StgIsStorageILockBytes failed\n");
282
283 memset( &stat, 0, sizeof stat );
284 r = IStorage_Stat( stg, &stat, 0 );
285
286 ok( stat.pwcsName == NULL, "storage name not null\n");
287 ok( stat.type == 1, "type is wrong\n");
288 ok( stat.grfMode == 0x12, "grf mode is incorrect\n");
289 ok( !memcmp(&stat.clsid, &test_stg_cls, sizeof test_stg_cls), "CLSID is wrong\n");
290
291 refcount = IStorage_Release( stg );
292 ok( refcount == 0, "IStorage refcount is wrong\n");
293 refcount = ILockBytes_Release( ilb );
294 ok( refcount == 0, "ILockBytes refcount is wrong\n");
295 }
296
297 static void test_create_storage_modes(void)
298 {
299 IStorage *stg = NULL;
300 HRESULT r;
301
302 DeleteFileA(filenameA);
303
304 /* test with some invalid parameters */
305 r = StgCreateDocfile( NULL, 0, 0, &stg);
306 ok(r==STG_E_INVALIDFLAG, "StgCreateDocfile succeeded\n");
307 r = StgCreateDocfile( filename, 0, 0, &stg);
308 ok(r==STG_E_INVALIDFLAG, "StgCreateDocfile succeeded\n");
309 r = StgCreateDocfile( filename, STGM_CREATE, 0, &stg);
310 ok(r==STG_E_INVALIDFLAG, "StgCreateDocfile succeeded\n");
311 r = StgCreateDocfile( filename, STGM_CREATE | STGM_READWRITE, 0, &stg);
312 ok(r==STG_E_INVALIDFLAG, "StgCreateDocfile succeeded\n");
313 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE, 0, &stg);
314 ok(r==STG_E_INVALIDFLAG, "StgCreateDocfile succeeded\n");
315 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, NULL);
316 ok(r==STG_E_INVALIDPOINTER, "StgCreateDocfile succeeded\n");
317 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 1, &stg);
318 ok(r==STG_E_INVALIDPARAMETER, "StgCreateDocfile succeeded\n");
319 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_DENY_WRITE | STGM_READWRITE, 0, &stg);
320 ok(r==STG_E_INVALIDFLAG, "StgCreateDocfile succeeded\n");
321 r = StgCreateDocfile( filename, STGM_SHARE_EXCLUSIVE | STGM_READ, 0, &stg);
322 ok(r==STG_E_INVALIDFLAG, "StgCreateDocfile succeeded\n");
323 r = StgCreateDocfile( filename, STGM_PRIORITY, 0, &stg);
324 ok(r==STG_E_INVALIDFLAG, "StgCreateDocfile succeeded\n");
325
326 /* StgCreateDocfile seems to be very particular about the flags it accepts */
327 r = StgCreateDocfile( filename, STGM_SHARE_EXCLUSIVE | STGM_READWRITE |STGM_TRANSACTED | STGM_WRITE, 0, &stg);
328 ok(r==STG_E_INVALIDFLAG, "StgCreateDocfile succeeded\n");
329 r = StgCreateDocfile( filename, STGM_SHARE_EXCLUSIVE | STGM_READWRITE |STGM_TRANSACTED | 8, 0, &stg);
330 ok(r==STG_E_INVALIDFLAG, "StgCreateDocfile succeeded\n");
331 r = StgCreateDocfile( filename, STGM_SHARE_EXCLUSIVE | STGM_READWRITE |STGM_TRANSACTED | 0x80, 0, &stg);
332 ok(r==STG_E_INVALIDFLAG, "StgCreateDocfile succeeded\n");
333 r = StgCreateDocfile( filename, STGM_SHARE_EXCLUSIVE | STGM_READWRITE |STGM_TRANSACTED | 0x800, 0, &stg);
334 ok(r==STG_E_INVALIDFLAG, "StgCreateDocfile succeeded\n");
335 r = StgCreateDocfile( filename, STGM_SHARE_EXCLUSIVE | STGM_READWRITE |STGM_TRANSACTED | 0x8000, 0, &stg);
336 ok(r==STG_E_INVALIDFLAG, "StgCreateDocfile succeeded\n");
337 r = StgCreateDocfile( filename, STGM_SHARE_EXCLUSIVE | STGM_READWRITE |STGM_TRANSACTED | 0x80000, 0, &stg);
338 ok(r==STG_E_INVALIDFLAG, "StgCreateDocfile succeeded\n");
339 r = StgCreateDocfile( filename, STGM_SHARE_EXCLUSIVE | STGM_READWRITE |STGM_TRANSACTED | 0x800000, 0, &stg);
340 ok(r==STG_E_INVALIDFLAG, "StgCreateDocfile succeeded\n");
341 ok(stg == NULL, "stg was set\n");
342
343 /* check what happens if the file already exists (which is how it's meant to be used) */
344 r = StgCreateDocfile( filename, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &stg);
345 ok(r==S_OK, "StgCreateDocfile failed\n");
346 r = IStorage_Release(stg);
347 ok(r == 0, "storage not released\n");
348 r = StgCreateDocfile( filename, STGM_SHARE_EXCLUSIVE | STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
349 ok(r==STG_E_FILEALREADYEXISTS, "StgCreateDocfile wrong error\n"); /* FAILIFTHERE is default */
350 r = StgCreateDocfile( filename, STGM_READ, 0, &stg);
351 ok(r==STG_E_INVALIDFLAG, "StgCreateDocfile succeeded\n"); /* need at least readmode and sharemode */
352 r = StgCreateDocfile( filename, STGM_SHARE_EXCLUSIVE, 0, &stg);
353 ok(r==STG_E_INVALIDFLAG, "StgCreateDocfile succeeded\n");
354 r = StgCreateDocfile( filename, STGM_SHARE_DENY_WRITE, 0, &stg);
355 ok(r==STG_E_INVALIDFLAG, "StgCreateDocfile succeeded\n");
356 r = StgCreateDocfile( filename, STGM_SHARE_DENY_NONE, 0, &stg);
357 ok(r==STG_E_INVALIDFLAG, "StgCreateDocfile failed\n");
358 r = StgCreateDocfile( filename, STGM_SHARE_DENY_NONE | STGM_TRANSACTED, 0, &stg);
359 ok(r==STG_E_INVALIDFLAG, "StgCreateDocfile failed\n");
360 r = StgCreateDocfile( filename, STGM_SHARE_DENY_NONE | STGM_READWRITE, 0, &stg);
361 ok(r==STG_E_INVALIDFLAG, "StgCreateDocfile failed\n");
362 r = StgCreateDocfile( filename, STGM_SHARE_DENY_NONE | STGM_WRITE, 0, &stg);
363 ok(r==STG_E_INVALIDFLAG, "StgCreateDocfile failed\n");
364 r = StgCreateDocfile( filename, STGM_SHARE_DENY_WRITE | STGM_WRITE, 0, &stg);
365 ok(r==STG_E_INVALIDFLAG, "StgCreateDocfile failed\n");
366 r = StgCreateDocfile( filename, STGM_SHARE_DENY_WRITE | STGM_READ, 0, &stg);
367 ok(r==STG_E_INVALIDFLAG, "StgCreateDocfile wrong error\n");
368 r = StgCreateDocfile( filename, STGM_TRANSACTED | STGM_SHARE_DENY_WRITE | STGM_READ, 0, &stg);
369 ok(r==STG_E_INVALIDFLAG, "StgCreateDocfile wrong error\n");
370 ok(DeleteFileA(filenameA), "failed to delete file\n");
371
372 r = StgCreateDocfile( filename, STGM_SHARE_EXCLUSIVE | STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
373 ok(r==S_OK, "StgCreateDocfile failed\n");
374 r = IStorage_Release(stg);
375 ok(r == 0, "storage not released\n");
376 r = StgCreateDocfile( filename, STGM_SHARE_EXCLUSIVE | STGM_READWRITE |STGM_TRANSACTED |STGM_FAILIFTHERE, 0, &stg);
377 ok(r==STG_E_FILEALREADYEXISTS, "StgCreateDocfile wrong error\n");
378 r = StgCreateDocfile( filename, STGM_SHARE_EXCLUSIVE | STGM_WRITE, 0, &stg);
379 ok(r==STG_E_FILEALREADYEXISTS, "StgCreateDocfile wrong error\n");
380
381 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_DENY_WRITE | STGM_READWRITE, 0, &stg);
382 ok(r==STG_E_INVALIDFLAG, "StgCreateDocfile succeeded\n");
383 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
384 ok(r==S_OK, "StgCreateDocfile failed\n");
385 r = IStorage_Release(stg);
386 ok(r == 0, "storage not released\n");
387 ok(DeleteFileA(filenameA), "failed to delete file\n");
388
389 r = StgCreateDocfile( filename, STGM_CREATE | STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
390 ok(r==S_OK, "StgCreateDocfile failed\n");
391 r = IStorage_Release(stg);
392 ok(r == 0, "storage not released\n");
393 ok(DeleteFileA(filenameA), "failed to delete file\n");
394
395 /* test the way excel uses StgCreateDocFile */
396 r = StgCreateDocfile( filename, STGM_TRANSACTED|STGM_CREATE|STGM_SHARE_DENY_WRITE|STGM_READWRITE, 0, &stg);
397 ok(r==S_OK, "StgCreateDocfile the excel way failed\n");
398 if(r == S_OK)
399 {
400 r = IStorage_Release(stg);
401 ok(r == 0, "storage not released\n");
402 ok(DeleteFileA(filenameA), "failed to delete file\n");
403 }
404
405 /* and the way windows media uses it ... */
406 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_DENY_NONE | STGM_READWRITE | STGM_TRANSACTED, 0, &stg);
407 ok(r==S_OK, "StgCreateDocfile the windows media way failed\n");
408 if (r == S_OK)
409 {
410 r = IStorage_Release(stg);
411 ok(r == 0, "storage not released\n");
412 ok(DeleteFileA(filenameA), "failed to delete file\n");
413 }
414
415 /* looks like we need STGM_TRANSACTED or STGM_CREATE */
416 r = StgCreateDocfile( filename, STGM_TRANSACTED|STGM_SHARE_DENY_WRITE|STGM_READWRITE, 0, &stg);
417 ok(r==S_OK, "StgCreateDocfile the excel way failed\n");
418 if(r == S_OK)
419 {
420 r = IStorage_Release(stg);
421 ok(r == 0, "storage not released\n");
422 ok(DeleteFileA(filenameA), "failed to delete file\n");
423 }
424
425 r = StgCreateDocfile( filename, STGM_TRANSACTED|STGM_CREATE|STGM_SHARE_DENY_WRITE|STGM_WRITE, 0, &stg);
426 ok(r==S_OK, "StgCreateDocfile the excel way failed\n");
427 if(r == S_OK)
428 {
429 r = IStorage_Release(stg);
430 ok(r == 0, "storage not released\n");
431 ok(DeleteFileA(filenameA), "failed to delete file\n");
432 }
433
434 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &stg);
435 ok(r==S_OK, "StgCreateDocfile the powerpoint way failed\n");
436 if(r == S_OK)
437 {
438 r = IStorage_Release(stg);
439 ok(r == 0, "storage not released\n");
440 ok(DeleteFileA(filenameA), "failed to delete file\n");
441 }
442
443 /* test the way msi uses StgCreateDocfile */
444 r = StgCreateDocfile( filename, STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &stg);
445 ok(r==S_OK, "StgCreateDocFile failed\n");
446 r = IStorage_Release(stg);
447 ok(r == 0, "storage not released\n");
448 ok(DeleteFileA(filenameA), "failed to delete file\n");
449 }
450
451 static void test_stgcreatestorageex(void)
452 {
453 HRESULT (WINAPI *pStgCreateStorageEx)(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen);
454 HMODULE hOle32 = GetModuleHandleA("ole32");
455 IStorage *stg = NULL;
456 STGOPTIONS stgoptions = {1, 0, 4096};
457 HRESULT r;
458
459 pStgCreateStorageEx = (void *) GetProcAddress(hOle32, "StgCreateStorageEx");
460 if (!pStgCreateStorageEx)
461 {
462 win_skip("skipping test on NT4\n");
463 return;
464 }
465
466 DeleteFileA(filenameA);
467
468 /* Verify that StgCreateStorageEx can accept an options param */
469 r = pStgCreateStorageEx( filename,
470 STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
471 STGFMT_DOCFILE,
472 0,
473 &stgoptions,
474 NULL,
475 &IID_IStorage,
476 (void **) &stg);
477 ok(r==S_OK || r==STG_E_UNIMPLEMENTEDFUNCTION, "StgCreateStorageEx with options failed\n");
478 if (r==STG_E_UNIMPLEMENTEDFUNCTION)
479 {
480 /* We're on win98 which means all bets are off. Let's get out of here. */
481 win_skip("skipping test on win9x\n");
482 return;
483 }
484
485 r = IStorage_Release(stg);
486 ok(r == 0, "storage not released\n");
487 ok(DeleteFileA(filenameA), "failed to delete file\n");
488
489 /* Verify that StgCreateStorageEx can accept a NULL pStgOptions */
490 r = pStgCreateStorageEx( filename,
491 STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
492 STGFMT_STORAGE,
493 0,
494 NULL,
495 NULL,
496 &IID_IStorage,
497 (void **) &stg);
498 ok(r==S_OK, "StgCreateStorageEx with NULL options failed\n");
499 r = IStorage_Release(stg);
500 ok(r == 0, "storage not released\n");
501 ok(DeleteFileA(filenameA), "failed to delete file\n");
502 }
503
504 static void test_storage_stream(void)
505 {
506 static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
507 static const WCHAR longname[] = {
508 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
509 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',0
510 };
511 IStorage *stg = NULL;
512 HRESULT r;
513 IStream *stm = NULL;
514 IStream *stm2 = NULL;
515 ULONG count = 0;
516 LARGE_INTEGER pos;
517 ULARGE_INTEGER p;
518 unsigned char buffer[0x100];
519 IUnknown *unk;
520 BOOL ret;
521
522 DeleteFileA(filenameA);
523
524 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
525 ok(r==S_OK, "StgCreateDocfile failed\n");
526
527 /* try create some invalid streams */
528 r = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 1, 0, &stm );
529 ok(r==STG_E_INVALIDPARAMETER, "IStorage->CreateStream wrong error\n");
530 r = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 1, &stm );
531 ok(r==STG_E_INVALIDPARAMETER, "IStorage->CreateStream wrong error\n");
532 r = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, NULL );
533 ok(r==STG_E_INVALIDPOINTER, "IStorage->CreateStream wrong error\n");
534 r = IStorage_CreateStream(stg, NULL, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
535 ok(r==STG_E_INVALIDNAME, "IStorage->CreateStream wrong error\n");
536 r = IStorage_CreateStream(stg, longname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
537 ok(r==STG_E_INVALIDNAME || broken(r==S_OK) /* nt4 */,
538 "IStorage->CreateStream wrong error, got %d GetLastError()=%d\n", r, GetLastError());
539 r = IStorage_CreateStream(stg, stmname, STGM_READWRITE, 0, 0, &stm );
540 ok(r==STG_E_INVALIDFLAG, "IStorage->CreateStream wrong error\n");
541 r = IStorage_CreateStream(stg, stmname, STGM_READ, 0, 0, &stm );
542 ok(r==STG_E_INVALIDFLAG, "IStorage->CreateStream wrong error\n");
543 r = IStorage_CreateStream(stg, stmname, STGM_WRITE, 0, 0, &stm );
544 ok(r==STG_E_INVALIDFLAG, "IStorage->CreateStream wrong error\n");
545 r = IStorage_CreateStream(stg, stmname, STGM_SHARE_DENY_NONE | STGM_READWRITE, 0, 0, &stm );
546 ok(r==STG_E_INVALIDFLAG, "IStorage->CreateStream wrong error\n");
547 r = IStorage_CreateStream(stg, stmname, STGM_SHARE_DENY_NONE | STGM_READ, 0, 0, &stm );
548 ok(r==STG_E_INVALIDFLAG, "IStorage->CreateStream wrong error\n");
549
550 /* now really create a stream and delete it */
551 r = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
552 ok(r==S_OK, "IStorage->CreateStream failed\n");
553
554 /* test for support interfaces */
555 r = IStream_QueryInterface(stm, &IID_IPersist, (void**)&unk);
556 ok(r==E_NOINTERFACE, "got 0x%08x\n", r);
557 r = IStream_QueryInterface(stm, &IID_IPersistStream, (void**)&unk);
558 ok(r==E_NOINTERFACE, "got 0x%08x\n", r);
559
560 r = IStream_Release(stm);
561 ok(r == 0, "wrong ref count\n");
562 r = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
563 ok(r==STG_E_FILEALREADYEXISTS, "IStorage->CreateStream failed\n");
564 r = IStorage_DestroyElement(stg,stmname);
565 ok(r==S_OK, "IStorage->DestroyElement failed\n");
566
567 /* create a stream and write to it */
568 r = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
569 ok(r==S_OK, "IStorage->CreateStream failed\n");
570
571 r = IStream_Clone(stm, &stm2);
572 ok(r==S_OK, "failed to clone stream\n");
573
574 r = IStream_Write(stm, NULL, 0, NULL );
575 ok(r==STG_E_INVALIDPOINTER, "IStream->Write wrong error\n");
576 r = IStream_Write(stm, "Hello\n", 0, NULL );
577 ok(r==S_OK, "failed to write stream\n");
578 r = IStream_Write(stm, "Hello\n", 0, &count );
579 ok(r==S_OK, "failed to write stream\n");
580 r = IStream_Write(stm, "Hello\n", 6, &count );
581 ok(r==S_OK, "failed to write stream\n");
582 r = IStream_Commit(stm, STGC_DEFAULT );
583 ok(r==S_OK, "failed to commit stream\n");
584 r = IStream_Commit(stm, STGC_DEFAULT );
585 ok(r==S_OK, "failed to commit stream\n");
586
587 /* Read past the end of the stream. */
588 pos.QuadPart = 3;
589 r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &p );
590 ok(r==S_OK, "failed to seek stream\n");
591 ok(p.QuadPart == 3, "at wrong place\n");
592 r = IStream_Read(stm, buffer, sizeof buffer, &count );
593 ok(r==S_OK, "failed to read\n");
594 ok(count == 3, "read bytes past end of stream\n");
595 pos.QuadPart = 10;
596 r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &p );
597 ok(r==S_OK, "failed to seek stream\n");
598 ok(p.QuadPart == 10, "at wrong place\n");
599 r = IStream_Read(stm, buffer, sizeof buffer, &count );
600 ok(r==S_OK, "failed to read\n");
601 ok(count == 0, "read bytes past end of stream\n");
602 pos.QuadPart = 10000;
603 r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &p );
604 ok(r==S_OK, "failed to seek stream\n");
605 ok(p.QuadPart == 10000, "at wrong place\n");
606 r = IStream_Read(stm, buffer, sizeof buffer, &count );
607 ok(r==S_OK, "failed to read\n");
608 ok(count == 0, "read bytes past end of stream\n");
609
610 /* Convert to a big block stream, and read past the end. */
611 p.QuadPart = 5000;
612 r = IStream_SetSize(stm,p);
613 ok(r==S_OK, "failed to set pos\n");
614 pos.QuadPart = 4997;
615 r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &p );
616 ok(r==S_OK, "failed to seek stream\n");
617 ok(p.QuadPart == 4997, "at wrong place\n");
618 r = IStream_Read(stm, buffer, sizeof buffer, &count );
619 ok(r==S_OK, "failed to read\n");
620 ok(count == 3, "read bytes past end of stream\n");
621 pos.QuadPart = 5001;
622 r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &p );
623 ok(r==S_OK, "failed to seek stream\n");
624 ok(p.QuadPart == 5001, "at wrong place\n");
625 r = IStream_Read(stm, buffer, sizeof buffer, &count );
626 ok(r==S_OK, "failed to read\n");
627 ok(count == 0, "read bytes past end of stream\n");
628 pos.QuadPart = 10000;
629 r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &p );
630 ok(r==S_OK, "failed to seek stream\n");
631 ok(p.QuadPart == 10000, "at wrong place\n");
632 r = IStream_Read(stm, buffer, sizeof buffer, &count );
633 ok(r==S_OK, "failed to read\n");
634 ok(count == 0, "read bytes past end of stream\n");
635
636 /* seek round a bit, reset the stream size */
637 pos.QuadPart = 0;
638 r = IStream_Seek(stm, pos, 3, &p );
639 ok(r==STG_E_INVALIDFUNCTION, "IStream->Seek returned wrong error\n");
640 r = IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
641 ok(r==S_OK, "failed to seek stream\n");
642 r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &p );
643 ok(r==S_OK, "failed to seek stream\n");
644 r = IStream_SetSize(stm,p);
645 ok(r==S_OK, "failed to set pos\n");
646 pos.QuadPart = 10;
647 r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &p );
648 ok(r==S_OK, "failed to seek stream\n");
649 ok(p.QuadPart == 10, "at wrong place\n");
650 r = IStream_Read(stm, buffer, sizeof buffer, &count );
651 ok(r==S_OK, "failed to set pos\n");
652 ok(count == 0, "read bytes from empty stream\n");
653 pos.QuadPart = 10000;
654 r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &p );
655 ok(r==S_OK, "failed to seek stream\n");
656 ok(p.QuadPart == 10000, "at wrong place\n");
657 r = IStream_Read(stm, buffer, sizeof buffer, &count );
658 ok(r==S_OK, "failed to set pos\n");
659 ok(count == 0, "read bytes from empty stream\n");
660 pos.QuadPart = 0;
661 r = IStream_Seek(stm, pos, STREAM_SEEK_END, &p );
662 ok(r==S_OK, "failed to seek stream\n");
663 ok(p.QuadPart == 0, "at wrong place\n");
664 r = IStream_Read(stm, buffer, sizeof buffer, &count );
665 ok(r==S_OK, "failed to set pos\n");
666 ok(count == 0, "read bytes from empty stream\n");
667
668 /* wrap up */
669 r = IStream_Release(stm2);
670 ok(r == 0, "wrong ref count\n");
671
672 /* create a stream and write to it */
673 r = IStorage_CreateStream(stg, stmname, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm2 );
674 ok(r==S_OK, "IStorage->CreateStream failed\n");
675
676 r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &p);
677 ok(r==STG_E_REVERTED, "overwritten stream should return STG_E_REVERTED instead of 0x%08x\n", r);
678
679 r = IStream_Release(stm2);
680 ok(r == 0, "wrong ref count\n");
681 r = IStream_Release(stm);
682 ok(r == 0, "wrong ref count\n");
683
684 r = IStorage_Release(stg);
685 ok(r == 0, "wrong ref count\n");
686
687 /* try create some invalid streams */
688 stg = NULL;
689 stm = NULL;
690 r = StgOpenStorage(filename, NULL, STGM_READ | STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
691 ok(r == S_OK, "should succeed\n");
692 if (stg)
693 {
694 r = IStorage_OpenStream(stg, stmname, NULL, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &stm);
695 ok(r == STG_E_INVALIDFLAG, "IStorage->OpenStream should return STG_E_INVALIDFLAG instead of 0x%08x\n", r);
696 IStorage_Release(stg);
697 }
698
699 ret = DeleteFileA(filenameA);
700 ok(ret, "file should exist\n");
701 }
702
703 static BOOL touch_file(LPCSTR filename)
704 {
705 HANDLE file;
706
707 file = CreateFileA(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL,
708 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
709 if (file==INVALID_HANDLE_VALUE)
710 return FALSE;
711 CloseHandle(file);
712 return TRUE;
713 }
714
715 static BOOL is_zero_length(LPCSTR filename)
716 {
717 HANDLE file;
718 DWORD len;
719
720 file = CreateFileA(filename, GENERIC_READ, 0, NULL,
721 OPEN_EXISTING, 0, NULL);
722 if (file==INVALID_HANDLE_VALUE)
723 return FALSE;
724 len = GetFileSize(file, NULL);
725 CloseHandle(file);
726 return len == 0;
727 }
728
729 static BOOL is_existing_file(LPCSTR filename)
730 {
731 HANDLE file;
732
733 file = CreateFileA(filename, GENERIC_READ, 0, NULL,
734 OPEN_EXISTING, 0, NULL);
735 if (file==INVALID_HANDLE_VALUE)
736 return FALSE;
737 CloseHandle(file);
738 return TRUE;
739 }
740
741 static void test_open_storage(void)
742 {
743 static const WCHAR szNonExist[] = { 'n','o','n','e','x','i','s','t',0 };
744 IStorage *stg = NULL, *stg2 = NULL;
745 HRESULT r;
746 DWORD stgm;
747 BOOL ret;
748
749 /* try opening a zero length file - it should stay zero length */
750 DeleteFileA(filenameA);
751 touch_file(filenameA);
752 stgm = STGM_NOSCRATCH | STGM_TRANSACTED | STGM_SHARE_DENY_WRITE | STGM_READWRITE;
753 r = StgOpenStorage( filename, NULL, stgm, NULL, 0, &stg);
754 ok(r==STG_E_FILEALREADYEXISTS, "StgOpenStorage didn't fail\n");
755
756 stgm = STGM_SHARE_EXCLUSIVE | STGM_READWRITE;
757 r = StgOpenStorage( filename, NULL, stgm, NULL, 0, &stg);
758 ok(r==STG_E_FILEALREADYEXISTS, "StgOpenStorage didn't fail\n");
759 ok(is_zero_length(filenameA), "file length changed\n");
760
761 DeleteFileA(filenameA);
762
763 /* try opening a nonexistent file - it should not create it */
764 stgm = STGM_DIRECT | STGM_SHARE_EXCLUSIVE | STGM_READWRITE;
765 r = StgOpenStorage( filename, NULL, stgm, NULL, 0, &stg);
766 ok(r!=S_OK, "StgOpenStorage failed: 0x%08x\n", r);
767 if (r==S_OK) IStorage_Release(stg);
768 ok(!is_existing_file(filenameA), "StgOpenStorage should not create a file\n");
769 DeleteFileA(filenameA);
770
771 /* create the file */
772 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
773 ok(r==S_OK, "StgCreateDocfile failed\n");
774 IStorage_Release(stg);
775
776 r = StgOpenStorage( filename, NULL, 0, NULL, 0, &stg);
777 ok(r==STG_E_INVALIDFLAG, "StgOpenStorage wrong error\n");
778 r = StgOpenStorage( NULL, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg);
779 ok(r==STG_E_INVALIDNAME, "StgOpenStorage wrong error\n");
780 r = StgOpenStorage( filename, NULL, STGM_SHARE_EXCLUSIVE | STGM_READ, NULL, 0, NULL);
781 ok(r==STG_E_INVALIDPOINTER, "StgOpenStorage wrong error\n");
782 r = StgOpenStorage( filename, NULL, STGM_SHARE_EXCLUSIVE | STGM_READ, NULL, 1, &stg);
783 ok(r==STG_E_INVALIDPARAMETER, "StgOpenStorage wrong error\n");
784 r = StgOpenStorage( szNonExist, NULL, STGM_SHARE_EXCLUSIVE | STGM_READ, NULL, 0, &stg);
785 ok(r==STG_E_FILENOTFOUND, "StgOpenStorage failed\n");
786 r = StgOpenStorage( filename, NULL, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READ, NULL, 0, &stg);
787 ok(r==STG_E_INVALIDFLAG, "StgOpenStorage failed\n");
788 r = StgOpenStorage( filename, NULL, STGM_SHARE_DENY_NONE | STGM_READ, NULL, 0, &stg);
789 ok(r==STG_E_INVALIDFLAG, "StgOpenStorage failed\n");
790 r = StgOpenStorage( filename, NULL, STGM_SHARE_DENY_READ | STGM_READ, NULL, 0, &stg);
791 ok(r==STG_E_INVALIDFLAG, "StgOpenStorage failed\n");
792 r = StgOpenStorage( filename, NULL, STGM_SHARE_DENY_WRITE | STGM_READWRITE, NULL, 0, &stg);
793 ok(r==STG_E_INVALIDFLAG, "StgOpenStorage failed\n");
794
795 /* open it for real */
796 r = StgOpenStorage( filename, NULL, STGM_SHARE_DENY_NONE | STGM_READ | STGM_TRANSACTED, NULL, 0, &stg); /* XLViewer 97/2000 */
797 ok(r==S_OK, "StgOpenStorage failed\n");
798 if(stg)
799 {
800 r = IStorage_Release(stg);
801 ok(r == 0, "wrong ref count\n");
802 }
803
804 r = StgOpenStorage( filename, NULL, STGM_SHARE_DENY_WRITE | STGM_READ, NULL, 0, &stg);
805 ok(r==S_OK, "StgOpenStorage failed\n");
806 if(stg)
807 {
808 r = IStorage_Release(stg);
809 ok(r == 0, "wrong ref count\n");
810 }
811
812 /* test the way word opens its custom dictionary */
813 r = StgOpenStorage( filename, NULL, STGM_NOSCRATCH | STGM_TRANSACTED |
814 STGM_SHARE_DENY_WRITE | STGM_READWRITE, NULL, 0, &stg);
815 ok(r==S_OK, "StgOpenStorage failed\n");
816 if(stg)
817 {
818 r = IStorage_Release(stg);
819 ok(r == 0, "wrong ref count\n");
820 }
821
822 r = StgOpenStorage( filename, NULL, STGM_SHARE_EXCLUSIVE | STGM_READ, NULL, 0, &stg);
823 ok(r==S_OK, "StgOpenStorage failed\n");
824 r = StgOpenStorage( filename, NULL, STGM_SHARE_EXCLUSIVE | STGM_READ, NULL, 0, &stg2);
825 ok(r==STG_E_SHAREVIOLATION, "StgOpenStorage failed\n");
826 if(stg)
827 {
828 r = IStorage_Release(stg);
829 ok(r == 0, "wrong ref count\n");
830 }
831
832 /* now try write to a storage file we opened read-only */
833 r = StgOpenStorage( filename, NULL, STGM_SHARE_EXCLUSIVE | STGM_READ, NULL, 0, &stg);
834 ok(r==S_OK, "StgOpenStorage failed\n");
835 if(stg)
836 {
837 static const WCHAR stmname[] = { 'w','i','n','e','t','e','s','t',0};
838 IStream *stm = NULL;
839 IStorage *stg2 = NULL;
840
841 r = IStorage_CreateStream( stg, stmname, STGM_WRITE | STGM_SHARE_EXCLUSIVE,
842 0, 0, &stm );
843 ok(r == STG_E_ACCESSDENIED, "CreateStream should fail\n");
844 r = IStorage_CreateStorage( stg, stmname, STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
845 ok(r == STG_E_ACCESSDENIED, "CreateStream should fail\n");
846
847 r = IStorage_Release(stg);
848 ok(r == 0, "wrong ref count\n");
849 }
850
851 /* open like visio 2003 */
852 stg = NULL;
853 r = StgOpenStorage( filename, NULL, STGM_PRIORITY | STGM_SHARE_DENY_NONE, NULL, 0, &stg);
854 ok(r == S_OK, "should succeed\n");
855 if (stg)
856 IStorage_Release(stg);
857
858 /* test other sharing modes with STGM_PRIORITY */
859 stg = NULL;
860 r = StgOpenStorage( filename, NULL, STGM_PRIORITY | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg);
861 ok(r == S_OK, "should succeed\n");
862 if (stg)
863 IStorage_Release(stg);
864
865 stg = NULL;
866 r = StgOpenStorage( filename, NULL, STGM_PRIORITY | STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
867 ok(r == S_OK, "should succeed\n");
868 if (stg)
869 IStorage_Release(stg);
870
871 stg = NULL;
872 r = StgOpenStorage( filename, NULL, STGM_PRIORITY | STGM_SHARE_DENY_READ, NULL, 0, &stg);
873 ok(r == S_OK, "should succeed\n");
874 if (stg)
875 IStorage_Release(stg);
876
877 /* open like Project 2003 */
878 stg = NULL;
879 r = StgOpenStorage( filename, NULL, STGM_PRIORITY, NULL, 0, &stg);
880 ok(r == S_OK, "should succeed\n");
881 r = StgOpenStorage( filename, NULL, STGM_PRIORITY, NULL, 0, &stg2);
882 ok(r == S_OK, "should succeed\n");
883 if (stg2)
884 IStorage_Release(stg2);
885 if (stg)
886 IStorage_Release(stg);
887
888 stg = NULL;
889 r = StgOpenStorage( filename, NULL, STGM_PRIORITY | STGM_READWRITE, NULL, 0, &stg);
890 ok(r == STG_E_INVALIDFLAG, "should fail\n");
891
892 r = StgOpenStorage( filename, NULL, STGM_TRANSACTED | STGM_PRIORITY, NULL, 0, &stg);
893 ok(r == STG_E_INVALIDFLAG, "should fail\n");
894
895 r = StgOpenStorage( filename, NULL, STGM_SIMPLE | STGM_PRIORITY, NULL, 0, &stg);
896 ok(r == STG_E_INVALIDFLAG, "should fail\n");
897
898 r = StgOpenStorage( filename, NULL, STGM_DELETEONRELEASE | STGM_PRIORITY, NULL, 0, &stg);
899 ok(r == STG_E_INVALIDFUNCTION, "should fail\n");
900
901 r = StgOpenStorage( filename, NULL, STGM_NOSCRATCH | STGM_PRIORITY, NULL, 0, &stg);
902 ok(r == STG_E_INVALIDFLAG, "should fail\n");
903
904 r = StgOpenStorage( filename, NULL, STGM_NOSNAPSHOT | STGM_PRIORITY, NULL, 0, &stg);
905 ok(r == STG_E_INVALIDFLAG, "should fail\n");
906
907 ret = DeleteFileA(filenameA);
908 ok(ret, "file didn't exist\n");
909 }
910
911 static void test_storage_suminfo(void)
912 {
913 IStorage *stg = NULL;
914 IPropertySetStorage *propset = NULL;
915 IPropertyStorage *ps = NULL;
916 HRESULT r;
917
918 DeleteFileA(filenameA);
919
920 /* create the file */
921 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
922 STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
923 ok(r==S_OK, "StgCreateDocfile failed\n");
924
925 r = IStorage_QueryInterface( stg, &IID_IPropertySetStorage, (LPVOID) &propset );
926 ok(r == S_OK, "query interface failed\n");
927
928 /* delete it */
929 r = IPropertySetStorage_Delete( propset, &FMTID_SummaryInformation );
930 ok(r == STG_E_FILENOTFOUND, "deleted property set storage\n");
931
932 r = IPropertySetStorage_Open( propset, &FMTID_SummaryInformation,
933 STGM_READ | STGM_SHARE_EXCLUSIVE, &ps );
934 ok(r == STG_E_FILENOTFOUND, "opened property set storage\n");
935
936 r = IPropertySetStorage_Create( propset, &FMTID_SummaryInformation, NULL, 0,
937 STGM_READ | STGM_SHARE_EXCLUSIVE, &ps );
938 ok(r == STG_E_INVALIDFLAG, "created property set storage\n");
939
940 r = IPropertySetStorage_Create( propset, &FMTID_SummaryInformation, NULL, 0,
941 STGM_READ, &ps );
942 ok(r == STG_E_INVALIDFLAG, "created property set storage\n");
943
944 r = IPropertySetStorage_Create( propset, &FMTID_SummaryInformation, NULL, 0, 0, &ps );
945 ok(r == STG_E_INVALIDFLAG, "created property set storage\n");
946
947 r = IPropertySetStorage_Create( propset, &FMTID_SummaryInformation, NULL, 0,
948 STGM_WRITE|STGM_SHARE_EXCLUSIVE, &ps );
949 ok(r == STG_E_INVALIDFLAG, "created property set storage\n");
950
951 r = IPropertySetStorage_Create( propset, &FMTID_SummaryInformation, NULL, 0,
952 STGM_CREATE|STGM_WRITE|STGM_SHARE_EXCLUSIVE, &ps );
953 ok(r == STG_E_INVALIDFLAG, "created property set storage\n");
954
955 /* now try really creating a property set */
956 r = IPropertySetStorage_Create( propset, &FMTID_SummaryInformation, NULL, 0,
957 STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, &ps );
958 ok(r == S_OK, "failed to create property set storage\n");
959
960 if( ps )
961 IPropertyStorage_Release(ps);
962
963 /* now try creating the same thing again */
964 r = IPropertySetStorage_Create( propset, &FMTID_SummaryInformation, NULL, 0,
965 STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, &ps );
966 ok(r == S_OK, "failed to create property set storage\n");
967 if( ps )
968 IPropertyStorage_Release(ps);
969
970 /* should be able to open it */
971 r = IPropertySetStorage_Open( propset, &FMTID_SummaryInformation,
972 STGM_READWRITE|STGM_SHARE_EXCLUSIVE, &ps);
973 ok(r == S_OK, "open failed\n");
974 if(r == S_OK)
975 IPropertyStorage_Release(ps);
976
977 /* delete it */
978 r = IPropertySetStorage_Delete( propset, &FMTID_SummaryInformation );
979 ok(r == S_OK, "failed to delete property set storage\n");
980
981 /* try opening with an invalid FMTID */
982 r = IPropertySetStorage_Open( propset, NULL,
983 STGM_READWRITE|STGM_SHARE_EXCLUSIVE, &ps);
984 ok(r == E_INVALIDARG, "open succeeded\n");
985 if(r == S_OK)
986 IPropertyStorage_Release(ps);
987
988 /* try a bad guid */
989 r = IPropertySetStorage_Open( propset, &IID_IStorage,
990 STGM_READWRITE|STGM_SHARE_EXCLUSIVE, &ps);
991 ok(r == STG_E_FILENOTFOUND, "open succeeded\n");
992 if(r == S_OK)
993 IPropertyStorage_Release(ps);
994
995
996 /* try some invalid flags */
997 r = IPropertySetStorage_Open( propset, &FMTID_SummaryInformation,
998 STGM_CREATE | STGM_READWRITE|STGM_SHARE_EXCLUSIVE, &ps);
999 ok(r == STG_E_INVALIDFLAG, "open succeeded\n");
1000 if(r == S_OK)
1001 IPropertyStorage_Release(ps);
1002
1003 /* after deleting it, it should be gone */
1004 r = IPropertySetStorage_Open( propset, &FMTID_SummaryInformation,
1005 STGM_READWRITE|STGM_SHARE_EXCLUSIVE, &ps);
1006 ok(r == STG_E_FILENOTFOUND, "open failed\n");
1007 if(r == S_OK)
1008 IPropertyStorage_Release(ps);
1009
1010 r = IPropertySetStorage_Release( propset );
1011 ok(r == 1, "ref count wrong\n");
1012
1013 r = IStorage_Release(stg);
1014 ok(r == 0, "ref count wrong\n");
1015
1016 DeleteFileA(filenameA);
1017 }
1018
1019 static void test_storage_refcount(void)
1020 {
1021 IStorage *stg = NULL;
1022 IStorage *stgprio = NULL;
1023 HRESULT r;
1024 IStream *stm = NULL;
1025 static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
1026 LARGE_INTEGER pos;
1027 ULARGE_INTEGER upos;
1028 STATSTG stat;
1029 char buffer[10];
1030
1031 DeleteFileA(filenameA);
1032
1033 /* create the file */
1034 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
1035 STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
1036 ok(r==S_OK, "StgCreateDocfile failed\n");
1037
1038 r = WriteClassStg( stg, &test_stg_cls );
1039 ok( r == S_OK, "WriteClassStg failed\n");
1040
1041 r = IStorage_Commit( stg, STGC_DEFAULT );
1042 ok( r == S_OK, "IStorage_Commit failed\n");
1043
1044 /* now create a stream */
1045 r = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
1046 ok(r==S_OK, "IStorage->CreateStream failed\n");
1047
1048 r = IStorage_Release( stg );
1049 ok (r == 0, "storage not released\n");
1050
1051 pos.QuadPart = 0;
1052 r = IStream_Seek( stm, pos, 0, &upos );
1053 ok (r == STG_E_REVERTED, "seek should fail\n");
1054
1055 r = IStream_Stat( stm, &stat, STATFLAG_DEFAULT );
1056 ok (r == STG_E_REVERTED, "stat should fail\n");
1057
1058 r = IStream_Write( stm, "Test string", strlen("Test string"), NULL);
1059 ok (r == STG_E_REVERTED, "IStream_Write should return STG_E_REVERTED instead of 0x%08x\n", r);
1060
1061 r = IStream_Read( stm, buffer, sizeof(buffer), NULL);
1062 ok (r == STG_E_REVERTED, "IStream_Read should return STG_E_REVERTED instead of 0x%08x\n", r);
1063
1064 r = IStream_Release(stm);
1065 ok (r == 0, "stream not released\n");
1066
1067 /* tests that STGM_PRIORITY doesn't prevent readwrite access from other
1068 * StgOpenStorage calls in transacted mode */
1069 r = StgOpenStorage( filename, NULL, STGM_PRIORITY, NULL, 0, &stgprio);
1070 ok(r==S_OK, "StgOpenStorage failed with error 0x%08x\n", r);
1071
1072 /* non-transacted mode read/write fails */
1073 r = StgOpenStorage( filename, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg);
1074 ok(r==STG_E_LOCKVIOLATION, "StgOpenStorage should return STG_E_LOCKVIOLATION instead of 0x%08x\n", r);
1075
1076 /* non-transacted mode read-only succeeds */
1077 r = StgOpenStorage( filename, NULL, STGM_SHARE_DENY_WRITE|STGM_READ, NULL, 0, &stg);
1078 ok(r==S_OK, "StgOpenStorage failed with error 0x%08x\n", r);
1079 IStorage_Release(stg);
1080
1081 r = StgOpenStorage( filename, NULL, STGM_TRANSACTED|STGM_SHARE_DENY_WRITE|STGM_READWRITE, NULL, 0, &stg);
1082 ok(r==S_OK, "StgOpenStorage failed with error 0x%08x\n", r);
1083 if(stg)
1084 {
1085 static const WCHAR stgname[] = { ' ',' ',' ','2','9',0 };
1086 static const WCHAR stgname2[] = { 'C','V','_','i','e','w',0 };
1087 static const WCHAR stmname2[] = { 'V','a','r','2','D','a','t','a',0 };
1088 IStorage *stg2;
1089 IStorage *stg3;
1090 STATSTG statstg;
1091
1092 r = IStorage_Stat( stg, &statstg, STATFLAG_NONAME );
1093 ok(r == S_OK, "Stat should have succeeded instead of returning 0x%08x\n", r);
1094 ok(statstg.type == STGTY_STORAGE, "Statstg type should have been STGTY_STORAGE instead of %d\n", statstg.type);
1095 ok(U(statstg.cbSize).LowPart == 0, "Statstg cbSize.LowPart should have been 0 instead of %d\n", U(statstg.cbSize).LowPart);
1096 ok(U(statstg.cbSize).HighPart == 0, "Statstg cbSize.HighPart should have been 0 instead of %d\n", U(statstg.cbSize).HighPart);
1097 ok(statstg.grfMode == (STGM_TRANSACTED|STGM_SHARE_DENY_WRITE|STGM_READWRITE),
1098 "Statstg grfMode should have been 0x10022 instead of 0x%x\n", statstg.grfMode);
1099 ok(statstg.grfLocksSupported == 0, "Statstg grfLocksSupported should have been 0 instead of %d\n", statstg.grfLocksSupported);
1100 ok(IsEqualCLSID(&statstg.clsid, &test_stg_cls), "Statstg clsid is not test_stg_cls\n");
1101 ok(statstg.grfStateBits == 0, "Statstg grfStateBits should have been 0 instead of %d\n", statstg.grfStateBits);
1102 ok(statstg.reserved == 0, "Statstg reserved should have been 0 instead of %d\n", statstg.reserved);
1103
1104 r = IStorage_CreateStorage( stg, stgname, STGM_SHARE_EXCLUSIVE, 0, 0, &stg2 );
1105 ok(r == S_OK, "CreateStorage should have succeeded instead of returning 0x%08x\n", r);
1106
1107 r = IStorage_Stat( stg2, &statstg, STATFLAG_DEFAULT );
1108 ok(r == S_OK, "Stat should have succeeded instead of returning 0x%08x\n", r);
1109 ok(!memcmp(statstg.pwcsName, stgname, sizeof(stgname)),
1110 "Statstg pwcsName should have been the name the storage was created with\n");
1111 ok(statstg.type == STGTY_STORAGE, "Statstg type should have been STGTY_STORAGE instead of %d\n", statstg.type);
1112 ok(U(statstg.cbSize).LowPart == 0, "Statstg cbSize.LowPart should have been 0 instead of %d\n", U(statstg.cbSize).LowPart);
1113 ok(U(statstg.cbSize).HighPart == 0, "Statstg cbSize.HighPart should have been 0 instead of %d\n", U(statstg.cbSize).HighPart);
1114 ok(statstg.grfMode == STGM_SHARE_EXCLUSIVE,
1115 "Statstg grfMode should have been STGM_SHARE_EXCLUSIVE instead of 0x%x\n", statstg.grfMode);
1116 ok(statstg.grfLocksSupported == 0, "Statstg grfLocksSupported should have been 0 instead of %d\n", statstg.grfLocksSupported);
1117 ok(IsEqualCLSID(&statstg.clsid, &CLSID_NULL), "Statstg clsid is not CLSID_NULL\n");
1118 ok(statstg.grfStateBits == 0, "Statstg grfStateBits should have been 0 instead of %d\n", statstg.grfStateBits);
1119 ok(statstg.reserved == 0, "Statstg reserved should have been 0 instead of %d\n", statstg.reserved);
1120 CoTaskMemFree(statstg.pwcsName);
1121
1122 r = IStorage_CreateStorage( stg2, stgname2, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &stg3 );
1123 ok(r == STG_E_ACCESSDENIED, "CreateStorage should have returned STG_E_ACCESSDENIED instead of 0x%08x\n", r);
1124
1125 r = IStorage_CreateStream( stg2, stmname2, STGM_CREATE|STGM_SHARE_EXCLUSIVE, 0, 0, &stm );
1126 ok(r == STG_E_ACCESSDENIED, "CreateStream should have returned STG_E_ACCESSDENIED instead of 0x%08x\n", r);
1127
1128 IStorage_Release(stg2);
1129
1130 r = IStorage_Release(stg);
1131 ok(r == 0, "wrong ref count\n");
1132 }
1133
1134 /* Multiple STGM_PRIORITY opens are possible. */
1135 r = StgOpenStorage( filename, NULL, STGM_PRIORITY, NULL, 0, &stg);
1136 ok(r==S_OK, "StgOpenStorage failed with error 0x%08x\n", r);
1137 if(stg)
1138 {
1139 r = IStorage_Release(stg);
1140 ok(r == 0, "wrong ref count\n");
1141 }
1142
1143 r = StgOpenStorage( NULL, stgprio, STGM_TRANSACTED|STGM_SHARE_DENY_WRITE|STGM_READWRITE, NULL, 0, &stg);
1144 ok(r==S_OK, "StgOpenStorage failed with error 0x%08x\n", r);
1145 if(stg)
1146 {
1147 static const WCHAR stgname[] = { ' ',' ',' ','2','9',0 };
1148 IStorage *stg2;
1149 STATSTG statstg;
1150
1151 r = IStorage_Stat( stg, &statstg, STATFLAG_NONAME );
1152 ok(r == S_OK, "Stat should have succeeded instead of returning 0x%08x\n", r);
1153 ok(statstg.type == STGTY_STORAGE, "Statstg type should have been STGTY_STORAGE instead of %d\n", statstg.type);
1154 ok(U(statstg.cbSize).LowPart == 0, "Statstg cbSize.LowPart should have been 0 instead of %d\n", U(statstg.cbSize).LowPart);
1155 ok(U(statstg.cbSize).HighPart == 0, "Statstg cbSize.HighPart should have been 0 instead of %d\n", U(statstg.cbSize).HighPart);
1156 ok(statstg.grfMode == (STGM_TRANSACTED|STGM_SHARE_DENY_WRITE|STGM_READWRITE),
1157 "Statstg grfMode should have been 0x10022 instead of 0x%x\n", statstg.grfMode);
1158 ok(statstg.grfLocksSupported == 0, "Statstg grfLocksSupported should have been 0 instead of %d\n", statstg.grfLocksSupported);
1159 ok(IsEqualCLSID(&statstg.clsid, &test_stg_cls), "Statstg clsid is not test_stg_cls\n");
1160 ok(statstg.grfStateBits == 0, "Statstg grfStateBits should have been 0 instead of %d\n", statstg.grfStateBits);
1161 ok(statstg.reserved == 0, "Statstg reserved should have been 0 instead of %d\n", statstg.reserved);
1162
1163 r = IStorage_CreateStorage( stg, stgname, STGM_SHARE_EXCLUSIVE, 0, 0, &stg2 );
1164 ok(r == S_OK, "CreateStorage should have succeeded instead of returning 0x%08x\n", r);
1165
1166 IStorage_Release(stg2);
1167
1168 r = IStorage_Commit( stg, 0 );
1169 ok(r == S_OK, "Commit should have succeeded instead of returning 0x%08x\n", r);
1170
1171 r = IStorage_Release(stg);
1172 ok(r == 0, "wrong ref count\n");
1173 }
1174 /* IStorage_Release(stgprio) not necessary because StgOpenStorage released it. */
1175
1176 DeleteFileA(filenameA);
1177 }
1178
1179 static void test_writeclassstg(void)
1180 {
1181 IStorage *stg = NULL;
1182 HRESULT r;
1183 CLSID temp_cls, cls2;
1184
1185 DeleteFileA(filenameA);
1186
1187 /* create the file */
1188 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
1189 STGM_READWRITE, 0, &stg);
1190 ok(r==S_OK, "StgCreateDocfile failed\n");
1191
1192 r = ReadClassStg( NULL, NULL );
1193 ok(r == E_INVALIDARG, "ReadClassStg should return E_INVALIDARG instead of 0x%08X\n", r);
1194
1195 memset(&temp_cls, 0xcc, sizeof(temp_cls));
1196 memset(&cls2, 0xcc, sizeof(cls2));
1197 r = ReadClassStg( NULL, &temp_cls );
1198 ok(r == E_INVALIDARG, "got 0x%08x\n", r);
1199 ok(IsEqualCLSID(&temp_cls, &cls2), "got wrong clsid\n");
1200
1201 r = ReadClassStg( stg, NULL );
1202 ok(r == E_INVALIDARG, "ReadClassStg should return E_INVALIDARG instead of 0x%08X\n", r);
1203
1204 temp_cls.Data1 = 0xdeadbeef;
1205 r = ReadClassStg( stg, &temp_cls );
1206 ok(r == S_OK, "ReadClassStg failed with 0x%08X\n", r);
1207
1208 ok(IsEqualCLSID(&temp_cls, &CLSID_NULL), "ReadClassStg returned wrong clsid\n");
1209
1210 r = WriteClassStg( NULL, NULL );
1211 ok(r == E_INVALIDARG, "WriteClassStg should return E_INVALIDARG instead of 0x%08X\n", r);
1212
1213 r = WriteClassStg( stg, NULL );
1214 ok(r == STG_E_INVALIDPOINTER, "WriteClassStg should return STG_E_INVALIDPOINTER instead of 0x%08X\n", r);
1215
1216 r = WriteClassStg( stg, &test_stg_cls );
1217 ok( r == S_OK, "WriteClassStg failed with 0x%08X\n", r);
1218
1219 r = ReadClassStg( stg, &temp_cls );
1220 ok( r == S_OK, "ReadClassStg failed with 0x%08X\n", r);
1221 ok(IsEqualCLSID(&temp_cls, &test_stg_cls), "ReadClassStg returned wrong clsid\n");
1222
1223 r = IStorage_Release( stg );
1224 ok (r == 0, "storage not released\n");
1225
1226 DeleteFileA(filenameA);
1227 }
1228
1229 static void test_streamenum(void)
1230 {
1231 IStorage *stg = NULL;
1232 HRESULT r;
1233 IStream *stm = NULL;
1234 static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
1235 static const WCHAR stmname2[] = { 'A','B','C','D','E','F','G','H','I',0 };
1236 static const WCHAR stmname3[] = { 'A','B','C','D','E','F','G','H','I','J',0 };
1237 static const STATSTG stat_null;
1238 STATSTG stat;
1239 IEnumSTATSTG *ee = NULL;
1240 ULONG count;
1241
1242 DeleteFileA(filenameA);
1243
1244 /* create the file */
1245 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
1246 STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
1247 ok(r==S_OK, "StgCreateDocfile failed\n");
1248
1249 r = WriteClassStg( stg, &test_stg_cls );
1250 ok( r == S_OK, "WriteClassStg failed\n");
1251
1252 r = IStorage_Commit( stg, STGC_DEFAULT );
1253 ok( r == S_OK, "IStorage_Commit failed\n");
1254
1255 /* now create a stream */
1256 r = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
1257 ok(r==S_OK, "IStorage->CreateStream failed\n");
1258
1259 IStream_Release(stm);
1260
1261 /* first enum ... should be 1 stream */
1262 r = IStorage_EnumElements(stg, 0, NULL, 0, &ee);
1263 ok(r==S_OK, "IStorage->EnumElements failed\n");
1264
1265 count = 0xf00;
1266 r = IEnumSTATSTG_Next(ee, 1, &stat, &count);
1267 ok(r==S_OK, "IEnumSTATSTG->Next failed\n");
1268 ok(count == 1, "count wrong\n");
1269
1270 if (r == S_OK)
1271 CoTaskMemFree(stat.pwcsName);
1272
1273 r = IEnumSTATSTG_Release(ee);
1274 ok(r==S_OK, "EnumSTATSTG_Release failed with error 0x%08x\n", r);
1275
1276 /* second enum... destroy the stream before reading */
1277 r = IStorage_EnumElements(stg, 0, NULL, 0, &ee);
1278 ok(r==S_OK, "IStorage->EnumElements failed\n");
1279
1280 r = IStorage_DestroyElement(stg, stmname);
1281 ok(r==S_OK, "IStorage->DestroyElement failed\n");
1282
1283 memset(&stat, 0xad, sizeof(stat));
1284 count = 0xf00;
1285 r = IEnumSTATSTG_Next(ee, 1, &stat, &count);
1286 ok(r==S_FALSE, "IEnumSTATSTG->Next failed\n");
1287 ok(count == 0, "count wrong\n");
1288 ok(memcmp(&stat, &stat_null, sizeof(stat)) == 0, "stat is not zeroed\n");
1289
1290 /* reset and try again */
1291 r = IEnumSTATSTG_Reset(ee);
1292 ok(r==S_OK, "IEnumSTATSTG->Reset failed\n");
1293
1294 count = 0xf00;
1295 r = IEnumSTATSTG_Next(ee, 1, &stat, &count);
1296 ok(r==S_FALSE, "IEnumSTATSTG->Next failed\n");
1297 ok(count == 0, "count wrong\n");
1298
1299 /* add a stream before reading */
1300 r = IEnumSTATSTG_Reset(ee);
1301 ok(r==S_OK, "IEnumSTATSTG->Reset failed\n");
1302
1303 r = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
1304 ok(r==S_OK, "IStorage->CreateStream failed\n");
1305
1306 r = IStream_Release(stm);
1307 ok(r==S_OK, "Stream_Release failed with error 0x%08x\n", r);
1308
1309 count = 0xf00;
1310 r = IEnumSTATSTG_Next(ee, 1, &stat, &count);
1311 ok(r==S_OK, "IEnumSTATSTG->Next failed\n");
1312 ok(count == 1, "count wrong\n");
1313
1314 if (r == S_OK)
1315 {
1316 ok(lstrcmpiW(stat.pwcsName, stmname) == 0, "expected CONTENTS, got %s\n", wine_dbgstr_w(stat.pwcsName));
1317 CoTaskMemFree(stat.pwcsName);
1318 }
1319
1320 r = IStorage_CreateStream(stg, stmname2, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
1321 ok(r==S_OK, "IStorage->CreateStream failed\n");
1322
1323 r = IStream_Release(stm);
1324 ok(r==S_OK, "Stream_Release failed with error 0x%08x\n", r);
1325
1326 count = 0xf00;
1327 r = IEnumSTATSTG_Next(ee, 1, &stat, &count);
1328 ok(r==S_OK, "IEnumSTATSTG->Next failed\n");
1329 ok(count == 1, "count wrong\n");
1330
1331 if (r == S_OK)
1332 {
1333 ok(lstrcmpiW(stat.pwcsName, stmname2) == 0, "expected ABCDEFGHI, got %s\n", wine_dbgstr_w(stat.pwcsName));
1334 CoTaskMemFree(stat.pwcsName);
1335 }
1336
1337 /* delete previous and next stream after reading */
1338 r = IStorage_CreateStream(stg, stmname3, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
1339 ok(r==S_OK, "IStorage->CreateStream failed\n");
1340
1341 r = IStream_Release(stm);
1342 ok(r==S_OK, "Stream_Release failed with error 0x%08x\n", r);
1343
1344 r = IEnumSTATSTG_Reset(ee);
1345 ok(r==S_OK, "IEnumSTATSTG->Reset failed\n");
1346
1347 count = 0xf00;
1348 r = IEnumSTATSTG_Next(ee, 1, &stat, &count);
1349 ok(r==S_OK, "IEnumSTATSTG->Next failed\n");
1350 ok(count == 1, "count wrong\n");
1351
1352 if (r == S_OK)
1353 {
1354 ok(lstrcmpiW(stat.pwcsName, stmname) == 0, "expected CONTENTS, got %s\n", wine_dbgstr_w(stat.pwcsName));
1355 CoTaskMemFree(stat.pwcsName);
1356 }
1357
1358 r = IStorage_DestroyElement(stg, stmname);
1359 ok(r==S_OK, "IStorage->DestroyElement failed\n");
1360
1361 r = IStorage_DestroyElement(stg, stmname2);
1362 ok(r==S_OK, "IStorage->DestroyElement failed\n");
1363
1364 count = 0xf00;
1365 r = IEnumSTATSTG_Next(ee, 1, &stat, &count);
1366 ok(r==S_OK, "IEnumSTATSTG->Next failed\n");
1367 ok(count == 1, "count wrong\n");
1368
1369 if (r == S_OK)
1370 {
1371 ok(lstrcmpiW(stat.pwcsName, stmname3) == 0, "expected ABCDEFGHIJ, got %s\n", wine_dbgstr_w(stat.pwcsName));
1372 CoTaskMemFree(stat.pwcsName);
1373 }
1374
1375 r = IStorage_Release( stg );
1376 todo_wine ok (r == 0, "storage not released\n");
1377
1378 /* enumerator is still valid and working after the storage is released */
1379 r = IEnumSTATSTG_Reset(ee);
1380 ok(r==S_OK, "IEnumSTATSTG->Reset failed\n");
1381
1382 count = 0xf00;
1383 r = IEnumSTATSTG_Next(ee, 1, &stat, &count);
1384 ok(r==S_OK, "IEnumSTATSTG->Next failed\n");
1385 ok(count == 1, "count wrong\n");
1386
1387 if (r == S_OK)
1388 {
1389 ok(lstrcmpiW(stat.pwcsName, stmname3) == 0, "expected ABCDEFGHIJ, got %s\n", wine_dbgstr_w(stat.pwcsName));
1390 CoTaskMemFree(stat.pwcsName);
1391 }
1392
1393 /* the storage is left open until the enumerator is freed */
1394 r = StgOpenStorage( filename, NULL, STGM_SHARE_EXCLUSIVE |
1395 STGM_READWRITE |STGM_TRANSACTED, NULL, 0, &stg);
1396 ok(r==STG_E_SHAREVIOLATION ||
1397 r==STG_E_LOCKVIOLATION, /* XP-SP2/W2K3-SP1 and below */
1398 "StgCreateDocfile failed, res=%x\n", r);
1399
1400 r = IEnumSTATSTG_Release(ee);
1401 ok (r == 0, "enum not released\n");
1402
1403 DeleteFileA(filenameA);
1404 }
1405
1406 static void test_transact(void)
1407 {
1408 IStorage *stg = NULL, *stg2 = NULL, *stg3 = NULL;
1409 HRESULT r;
1410 IStream *stm = NULL;
1411 static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
1412 static const WCHAR stmname2[] = { 'F','O','O',0 };
1413 static const WCHAR stgname[] = { 'P','E','R','M','S','T','G',0 };
1414 static const WCHAR stgname2[] = { 'T','E','M','P','S','T','G',0 };
1415 BOOL ret;
1416
1417 DeleteFileA(filenameA);
1418
1419 /* create the file */
1420 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
1421 STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
1422 ok(r==S_OK, "StgCreateDocfile failed\n");
1423
1424 /* commit a new stream and storage */
1425 r = IStorage_CreateStream(stg, stmname2, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
1426 ok(r==S_OK, "IStorage->CreateStream failed\n");
1427
1428 r = IStream_Write(stm, "this is stream 1\n", 16, NULL);
1429 ok(r==S_OK, "IStream->Write failed\n");
1430
1431 IStream_Release(stm);
1432
1433 r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
1434 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
1435
1436 if (r == S_OK)
1437 {
1438 /* Create two substorages but only commit one */
1439 r = IStorage_CreateStorage(stg2, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg3);
1440 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
1441
1442 if (r == S_OK)
1443 IStorage_Release(stg3);
1444
1445 r = IStorage_Commit(stg, 0);
1446 ok(r==S_OK, "IStorage->Commit failed\n");
1447
1448 r = IStorage_CreateStorage(stg2, stgname2, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg3);
1449 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
1450
1451 if (r == S_OK)
1452 IStorage_Release(stg3);
1453
1454 IStorage_Release(stg2);
1455 }
1456
1457 /* now create a stream and storage, but don't commit them */
1458 stm = NULL;
1459 r = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
1460 ok(r==S_OK, "IStorage->CreateStream failed\n");
1461
1462 r = IStream_Write(stm, "this is stream 2\n", 16, NULL);
1463 ok(r==S_OK, "IStream->Write failed\n");
1464
1465 /* IStream::Commit does nothing for OLE storage streams */
1466 r = IStream_Commit(stm, STGC_ONLYIFCURRENT | STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE);
1467 ok(r==S_OK, "IStream->Commit failed\n");
1468
1469 r = IStorage_CreateStorage(stg, stgname2, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
1470 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
1471
1472 if (r == S_OK)
1473 IStorage_Release(stg2);
1474
1475 IStream_Release(stm);
1476
1477 IStorage_Release(stg);
1478
1479 stm = NULL;
1480 stg = NULL;
1481 r = StgOpenStorage( filename, NULL, STGM_SHARE_DENY_NONE | STGM_READ | STGM_TRANSACTED, NULL, 0, &stg);
1482 ok(r==S_OK, "StgOpenStorage failed\n");
1483
1484 if (!stg)
1485 return;
1486
1487 r = IStorage_OpenStream(stg, stmname, NULL, STGM_SHARE_DENY_NONE|STGM_READ, 0, &stm );
1488 ok(r==STG_E_INVALIDFLAG, "IStorage->OpenStream failed %08x\n", r);
1489
1490 r = IStorage_OpenStream(stg, stmname, NULL, STGM_DELETEONRELEASE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
1491 ok(r==STG_E_INVALIDFUNCTION, "IStorage->OpenStream failed %08x\n", r);
1492
1493 r = IStorage_OpenStream(stg, stmname, NULL, STGM_TRANSACTED|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
1494 ok(r==STG_E_INVALIDFUNCTION, "IStorage->OpenStream failed %08x\n", r);
1495
1496 r = IStorage_OpenStorage(stg, stmname, NULL, STGM_TRANSACTED|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg2 );
1497 ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStream failed %08x\n", r);
1498
1499 r = IStorage_OpenStream(stg, stmname, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
1500 ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStream should fail %08x\n", r);
1501 if (r == S_OK)
1502 IStream_Release(stm);
1503
1504 r = IStorage_OpenStorage(stg, stgname2, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg2 );
1505 ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStorage should fail %08x\n", r);
1506 if (r == S_OK)
1507 IStorage_Release(stg2);
1508
1509 r = IStorage_OpenStorage(stg, stmname2, NULL, STGM_TRANSACTED|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg2 );
1510 ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStream failed %08x\n", r);
1511
1512 r = IStorage_OpenStream(stg, stmname2, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
1513 ok(r==S_OK, "IStorage->OpenStream should succeed %08x\n", r);
1514 if (r == S_OK)
1515 IStream_Release(stm);
1516
1517 r = IStorage_OpenStorage(stg, stgname, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg2 );
1518 ok(r==S_OK, "IStorage->OpenStorage should succeed %08x\n", r);
1519 if (r == S_OK)
1520 {
1521 r = IStorage_OpenStorage(stg2, stgname, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg3 );
1522 ok(r==S_OK, "IStorage->OpenStorage should succeed %08x\n", r);
1523 if (r == S_OK)
1524 IStorage_Release(stg3);
1525
1526 r = IStorage_OpenStorage(stg2, stgname2, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg3 );
1527 ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStorage should fail %08x\n", r);
1528 if (r == S_OK)
1529 IStorage_Release(stg3);
1530
1531 IStorage_Release(stg2);
1532 }
1533
1534 IStorage_Release(stg);
1535
1536 ret = DeleteFileA(filenameA);
1537 ok(ret, "deleted file\n");
1538 }
1539
1540 static void test_substorage_share(void)
1541 {
1542 IStorage *stg, *stg2, *stg3;
1543 IStream *stm, *stm2;
1544 HRESULT r;
1545 static const WCHAR stgname[] = { 'P','E','R','M','S','T','G',0 };
1546 static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
1547 static const WCHAR othername[] = { 'N','E','W','N','A','M','E',0 };
1548 BOOL ret;
1549
1550 DeleteFileA(filenameA);
1551
1552 /* create the file */
1553 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
1554 STGM_READWRITE, 0, &stg);
1555 ok(r==S_OK, "StgCreateDocfile failed\n");
1556
1557 /* create a read/write storage and try to open it again */
1558 r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
1559 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
1560
1561 if (r == S_OK)
1562 {
1563 r = IStorage_OpenStorage(stg, stgname, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg3);
1564 ok(r==STG_E_ACCESSDENIED, "IStorage->OpenStorage should fail %08x\n", r);
1565
1566 if (r == S_OK)
1567 IStorage_Release(stg3);
1568
1569 r = IStorage_OpenStorage(stg, stgname, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, 0, &stg3);
1570 ok(r==STG_E_ACCESSDENIED, "IStorage->OpenStorage should fail %08x\n", r);
1571
1572 if (r == S_OK)
1573 IStorage_Release(stg3);
1574
1575 /* cannot rename the storage while it's open */
1576 r = IStorage_RenameElement(stg, stgname, othername);
1577 ok(r==STG_E_ACCESSDENIED, "IStorage->RenameElement should fail %08x\n", r);
1578 if (SUCCEEDED(r)) IStorage_RenameElement(stg, othername, stgname);
1579
1580 /* destroying an object while it's open invalidates it */
1581 r = IStorage_DestroyElement(stg, stgname);
1582 ok(r==S_OK, "IStorage->DestroyElement failed, hr=%08x\n", r);
1583
1584 r = IStorage_CreateStream(stg2, stmname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm);
1585 ok(r==STG_E_REVERTED, "IStorage->CreateStream failed, hr=%08x\n", r);
1586
1587 if (r == S_OK)
1588 IStream_Release(stm);
1589
1590 IStorage_Release(stg2);
1591 }
1592
1593 /* create a read/write stream and try to open it again */
1594 r = IStorage_CreateStream(stg, stmname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm);
1595 ok(r==S_OK, "IStorage->CreateStream failed, hr=%08x\n", r);
1596
1597 if (r == S_OK)
1598 {
1599 r = IStorage_OpenStream(stg, stmname, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &stm2);
1600 ok(r==STG_E_ACCESSDENIED, "IStorage->OpenStream should fail %08x\n", r);
1601
1602 if (r == S_OK)
1603 IStream_Release(stm2);
1604
1605 r = IStorage_OpenStream(stg, stmname, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm2);
1606 ok(r==STG_E_ACCESSDENIED, "IStorage->OpenStream should fail %08x\n", r);
1607
1608 if (r == S_OK)
1609 IStream_Release(stm2);
1610
1611 /* cannot rename the stream while it's open */
1612 r = IStorage_RenameElement(stg, stmname, othername);
1613 ok(r==STG_E_ACCESSDENIED, "IStorage->RenameElement should fail %08x\n", r);
1614 if (SUCCEEDED(r)) IStorage_RenameElement(stg, othername, stmname);
1615
1616 /* destroying an object while it's open invalidates it */
1617 r = IStorage_DestroyElement(stg, stmname);
1618 ok(r==S_OK, "IStorage->DestroyElement failed, hr=%08x\n", r);
1619
1620 r = IStream_Write(stm, "this shouldn't work\n", 20, NULL);
1621 ok(r==STG_E_REVERTED, "IStream_Write should fail %08x\n", r);
1622
1623 IStream_Release(stm);
1624 }
1625
1626 IStorage_Release(stg);
1627
1628 ret = DeleteFileA(filenameA);
1629 ok(ret, "deleted file\n");
1630 }
1631
1632 static void test_revert(void)
1633 {
1634 IStorage *stg = NULL, *stg2 = NULL, *stg3 = NULL;
1635 HRESULT r;
1636 IStream *stm = NULL, *stm2 = NULL;
1637 static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
1638 static const WCHAR stmname2[] = { 'F','O','O',0 };
1639 static const WCHAR stgname[] = { 'P','E','R','M','S','T','G',0 };
1640 static const WCHAR stgname2[] = { 'T','E','M','P','S','T','G',0 };
1641 STATSTG statstg;
1642 BOOL ret;
1643
1644 DeleteFileA(filenameA);
1645
1646 /* create the file */
1647 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
1648 STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
1649 ok(r==S_OK, "StgCreateDocfile failed\n");
1650
1651 /* commit a new stream and storage */
1652 r = IStorage_CreateStream(stg, stmname2, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
1653 ok(r==S_OK, "IStorage->CreateStream failed\n");
1654
1655 r = IStream_Write(stm, "this is stream 1\n", 16, NULL);
1656 ok(r==S_OK, "IStream->Write failed\n");
1657
1658 r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
1659 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
1660
1661 if (r == S_OK)
1662 {
1663 /* Create two substorages but only commit one */
1664 r = IStorage_CreateStorage(stg2, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg3);
1665 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
1666
1667 if (r == S_OK)
1668 IStorage_Release(stg3);
1669
1670 r = IStorage_Commit(stg, 0);
1671 ok(r==S_OK, "IStorage->Commit failed\n");
1672
1673 r = IStorage_CreateStorage(stg2, stgname2, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg3);
1674 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
1675
1676 if (r == S_OK)
1677 IStorage_Release(stg3);
1678 }
1679
1680 /* now create a stream and storage, then revert */
1681 r = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm2 );
1682 ok(r==S_OK, "IStorage->CreateStream failed\n");
1683
1684 r = IStream_Write(stm2, "this is stream 2\n", 16, NULL);
1685 ok(r==S_OK, "IStream->Write failed\n");
1686
1687 r = IStorage_CreateStorage(stg, stgname2, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg3);
1688 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
1689
1690 r = IStorage_Revert(stg);
1691 ok(r==S_OK, "Storage_Revert failed with error 0x%08x\n", r);
1692
1693 /* all open objects become invalid */
1694 r = IStream_Write(stm, "this shouldn't work\n", 20, NULL);
1695 ok(r==STG_E_REVERTED, "IStream_Write should fail %08x\n", r);
1696
1697 r = IStream_Write(stm2, "this shouldn't work\n", 20, NULL);
1698 ok(r==STG_E_REVERTED, "IStream_Write should fail %08x\n", r);
1699
1700 r = IStorage_Stat(stg2, &statstg, STATFLAG_NONAME);
1701 ok(r==STG_E_REVERTED, "IStorage_Stat should fail %08x\n", r);
1702
1703 r = IStorage_Stat(stg3, &statstg, STATFLAG_NONAME);
1704 ok(r==STG_E_REVERTED, "IStorage_Stat should fail %08x\n", r);
1705
1706 IStream_Release(stm);
1707 IStream_Release(stm2);
1708 IStorage_Release(stg2);
1709 IStorage_Release(stg3);
1710
1711 r = IStorage_OpenStream(stg, stmname, NULL, STGM_SHARE_DENY_NONE|STGM_READ, 0, &stm );
1712 ok(r==STG_E_INVALIDFLAG, "IStorage->OpenStream failed %08x\n", r);
1713
1714 r = IStorage_OpenStream(stg, stmname, NULL, STGM_DELETEONRELEASE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
1715 ok(r==STG_E_INVALIDFUNCTION, "IStorage->OpenStream failed %08x\n", r);
1716
1717 r = IStorage_OpenStream(stg, stmname, NULL, STGM_TRANSACTED|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
1718 ok(r==STG_E_INVALIDFUNCTION, "IStorage->OpenStream failed %08x\n", r);
1719
1720 r = IStorage_OpenStorage(stg, stmname, NULL, STGM_TRANSACTED|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg2 );
1721 ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStream failed %08x\n", r);
1722
1723 r = IStorage_OpenStream(stg, stmname, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
1724 ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStream should fail %08x\n", r);
1725 if (r == S_OK)
1726 IStream_Release(stm);
1727
1728 r = IStorage_OpenStorage(stg, stgname2, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg2 );
1729 ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStorage should fail %08x\n", r);
1730 if (r == S_OK)
1731 IStorage_Release(stg2);
1732
1733 r = IStorage_OpenStorage(stg, stmname2, NULL, STGM_TRANSACTED|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg2 );
1734 ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStream failed %08x\n", r);
1735
1736 r = IStorage_OpenStream(stg, stmname2, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
1737 ok(r==S_OK, "IStorage->OpenStream should succeed %08x\n", r);
1738 if (r == S_OK)
1739 IStream_Release(stm);
1740
1741 r = IStorage_OpenStorage(stg, stgname, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg2 );
1742 ok(r==S_OK, "IStorage->OpenStorage should succeed %08x\n", r);
1743 if (r == S_OK)
1744 {
1745 r = IStorage_OpenStorage(stg2, stgname, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg3 );
1746 ok(r==S_OK, "IStorage->OpenStorage should succeed %08x\n", r);
1747 if (r == S_OK)
1748 IStorage_Release(stg3);
1749
1750 r = IStorage_OpenStorage(stg2, stgname2, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg3 );
1751 ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStorage should fail %08x\n", r);
1752 if (r == S_OK)
1753 IStorage_Release(stg3);
1754
1755 IStorage_Release(stg2);
1756 }
1757
1758 IStorage_Release(stg);
1759
1760 ret = DeleteFileA(filenameA);
1761 ok(ret, "deleted file\n");
1762
1763 /* Revert only invalidates objects in transacted mode */
1764 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
1765 STGM_READWRITE, 0, &stg);
1766 ok(r==S_OK, "StgCreateDocfile failed\n");
1767
1768 r = IStorage_CreateStream(stg, stmname2, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
1769 ok(r==S_OK, "IStorage->CreateStream failed\n");
1770
1771 r = IStorage_Revert(stg);
1772 ok(r==S_OK, "IStorage->Revert failed %08x\n", r);
1773
1774 r = IStream_Write(stm, "this works\n", 11, NULL);
1775 ok(r==S_OK, "IStream_Write should succeed %08x\n", r);
1776
1777 IStream_Release(stm);
1778 IStorage_Release(stg);
1779
1780 ret = DeleteFileA(filenameA);
1781 ok(ret, "deleted file\n");
1782 }
1783
1784 static void test_parent_free(void)
1785 {
1786 IStorage *stg = NULL, *stg2 = NULL, *stg3 = NULL;
1787 HRESULT r;
1788 IStream *stm = NULL;
1789 static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
1790 static const WCHAR stgname[] = { 'P','E','R','M','S','T','G',0 };
1791 ULONG ref;
1792 STATSTG statstg;
1793 BOOL ret;
1794
1795 DeleteFileA(filenameA);
1796
1797 /* create the file */
1798 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
1799 STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
1800 ok(r==S_OK, "StgCreateDocfile failed\n");
1801
1802 /* create a new storage */
1803 r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
1804 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
1805
1806 if (r == S_OK)
1807 {
1808 /* now create a stream inside the new storage */
1809 r = IStorage_CreateStream(stg2, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
1810 ok(r==S_OK, "IStorage->CreateStream failed\n");
1811
1812 if (r == S_OK)
1813 {
1814 /* create a storage inside the new storage */
1815 r = IStorage_CreateStorage(stg2, stgname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stg3 );
1816 ok(r==S_OK, "IStorage->CreateStorage failed\n");
1817 }
1818
1819 /* free the parent */
1820 ref = IStorage_Release(stg2);
1821 ok(ref == 0, "IStorage still has %u references\n", ref);
1822
1823 /* child objects are invalid */
1824 if (r == S_OK)
1825 {
1826 r = IStream_Write(stm, "this should fail\n", 17, NULL);
1827 ok(r==STG_E_REVERTED, "IStream->Write should fail, hr=%x\n", r);
1828
1829 IStream_Release(stm);
1830
1831 r = IStorage_Stat(stg3, &statstg, STATFLAG_NONAME);
1832 ok(r==STG_E_REVERTED, "IStorage_Stat should fail %08x\n", r);
1833
1834 r = IStorage_SetStateBits(stg3, 1, 1);
1835 ok(r==STG_E_REVERTED, "IStorage_Stat should fail %08x\n", r);
1836
1837 IStorage_Release(stg3);
1838 }
1839 }
1840
1841 IStorage_Release(stg);
1842
1843 ret = DeleteFileA(filenameA);
1844 ok(ret, "deleted file\n");
1845 }
1846
1847 static void test_nonroot_transacted(void)
1848 {
1849 IStorage *stg = NULL, *stg2 = NULL, *stg3 = NULL;
1850 HRESULT r;
1851 IStream *stm = NULL;
1852 static const WCHAR stgname[] = { 'P','E','R','M','S','T','G',0 };
1853 static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
1854 static const WCHAR stmname2[] = { 'F','O','O',0 };
1855 BOOL ret;
1856
1857 DeleteFileA(filenameA);
1858
1859 /* create a transacted file */
1860 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
1861 STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
1862 ok(r==S_OK, "StgCreateDocfile failed\n");
1863
1864 /* create a transacted substorage */
1865 r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_TRANSACTED, 0, 0, &stg2);
1866 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
1867
1868 if (r == S_OK)
1869 {
1870 /* create and commit stmname */
1871 r = IStorage_CreateStream(stg2, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
1872 ok(r==S_OK, "IStorage->CreateStream failed\n");
1873 if (r == S_OK)
1874 IStream_Release(stm);
1875
1876 IStorage_Commit(stg2, 0);
1877
1878 /* create and revert stmname2 */
1879 r = IStorage_CreateStream(stg2, stmname2, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
1880 ok(r==S_OK, "IStorage->CreateStream failed\n");
1881 if (r == S_OK)
1882 IStream_Release(stm);
1883
1884 IStorage_Revert(stg2);
1885
1886 /* check that Commit and Revert really worked */
1887 r = IStorage_OpenStream(stg2, stmname, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
1888 ok(r==S_OK, "IStorage->OpenStream should succeed %08x\n", r);
1889 if (r == S_OK)
1890 IStream_Release(stm);
1891
1892 r = IStorage_OpenStream(stg2, stmname2, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
1893 ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStream should fail %08x\n", r);
1894 if (r == S_OK)
1895 IStream_Release(stm);
1896
1897 IStorage_Release(stg2);
1898 }
1899
1900 /* create a read-only transacted substorage */
1901 r = IStorage_OpenStorage(stg, stgname, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE | STGM_TRANSACTED, NULL, 0, &stg2);
1902 ok(r==S_OK, "IStorage->OpenStorage failed, hr=%08x\n", r);
1903
1904 if (r == S_OK)
1905 {
1906 /* The storage can be modified. */
1907 r = IStorage_CreateStorage(stg2, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg3);
1908 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
1909 if (r == S_OK)
1910 IStorage_Release(stg3);
1911
1912 /* But changes cannot be committed. */
1913 r = IStorage_Commit(stg2, 0);
1914 ok(r==STG_E_ACCESSDENIED, "IStorage->Commit should fail, hr=%08x\n", r);
1915
1916 IStorage_Release(stg2);
1917 }
1918
1919 IStorage_Release(stg);
1920
1921 /* create a non-transacted file */
1922 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
1923 STGM_READWRITE, 0, &stg);
1924 ok(r==S_OK, "StgCreateDocfile failed\n");
1925
1926 /* create a transacted substorage */
1927 r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_TRANSACTED, 0, 0, &stg2);
1928 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
1929
1930 if (r == S_OK)
1931 {
1932 /* create and commit stmname */
1933 r = IStorage_CreateStream(stg2, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
1934 ok(r==S_OK, "IStorage->CreateStream failed\n");
1935 if (r == S_OK)
1936 IStream_Release(stm);
1937
1938 IStorage_Commit(stg2, 0);
1939
1940 /* create and revert stmname2 */
1941 r = IStorage_CreateStream(stg2, stmname2, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
1942 ok(r==S_OK, "IStorage->CreateStream failed\n");
1943 if (r == S_OK)
1944 IStream_Release(stm);
1945
1946 IStorage_Revert(stg2);
1947
1948 /* check that Commit and Revert really worked */
1949 r = IStorage_OpenStream(stg2, stmname, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
1950 ok(r==S_OK, "IStorage->OpenStream should succeed %08x\n", r);
1951 if (r == S_OK)
1952 IStream_Release(stm);
1953
1954 r = IStorage_OpenStream(stg2, stmname2, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
1955 ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStream should fail %08x\n", r);
1956 if (r == S_OK)
1957 IStream_Release(stm);
1958
1959 IStorage_Release(stg2);
1960 }
1961
1962 IStorage_Release(stg);
1963
1964 ret = DeleteFileA(filenameA);
1965 ok(ret, "deleted file\n");
1966 }
1967
1968 static void test_ReadClassStm(void)
1969 {
1970 CLSID clsid, clsid2;
1971 HRESULT hr;
1972 IStream *pStream;
1973 static const LARGE_INTEGER llZero;
1974
1975 hr = ReadClassStm(NULL, &clsid);
1976 ok(hr == E_INVALIDARG, "ReadClassStm should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1977
1978 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1979 ok_ole_success(hr, "CreateStreamOnHGlobal");
1980 hr = WriteClassStm(pStream, &test_stg_cls);
1981 ok_ole_success(hr, "WriteClassStm");
1982
1983 hr = ReadClassStm(pStream, NULL);
1984 ok(hr == E_INVALIDARG, "ReadClassStm should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1985
1986 memset(&clsid, 0xcc, sizeof(clsid));
1987 memset(&clsid2, 0xcc, sizeof(clsid2));
1988 hr = ReadClassStm(NULL, &clsid);
1989 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1990 ok(IsEqualCLSID(&clsid, &clsid2), "got wrong clsid\n");
1991
1992 /* test not rewound stream */
1993 hr = ReadClassStm(pStream, &clsid);
1994 ok(hr == STG_E_READFAULT, "ReadClassStm should have returned STG_E_READFAULT instead of 0x%08x\n", hr);
1995 ok(IsEqualCLSID(&clsid, &CLSID_NULL), "clsid should have been zeroed\n");
1996
1997 hr = IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
1998 ok_ole_success(hr, "IStream_Seek");
1999 hr = ReadClassStm(pStream, &clsid);
2000 ok_ole_success(hr, "ReadClassStm");
2001 ok(IsEqualCLSID(&clsid, &test_stg_cls), "clsid should have been set to CLSID_WineTest\n");
2002
2003 IStream_Release(pStream);
2004 }
2005
2006 struct access_res
2007 {
2008 BOOL gothandle;
2009 DWORD lasterr;
2010 BOOL ignore;
2011 };
2012
2013 static const struct access_res create[16] =
2014 {
2015 { TRUE, ERROR_SUCCESS, TRUE },
2016 { TRUE, ERROR_SUCCESS, TRUE },
2017 { TRUE, ERROR_SUCCESS, FALSE },
2018 { TRUE, ERROR_SUCCESS, FALSE },
2019 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2020 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2021 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2022 { TRUE, ERROR_SUCCESS, FALSE },
2023 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2024 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2025 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2026 { TRUE, ERROR_SUCCESS, TRUE },
2027 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2028 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2029 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2030 { TRUE, ERROR_SUCCESS, TRUE }
2031 };
2032
2033 static const struct access_res create_commit[16] =
2034 {
2035 { TRUE, ERROR_SUCCESS, TRUE },
2036 { TRUE, ERROR_SUCCESS, TRUE },
2037 { TRUE, ERROR_SUCCESS, FALSE },
2038 { TRUE, ERROR_SUCCESS, FALSE },
2039 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2040 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2041 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2042 { TRUE, ERROR_SUCCESS, FALSE },
2043 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2044 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2045 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2046 { TRUE, ERROR_SUCCESS, TRUE },
2047 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2048 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2049 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2050 { TRUE, ERROR_SUCCESS, TRUE }
2051 };
2052
2053 static const struct access_res create_close[16] =
2054 {
2055 { TRUE, ERROR_SUCCESS, FALSE },
2056 { TRUE, ERROR_SUCCESS, FALSE },
2057 { TRUE, ERROR_SUCCESS, FALSE },
2058 { TRUE, ERROR_SUCCESS, FALSE },
2059 { TRUE, ERROR_SUCCESS, FALSE },
2060 { TRUE, ERROR_SUCCESS, FALSE },
2061 { TRUE, ERROR_SUCCESS, FALSE },
2062 { TRUE, ERROR_SUCCESS, FALSE },
2063 { TRUE, ERROR_SUCCESS, FALSE },
2064 { TRUE, ERROR_SUCCESS, FALSE },
2065 { TRUE, ERROR_SUCCESS, FALSE },
2066 { TRUE, ERROR_SUCCESS, FALSE },
2067 { TRUE, ERROR_SUCCESS, FALSE },
2068 { TRUE, ERROR_SUCCESS, FALSE },
2069 { TRUE, ERROR_SUCCESS, FALSE },
2070 { TRUE, ERROR_SUCCESS }
2071 };
2072
2073 static const DWORD access_modes[4] = {
2074 0,
2075 GENERIC_READ,
2076 GENERIC_WRITE,
2077 GENERIC_READ | GENERIC_WRITE
2078 };
2079
2080 static const DWORD share_modes[4] = {
2081 0,
2082 FILE_SHARE_READ,
2083 FILE_SHARE_WRITE,
2084 FILE_SHARE_READ | FILE_SHARE_WRITE
2085 };
2086
2087 static void _test_file_access(LPCSTR file, const struct access_res *ares, DWORD line)
2088 {
2089 int i, j, idx = 0;
2090
2091 for (i = 0; i < ARRAY_SIZE(access_modes); i++)
2092 {
2093 for (j = 0; j < ARRAY_SIZE(share_modes); j++)
2094 {
2095 DWORD lasterr;
2096 HANDLE hfile;
2097
2098 if (ares[idx].ignore)
2099 continue;
2100
2101 SetLastError(0xdeadbeef);
2102 hfile = CreateFileA(file, access_modes[i], share_modes[j], NULL, OPEN_EXISTING,
2103 FILE_ATTRIBUTE_NORMAL, 0);
2104 lasterr = GetLastError();
2105
2106 ok((hfile != INVALID_HANDLE_VALUE) == ares[idx].gothandle,
2107 "(%d, handle, %d): Expected %d, got %d\n",
2108 line, idx, ares[idx].gothandle,
2109 (hfile != INVALID_HANDLE_VALUE));
2110
2111 ok(lasterr == ares[idx].lasterr ||
2112 broken(lasterr == 0xdeadbeef) /* win9x */,
2113 "(%d, lasterr, %d): Expected %d, got %d\n",
2114 line, idx, ares[idx].lasterr, lasterr);
2115
2116 CloseHandle(hfile);
2117 idx++;
2118 }
2119 }
2120 }
2121
2122 #define test_file_access(file, ares) _test_file_access(file, ares, __LINE__)
2123
2124 static void test_access(void)
2125 {
2126 static const WCHAR fileW[] = {'w','i','n','e','t','e','s','t',0};
2127 static const char fileA[] = "winetest";
2128 IStorage *stg;
2129 HRESULT hr;
2130
2131 /* STGM_TRANSACTED */
2132 hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE |
2133 STGM_SHARE_EXCLUSIVE | STGM_TRANSACTED, 0, &stg);
2134 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2135
2136 test_file_access(fileA, create);
2137
2138 hr = IStorage_Commit(stg, STGC_DEFAULT);
2139 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2140
2141 test_file_access(fileA, create_commit);
2142
2143 IStorage_Release(stg);
2144
2145 test_file_access(fileA, create_close);
2146
2147 DeleteFileA(fileA);
2148
2149 /* STGM_DIRECT */
2150 hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE |
2151 STGM_SHARE_EXCLUSIVE | STGM_DIRECT, 0, &stg);
2152 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2153
2154 test_file_access(fileA, create);
2155
2156 hr = IStorage_Commit(stg, STGC_DEFAULT);
2157 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2158
2159 test_file_access(fileA, create_commit);
2160
2161 IStorage_Release(stg);
2162
2163 test_file_access(fileA, create_close);
2164
2165 DeleteFileA(fileA);
2166
2167 /* STGM_SHARE_DENY_NONE */
2168 hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE |
2169 STGM_SHARE_DENY_NONE | STGM_TRANSACTED, 0, &stg);
2170 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2171
2172 test_file_access(fileA, create);
2173
2174 hr = IStorage_Commit(stg, STGC_DEFAULT);
2175 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2176
2177 test_file_access(fileA, create_commit);
2178
2179 IStorage_Release(stg);
2180
2181 test_file_access(fileA, create_close);
2182
2183 DeleteFileA(fileA);
2184
2185 /* STGM_SHARE_DENY_READ */
2186 hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE |
2187 STGM_SHARE_DENY_READ | STGM_TRANSACTED, 0, &stg);
2188 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2189
2190 test_file_access(fileA, create);
2191
2192 hr = IStorage_Commit(stg, STGC_DEFAULT);
2193 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2194
2195 test_file_access(fileA, create_commit);
2196
2197 IStorage_Release(stg);
2198
2199 test_file_access(fileA, create_close);
2200
2201 DeleteFileA(fileA);
2202
2203 /* STGM_SHARE_DENY_WRITE */
2204 hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE |
2205 STGM_SHARE_DENY_WRITE | STGM_TRANSACTED, 0, &stg);
2206 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2207
2208 test_file_access(fileA, create);
2209
2210 hr = IStorage_Commit(stg, STGC_DEFAULT);
2211 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2212
2213 test_file_access(fileA, create_commit);
2214
2215 IStorage_Release(stg);
2216
2217 test_file_access(fileA, create_close);
2218
2219 DeleteFileA(fileA);
2220
2221 /* STGM_DIRECT_SWMR | STGM_READ | STGM_SHARE_DENY_NONE - reader mode for direct SWMR mode */
2222 hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE | STGM_SHARE_DENY_WRITE | STGM_TRANSACTED, 0, &stg);
2223 ok(hr == S_OK, "got %08x\n", hr);
2224 IStorage_Release(stg);
2225
2226 hr = StgOpenStorage(fileW, NULL, STGM_DIRECT_SWMR | STGM_READ | STGM_SHARE_DENY_NONE, NULL, 0, &stg);
2227 ok(hr == S_OK || broken(hr == STG_E_INVALIDFLAG), "got %08x\n", hr);
2228 if(hr != S_OK)
2229 return;
2230
2231 test_file_access(fileA, create);
2232
2233 IStorage_Release(stg);
2234 test_file_access(fileA, create_close);
2235
2236 DeleteFileA(fileA);
2237 }
2238
2239 static void test_readonly(void)
2240 {
2241 IStorage *stg, *stg2, *stg3;
2242 IStream *stream;
2243 HRESULT hr;
2244 static const WCHAR fileW[] = {'w','i','n','e','t','e','s','t',0};
2245 static const WCHAR storageW[] = {'s','t','o','r','a','g','e',0};
2246 static const WCHAR streamW[] = {'s','t','r','e','a','m',0};
2247
2248 hr = StgCreateDocfile( fileW, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &stg);
2249 ok(hr == S_OK, "should succeed, res=%x\n", hr);
2250 if (SUCCEEDED(hr))
2251 {
2252 hr = IStorage_CreateStorage( stg, storageW, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stg2 );
2253 ok(hr == S_OK, "should succeed, res=%x\n", hr);
2254 if (SUCCEEDED(hr))
2255 {
2256 hr = IStorage_CreateStream( stg2, streamW, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stream );
2257 ok(hr == S_OK, "should succeed, res=%x\n", hr);
2258 if (SUCCEEDED(hr))
2259 IStream_Release(stream);
2260 IStorage_Release(stg2);
2261 }
2262 IStorage_Release(stg);
2263 }
2264
2265 /* re-open read only */
2266 hr = StgOpenStorage( fileW, NULL, STGM_TRANSACTED | STGM_SHARE_DENY_NONE | STGM_READ, NULL, 0, &stg);
2267 ok(hr == S_OK, "should succeed, res=%x\n", hr);
2268 if (SUCCEEDED(hr))
2269 {
2270 hr = IStorage_OpenStorage( stg, storageW, NULL, STGM_SHARE_EXCLUSIVE | STGM_READ, NULL, 0, &stg2 );
2271 ok(hr == S_OK, "should succeed, res=%x\n", hr);
2272 if (SUCCEEDED(hr))
2273 {
2274 /* CreateStream on read-only storage, name exists */
2275 hr = IStorage_CreateStream( stg2, streamW, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READ, 0, 0, &stream );
2276 ok(hr == STG_E_ACCESSDENIED, "should fail, res=%x\n", hr);
2277 if (SUCCEEDED(hr))
2278 IStream_Release(stream);
2279
2280 /* CreateStream on read-only storage, name does not exist */
2281 hr = IStorage_CreateStream( stg2, storageW, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READ, 0, 0, &stream );
2282 ok(hr == STG_E_ACCESSDENIED, "should fail, res=%x\n", hr);
2283 if (SUCCEEDED(hr))
2284 IStream_Release(stream);
2285
2286 /* CreateStorage on read-only storage, name exists */
2287 hr = IStorage_CreateStorage( stg2, streamW, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READ, 0, 0, &stg3 );
2288 ok(hr == STG_E_FILEALREADYEXISTS, "should fail, res=%x\n", hr);
2289 if (SUCCEEDED(hr))
2290 IStorage_Release(stg3);
2291
2292 /* CreateStorage on read-only storage, name does not exist */
2293 hr = IStorage_CreateStorage( stg2, storageW, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READ, 0, 0, &stg3 );
2294 ok(hr == STG_E_ACCESSDENIED, "should fail, res=%x\n", hr);
2295 if (SUCCEEDED(hr))
2296 IStorage_Release(stg3);
2297
2298 /* DestroyElement on read-only storage, name exists */
2299 hr = IStorage_DestroyElement( stg2, streamW );
2300 ok(hr == STG_E_ACCESSDENIED, "should fail, res=%x\n", hr);
2301
2302 /* DestroyElement on read-only storage, name does not exist */
2303 hr = IStorage_DestroyElement( stg2, storageW );
2304 ok(hr == STG_E_ACCESSDENIED, "should fail, res=%x\n", hr);
2305
2306 IStorage_Release(stg2);
2307 }
2308
2309 IStorage_Release(stg);
2310 }
2311
2312 DeleteFileA("winetest");
2313 }
2314
2315 static void test_simple(void)
2316 {
2317 /* Tests for STGM_SIMPLE mode */
2318
2319 IStorage *stg, *stg2;
2320 HRESULT r;
2321 IStream *stm;
2322 static const WCHAR stgname[] = { 'S','t','g',0 };
2323 static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
2324 static const WCHAR stmname2[] = { 'S','m','a','l','l',0 };
2325 LARGE_INTEGER pos;
2326 ULARGE_INTEGER upos;
2327 DWORD count;
2328 STATSTG stat;
2329
2330 DeleteFileA(filenameA);
2331
2332 r = StgCreateDocfile( filename, STGM_SIMPLE | STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &stg);
2333 ok(r == S_OK, "got %08x\n", r);
2334
2335 r = IStorage_CreateStorage(stg, stgname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stg2);
2336 ok(r == STG_E_INVALIDFUNCTION, "got %08x\n", r);
2337 if (SUCCEEDED(r)) IStorage_Release(stg2);
2338
2339 r = IStorage_CreateStream(stg, stmname, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm);
2340 ok(r == STG_E_INVALIDFLAG, "got %08x\n", r);
2341 r = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm);
2342 ok(r == S_OK, "got %08x\n", r);
2343
2344 upos.QuadPart = 6000;
2345 r = IStream_SetSize(stm, upos);
2346 ok(r == S_OK, "got %08x\n", r);
2347
2348 r = IStream_Write(stm, "foo", 3, &count);
2349 ok(r == S_OK, "got %08x\n", r);
2350 ok(count == 3, "got %d\n", count);
2351
2352 pos.QuadPart = 0;
2353 r = IStream_Seek(stm, pos, STREAM_SEEK_CUR, &upos);
2354 ok(r == S_OK, "got %08x\n", r);
2355 ok(upos.QuadPart == 3, "got %d\n", upos.u.LowPart);
2356
2357 r = IStream_Stat(stm, &stat, STATFLAG_NONAME);
2358 ok(r == S_OK ||
2359 broken(r == STG_E_INVALIDFUNCTION), /* NT4 and below */
2360 "got %08x\n", r);
2361 if (r == S_OK)
2362 ok(stat.cbSize.QuadPart == 3, "got %d\n", stat.cbSize.u.LowPart);
2363
2364 pos.QuadPart = 1;
2365 r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &upos);
2366 ok(r == S_OK, "got %08x\n", r);
2367 ok(upos.QuadPart == 1, "got %d\n", upos.u.LowPart);
2368
2369 r = IStream_Stat(stm, &stat, STATFLAG_NONAME);
2370 ok(r == S_OK ||
2371 broken(r == STG_E_INVALIDFUNCTION), /* NT4 and below */
2372 "got %08x\n", r);
2373 if (r == S_OK)
2374 ok(stat.cbSize.QuadPart == 1, "got %d\n", stat.cbSize.u.LowPart);
2375
2376 IStream_Release(stm);
2377
2378 r = IStorage_CreateStream(stg, stmname2, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm);
2379 ok(r == S_OK, "got %08x\n", r);
2380
2381 upos.QuadPart = 100;
2382 r = IStream_SetSize(stm, upos);
2383 ok(r == S_OK, "got %08x\n", r);
2384
2385 r = IStream_Write(stm, "foo", 3, &count);
2386 ok(r == S_OK, "got %08x\n", r);
2387 ok(count == 3, "got %d\n", count);
2388
2389 IStream_Release(stm);
2390
2391 IStorage_Commit(stg, STGC_DEFAULT);
2392 IStorage_Release(stg);
2393
2394 r = StgOpenStorage( filename, NULL, STGM_SIMPLE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &stg);
2395 if (r == STG_E_INVALIDFLAG)
2396 {
2397 win_skip("Flag combination is not supported on NT4 and below\n");
2398 DeleteFileA(filenameA);
2399 return;
2400 }
2401 ok(r == S_OK, "got %08x\n", r);
2402
2403 r = IStorage_OpenStorage(stg, stgname, NULL, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &stg2);
2404 ok(r == STG_E_INVALIDFUNCTION, "got %08x\n", r);
2405 if (SUCCEEDED(r)) IStorage_Release(stg2);
2406
2407 r = IStorage_OpenStream(stg, stmname, NULL, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &stm);
2408 ok(r == S_OK, "got %08x\n", r);
2409
2410 r = IStream_Stat(stm, &stat, STATFLAG_NONAME);
2411 ok(r == S_OK, "got %08x\n", r);
2412 ok(stat.cbSize.QuadPart == 6000, "got %d\n", stat.cbSize.u.LowPart);
2413
2414 IStream_Release(stm);
2415
2416 r = IStorage_OpenStream(stg, stmname2, NULL, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &stm);
2417 ok(r == S_OK, "got %08x\n", r);
2418
2419 r = IStream_Stat(stm, &stat, STATFLAG_NONAME);
2420 ok(r == S_OK, "got %08x\n", r);
2421 ok(stat.cbSize.QuadPart == 4096, "got %d\n", stat.cbSize.u.LowPart);
2422
2423 IStream_Release(stm);
2424
2425
2426 IStorage_Release(stg);
2427
2428 DeleteFileA(filenameA);
2429 }
2430
2431 static void test_fmtusertypestg(void)
2432 {
2433 IStorage *stg;
2434 IEnumSTATSTG *stat;
2435 HRESULT hr;
2436 static const char fileA[] = {'f','m','t','t','e','s','t',0};
2437 static const WCHAR fileW[] = {'f','m','t','t','e','s','t',0};
2438 static WCHAR userTypeW[] = {'S','t','g','U','s','r','T','y','p','e',0};
2439 static const WCHAR strmNameW[] = {1,'C','o','m','p','O','b','j',0};
2440 static const STATSTG statstg_null;
2441
2442 hr = StgCreateDocfile( fileW, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &stg);
2443 ok(hr == S_OK, "should succeed, res=%x\n", hr);
2444
2445 if (SUCCEEDED(hr))
2446 {
2447 /* try to write the stream */
2448 hr = WriteFmtUserTypeStg(stg, 0, userTypeW);
2449 ok(hr == S_OK, "should succeed, res=%x\n", hr);
2450
2451 /* check that the stream was created */
2452 hr = IStorage_EnumElements(stg, 0, NULL, 0, &stat);
2453 ok(hr == S_OK, "should succeed, res=%x\n", hr);
2454 if (SUCCEEDED(hr))
2455 {
2456 BOOL found = FALSE;
2457 STATSTG statstg;
2458 DWORD got;
2459 memset(&statstg, 0xad, sizeof(statstg));
2460 while ((hr = IEnumSTATSTG_Next(stat, 1, &statstg, &got)) == S_OK && got == 1)
2461 {
2462 if (strcmp_ww(statstg.pwcsName, strmNameW) == 0)
2463 found = TRUE;
2464 else
2465 ok(0, "found unexpected stream or storage\n");
2466 CoTaskMemFree(statstg.pwcsName);
2467 }
2468 ok(memcmp(&statstg, &statstg_null, sizeof(statstg)) == 0, "statstg is not zeroed\n");
2469 ok(found == TRUE, "expected storage to contain stream \\0001CompObj\n");
2470 IEnumSTATSTG_Release(stat);
2471 }
2472
2473 /* re-write the stream */
2474 hr = WriteFmtUserTypeStg(stg, 0, userTypeW);
2475 ok(hr == S_OK, "should succeed, res=%x\n", hr);
2476
2477 /* check that the stream is still there */
2478 hr = IStorage_EnumElements(stg, 0, NULL, 0, &stat);
2479 ok(hr == S_OK, "should succeed, res=%x\n", hr);
2480 if (SUCCEEDED(hr))
2481 {
2482 BOOL found = FALSE;
2483 STATSTG statstg;
2484 DWORD got;
2485 memset(&statstg, 0xad, sizeof(statstg));
2486 while ((hr = IEnumSTATSTG_Next(stat, 1, &statstg, &got)) == S_OK && got == 1)
2487 {
2488 if (strcmp_ww(statstg.pwcsName, strmNameW) == 0)
2489 found = TRUE;
2490 else
2491 ok(0, "found unexpected stream or storage\n");
2492 CoTaskMemFree(statstg.pwcsName);
2493 }
2494 ok(memcmp(&statstg, &statstg_null, sizeof(statstg)) == 0, "statstg is not zeroed\n");
2495 ok(found == TRUE, "expected storage to contain stream \\0001CompObj\n");
2496 IEnumSTATSTG_Release(stat);
2497 }
2498
2499 IStorage_Release(stg);
2500 DeleteFileA( fileA );
2501 }
2502 }
2503
2504 static void test_references(void)
2505 {
2506 IStorage *stg,*stg2;
2507 HRESULT hr;
2508 unsigned c1,c2;
2509 static const WCHAR StorName[] = { 'D','a','t','a','S','p','a','c','e','I','n','f','o',0 };
2510
2511 DeleteFileA(filenameA);
2512
2513 hr = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
2514 ok(hr==S_OK, "StgCreateDocfile failed\n");
2515
2516 if (SUCCEEDED(hr))
2517 {
2518 IStorage_Release(stg);
2519
2520 hr = StgOpenStorage( filename, NULL, STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &stg);
2521 ok(hr==S_OK, "StgOpenStorage failed (result=%x)\n",hr);
2522
2523 if (SUCCEEDED(hr))
2524 {
2525 hr = IStorage_CreateStorage(stg,StorName,STGM_READWRITE | STGM_SHARE_EXCLUSIVE,0,0,&stg2);
2526 ok(hr == S_OK, "IStorage_CreateStorage failed (result=%x)\n",hr);
2527
2528 if (SUCCEEDED(hr))
2529 {
2530 c1 = IStorage_AddRef(stg);
2531 ok(c1 == 2, "creating internal storage added references to ancestor\n");
2532 c1 = IStorage_AddRef(stg);
2533 IStorage_Release(stg2);
2534 c2 = IStorage_AddRef(stg) - 1;
2535 ok(c1 == c2, "releasing internal storage removed references to ancestor\n");
2536 }
2537 c1 = IStorage_Release(stg);
2538 while ( c1 ) c1 = IStorage_Release(stg);
2539 }
2540 }
2541
2542 DeleteFileA(filenameA);
2543 }
2544
2545 /* dest
2546 * |-StorageA
2547 * | `StreamA: "StreamA"
2548 * |-StorageB
2549 * | `StreamB: "StreamB"
2550 * `StreamC: "StreamC"
2551 */
2552 static HRESULT create_test_file(IStorage *dest)
2553 {
2554 IStorage *stgA = NULL, *stgB = NULL;
2555 IStream *strmA = NULL, *strmB = NULL, *strmC = NULL;
2556 const ULONG strmA_name_size = lstrlenW(strmA_name) * sizeof(WCHAR);
2557 const ULONG strmB_name_size = lstrlenW(strmB_name) * sizeof(WCHAR);
2558 const ULONG strmC_name_size = lstrlenW(strmC_name) * sizeof(WCHAR);
2559 ULONG bytes;
2560 HRESULT hr;
2561
2562 hr = IStorage_CreateStorage(dest, stgA_name, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stgA);
2563 ok(hr == S_OK, "IStorage_CreateStorage failed: 0x%08x\n", hr);
2564 if(FAILED(hr))
2565 goto cleanup;
2566
2567 hr = IStorage_CreateStream(stgA, strmA_name, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &strmA);
2568 ok(hr == S_OK, "IStorage_CreateStream failed: 0x%08x\n", hr);
2569 if(FAILED(hr))
2570 goto cleanup;
2571
2572 hr = IStream_Write(strmA, strmA_name, strmA_name_size, &bytes);
2573 ok(hr == S_OK && bytes == strmA_name_size, "IStream_Write failed: 0x%08x, %d of %d bytes written\n", hr, bytes, strmA_name_size);
2574
2575 hr = IStorage_CreateStorage(dest, stgB_name, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stgB);
2576 ok(hr == S_OK, "IStorage_CreateStorage failed: 0x%08x\n", hr);
2577 if(FAILED(hr))
2578 goto cleanup;
2579
2580 hr = IStorage_CreateStream(stgB, strmB_name, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &strmB);
2581 ok(hr == S_OK, "IStorage_CreateStream failed: 0x%08x\n", hr);
2582 if(FAILED(hr))
2583 goto cleanup;
2584
2585 hr = IStream_Write(strmB, strmB_name, strmB_name_size, &bytes);
2586 ok(hr == S_OK && bytes == strmB_name_size, "IStream_Write failed: 0x%08x, %d of %d bytes written\n", hr, bytes, strmB_name_size);
2587
2588 hr = IStorage_CreateStream(dest, strmC_name, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &strmC);
2589 ok(hr == S_OK, "IStorage_CreateStream failed: 0x%08x\n", hr);
2590 if(FAILED(hr))
2591 goto cleanup;
2592
2593 hr = IStream_Write(strmC, strmC_name, strmC_name_size, &bytes);
2594 ok(hr == S_OK && bytes == strmC_name_size, "IStream_Write failed: 0x%08x, %d of %d bytes written\n", hr, bytes, strmC_name_size);
2595
2596 cleanup:
2597 if(strmC)
2598 IStream_Release(strmC);
2599 if(strmB)
2600 IStream_Release(strmB);
2601 if(stgB)
2602 IStorage_Release(stgB);
2603 if(strmA)
2604 IStream_Release(strmA);
2605 if(stgA)
2606 IStorage_Release(stgA);
2607
2608 return hr;
2609 }
2610
2611 static void test_copyto(void)
2612 {
2613 IStorage *file1 = NULL, *file2 = NULL, *stg_tmp;
2614 IStream *strm_tmp;
2615 WCHAR buf[64];
2616 HRESULT hr;
2617
2618 /* create & populate file1 */
2619 hr = StgCreateDocfile(file1_name, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &file1);
2620 ok(hr == S_OK, "StgCreateDocfile failed: 0x%08x\n", hr);
2621 if(FAILED(hr))
2622 goto cleanup;
2623
2624 hr = create_test_file(file1);
2625 if(FAILED(hr))
2626 goto cleanup;
2627
2628 /* create file2 */
2629 hr = StgCreateDocfile(file2_name, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &file2);
2630 ok(hr == S_OK, "StgCreateDocfile failed: 0x%08x\n", hr);
2631 if(FAILED(hr))
2632 goto cleanup;
2633
2634 /* copy file1 into file2 */
2635 hr = IStorage_CopyTo(file1, 0, NULL, NULL, NULL);
2636 ok(hr == STG_E_INVALIDPOINTER, "CopyTo should give STG_E_INVALIDPONITER, gave: 0x%08x\n", hr);
2637
2638 hr = IStorage_CopyTo(file1, 0, NULL, NULL, file2);
2639 ok(hr == S_OK, "CopyTo failed: 0x%08x\n", hr);
2640 if(FAILED(hr))
2641 goto cleanup;
2642
2643 /* verify that all of file1 was copied */
2644 hr = IStorage_OpenStorage(file2, stgA_name, NULL,
2645 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg_tmp);
2646 ok(hr == S_OK, "OpenStorage failed: 0x%08x\n", hr);
2647
2648 if(SUCCEEDED(hr)){
2649 hr = IStorage_OpenStream(stg_tmp, strmA_name, NULL,
2650 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
2651 ok(hr == S_OK, "OpenStream failed: 0x%08x\n", hr);
2652
2653 if(SUCCEEDED(hr)){
2654 memset(buf, 0, sizeof(buf));
2655 hr = IStream_Read(strm_tmp, buf, sizeof(buf), NULL);
2656 ok(hr == S_OK, "Read failed: 0x%08x\n", hr);
2657 if(SUCCEEDED(hr))
2658 ok(strcmp_ww(buf, strmA_name) == 0,
2659 "Expected %s to be read, got %s\n", wine_dbgstr_w(strmA_name), wine_dbgstr_w(buf));
2660
2661 IStream_Release(strm_tmp);
2662 }
2663
2664 IStorage_Release(stg_tmp);
2665 }
2666
2667 hr = IStorage_OpenStorage(file2, stgB_name, NULL,
2668 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg_tmp);
2669 ok(hr == S_OK, "OpenStorage failed: 0x%08x\n", hr);
2670
2671 if(SUCCEEDED(hr)){
2672 hr = IStorage_OpenStream(stg_tmp, strmB_name, NULL,
2673 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
2674 ok(hr == S_OK, "OpenStream failed: 0x%08x\n", hr);
2675
2676 if(SUCCEEDED(hr)){
2677 memset(buf, 0, sizeof(buf));
2678 hr = IStream_Read(strm_tmp, buf, sizeof(buf), NULL);
2679 ok(hr == S_OK, "Read failed: 0x%08x\n", hr);
2680 if(SUCCEEDED(hr))
2681 ok(strcmp_ww(buf, strmB_name) == 0,
2682 "Expected %s to be read, got %s\n", wine_dbgstr_w(strmB_name), wine_dbgstr_w(buf));
2683
2684 IStream_Release(strm_tmp);
2685 }
2686
2687 IStorage_Release(stg_tmp);
2688 }
2689
2690 hr = IStorage_OpenStream(file2, strmC_name, NULL,
2691 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
2692 ok(hr == S_OK, "OpenStream failed: 0x%08x\n", hr);
2693
2694 if(SUCCEEDED(hr)){
2695 memset(buf, 0, sizeof(buf));
2696 hr = IStream_Read(strm_tmp, buf, sizeof(buf), NULL);
2697 ok(hr == S_OK, "Read failed: 0x%08x\n", hr);
2698 if(SUCCEEDED(hr))
2699 ok(strcmp_ww(buf, strmC_name) == 0,
2700 "Expected %s to be read, got %s\n", wine_dbgstr_w(strmC_name), wine_dbgstr_w(buf));
2701
2702 IStream_Release(strm_tmp);
2703 }
2704
2705 cleanup:
2706 if(file1)
2707 IStorage_Release(file1);
2708 if(file2)
2709 IStorage_Release(file2);
2710
2711 DeleteFileA(file1_nameA);
2712 DeleteFileA(file2_nameA);
2713 }
2714
2715 static void test_copyto_snbexclusions(void)
2716 {
2717 static const WCHAR *snb_exclude[] = {stgA_name, strmB_name, strmC_name, 0};
2718
2719 IStorage *file1 = NULL, *file2 = NULL, *stg_tmp;
2720 IStream *strm_tmp;
2721 WCHAR buf[64];
2722 HRESULT hr;
2723
2724 /* create & populate file1 */
2725 hr = StgCreateDocfile(file1_name, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &file1);
2726 ok(hr == S_OK, "StgCreateDocfile failed: 0x%08x\n", hr);
2727 if(FAILED(hr))
2728 goto cleanup;
2729
2730 hr = create_test_file(file1);
2731 if(FAILED(hr))
2732 goto cleanup;
2733
2734 /* create file2 */
2735 hr = StgCreateDocfile(file2_name, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &file2);
2736 ok(hr == S_OK, "StgCreateDocfile failed: 0x%08x\n", hr);
2737 if(FAILED(hr))
2738 goto cleanup;
2739
2740 /* copy file1 to file2 with name exclusions */
2741 hr = IStorage_CopyTo(file1, 0, NULL, (SNB)snb_exclude, file2);
2742 ok(hr == S_OK, "CopyTo failed: 0x%08x\n", hr);
2743 if(FAILED(hr))
2744 goto cleanup;
2745
2746 /* verify that file1 copied over, respecting exclusions */
2747 hr = IStorage_OpenStorage(file2, stgA_name, NULL,
2748 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg_tmp);
2749 ok(hr == STG_E_FILENOTFOUND, "OpenStorage should give STG_E_FILENOTFOUND, gave: 0x%08x\n", hr);
2750 if(SUCCEEDED(hr))
2751 IStorage_Release(stg_tmp);
2752
2753 hr = IStorage_OpenStream(file2, strmA_name, NULL,
2754 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
2755 ok(hr == STG_E_FILENOTFOUND, "OpenStream should give STG_E_FILENOTFOUND, gave: 0x%08x\n", hr);
2756 if(SUCCEEDED(hr))
2757 IStream_Release(strm_tmp);
2758
2759 hr = IStorage_OpenStorage(file2, stgB_name, NULL,
2760 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg_tmp);
2761 ok(hr == S_OK, "OpenStorage failed: 0x%08x\n", hr);
2762
2763 if(SUCCEEDED(hr)){
2764 hr = IStorage_OpenStream(stg_tmp, strmB_name, NULL,
2765 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
2766 ok(hr == S_OK, "OpenStream failed: 0x%08x\n", hr);
2767
2768 if(SUCCEEDED(hr)){
2769 memset(buf, 0, sizeof(buf));
2770 hr = IStream_Read(strm_tmp, buf, sizeof(buf), NULL);
2771 ok(hr == S_OK, "Read failed: 0x%08x\n", hr);
2772 if(SUCCEEDED(hr))
2773 ok(strcmp_ww(buf, strmB_name) == 0,
2774 "Expected %s to be read, got %s\n", wine_dbgstr_w(strmB_name), wine_dbgstr_w(buf));
2775
2776 IStream_Release(strm_tmp);
2777 }
2778
2779 IStorage_Release(stg_tmp);
2780 }
2781
2782 hr = IStorage_OpenStream(file2, strmC_name, NULL,
2783 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
2784 ok(hr == STG_E_FILENOTFOUND, "OpenStream should give STG_E_FILENOTFOUND, gave: 0x%08x\n", hr);
2785 if(SUCCEEDED(hr))
2786 IStream_Release(strm_tmp);
2787
2788 cleanup:
2789 if(file1)
2790 IStorage_Release(file1);
2791 if(file2)
2792 IStorage_Release(file2);
2793
2794 DeleteFileA(file1_nameA);
2795 DeleteFileA(file2_nameA);
2796 }
2797
2798 static void test_copyto_iidexclusions_storage(void)
2799 {
2800 IStorage *file1 = NULL, *file2 = NULL, *stg_tmp;
2801 IStream *strm_tmp;
2802 WCHAR buf[64];
2803 HRESULT hr;
2804
2805 /* create & populate file1 */
2806 hr = StgCreateDocfile(file1_name, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &file1);
2807 ok(hr == S_OK, "StgCreateDocfile failed: 0x%08x\n", hr);
2808 if(FAILED(hr))
2809 goto cleanup;
2810
2811 hr = create_test_file(file1);
2812 if(FAILED(hr))
2813 goto cleanup;
2814
2815 /* create file2 */
2816 hr = StgCreateDocfile(file2_name, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &file2);
2817 ok(hr == S_OK, "StgCreateDocfile failed: 0x%08x\n", hr);
2818 if(FAILED(hr))
2819 goto cleanup;
2820
2821 /* copy file1 to file2 with iid exclusions */
2822 hr = IStorage_CopyTo(file1, 1, &IID_IStorage, NULL, file2);
2823 ok(hr == S_OK, "CopyTo failed: 0x%08x\n", hr);
2824 if(FAILED(hr))
2825 goto cleanup;
2826
2827 /* verify that file1 copied over, respecting exclusions */
2828 hr = IStorage_OpenStorage(file2, stgA_name, NULL,
2829 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg_tmp);
2830 ok(hr == STG_E_FILENOTFOUND, "OpenStorage should give STG_E_FILENOTFOUND, gave: 0x%08x\n", hr);
2831 if(SUCCEEDED(hr))
2832 IStorage_Release(stg_tmp);
2833
2834 hr = IStorage_OpenStream(file2, strmA_name, NULL,
2835 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
2836 ok(hr == STG_E_FILENOTFOUND, "OpenStream should give STG_E_FILENOTFOUND, gave: 0x%08x\n", hr);
2837 if(SUCCEEDED(hr))
2838 IStream_Release(strm_tmp);
2839
2840 hr = IStorage_OpenStorage(file2, stgB_name, NULL,
2841 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg_tmp);
2842 ok(hr == STG_E_FILENOTFOUND, "OpenStorage should give STG_E_FILENOTFOUND, gave: 0x%08x\n", hr);
2843 if(SUCCEEDED(hr))
2844 IStorage_Release(stg_tmp);
2845
2846 hr = IStorage_OpenStream(file2, strmB_name, NULL,
2847 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
2848 ok(hr == STG_E_FILENOTFOUND, "OpenStream should give STG_E_FILENOTFOUND, gave: 0x%08x\n", hr);
2849 if(SUCCEEDED(hr))
2850 IStream_Release(strm_tmp);
2851
2852 hr = IStorage_OpenStream(file2, strmC_name, NULL,
2853 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
2854 ok(hr == S_OK, "OpenStream failed: 0x%08x\n", hr);
2855
2856 if(SUCCEEDED(hr)){
2857 memset(buf, 0, sizeof(buf));
2858 hr = IStream_Read(strm_tmp, buf, sizeof(buf), NULL);
2859 ok(hr == S_OK, "Read failed: 0x%08x\n", hr);
2860 if(SUCCEEDED(hr))
2861 ok(strcmp_ww(buf, strmC_name) == 0,
2862 "Expected %s to be read, got %s\n", wine_dbgstr_w(strmC_name), wine_dbgstr_w(buf));
2863
2864 IStream_Release(strm_tmp);
2865 }
2866
2867 cleanup:
2868 if(file1)
2869 IStorage_Release(file1);
2870 if(file2)
2871 IStorage_Release(file2);
2872
2873 DeleteFileA(file1_nameA);
2874 DeleteFileA(file2_nameA);
2875 }
2876
2877 static void test_copyto_iidexclusions_stream(void)
2878 {
2879 IStorage *file1 = NULL, *file2 = NULL, *stg_tmp;
2880 IStream *strm_tmp;
2881 HRESULT hr;
2882
2883 /* create & populate file1 */
2884 hr = StgCreateDocfile(file1_name, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &file1);
2885 ok(hr == S_OK, "StgCreateDocfile failed: 0x%08x\n", hr);
2886 if(FAILED(hr))
2887 goto cleanup;
2888
2889 hr = create_test_file(file1);
2890 if(FAILED(hr))
2891 goto cleanup;
2892
2893 /* create file2 */
2894 hr = StgCreateDocfile(file2_name, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &file2);
2895 ok(hr == S_OK, "StgCreateDocfile failed: 0x%08x\n", hr);
2896 if(FAILED(hr))
2897 goto cleanup;
2898
2899 /* copy file1 to file2 with iid exclusions */
2900 hr = IStorage_CopyTo(file1, 1, &IID_IStream, NULL, file2);
2901 ok(hr == S_OK, "CopyTo failed: 0x%08x\n", hr);
2902 if(FAILED(hr))
2903 goto cleanup;
2904
2905 /* verify that file1 copied over, respecting exclusions */
2906 hr = IStorage_OpenStorage(file2, stgA_name, NULL,
2907 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg_tmp);
2908 ok(hr == S_OK, "OpenStorage failed: 0x%08x\n", hr);
2909
2910 if(SUCCEEDED(hr)){
2911 hr = IStorage_OpenStream(stg_tmp, strmA_name, NULL,
2912 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
2913 ok(hr == STG_E_FILENOTFOUND, "OpenStream should give STG_E_FILENOTFOUND, gave: 0x%08x\n", hr);
2914 if(SUCCEEDED(hr))
2915 IStream_Release(strm_tmp);
2916
2917 IStorage_Release(stg_tmp);
2918 }
2919
2920 hr = IStorage_OpenStorage(file2, stgB_name, NULL,
2921 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg_tmp);
2922 ok(hr == S_OK, "OpenStorage failed: 0x%08x\n", hr);
2923
2924 if(SUCCEEDED(hr)){
2925 hr = IStorage_OpenStream(stg_tmp, strmB_name, NULL,
2926 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
2927 ok(hr == STG_E_FILENOTFOUND, "OpenStream should give STG_E_FILENOTFOUND, gave: 0x%08x\n", hr);
2928 if(SUCCEEDED(hr))
2929 IStream_Release(strm_tmp);
2930
2931 IStorage_Release(stg_tmp);
2932 }
2933
2934 hr = IStorage_OpenStream(file2, strmC_name, NULL,
2935 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
2936 ok(hr == STG_E_FILENOTFOUND, "OpenStream should give STG_E_FILENOTFOUND, gave: 0x%08x\n", hr);
2937 if(SUCCEEDED(hr))
2938 IStream_Release(strm_tmp);
2939
2940 cleanup:
2941 if(file1)
2942 IStorage_Release(file1);
2943 if(file2)
2944 IStorage_Release(file2);
2945
2946 DeleteFileA(file1_nameA);
2947 DeleteFileA(file2_nameA);
2948 }
2949
2950 static void test_rename(void)
2951 {
2952 IStorage *stg, *stg2;
2953 IStream *stm;
2954 HRESULT r;
2955 static const WCHAR stgname[] = { 'P','E','R','M','S','T','G',0 };
2956 static const WCHAR stgname2[] = { 'S','T','G',0 };
2957 static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
2958 static const WCHAR stmname2[] = { 'E','N','T','S',0 };
2959 BOOL ret;
2960
2961 DeleteFileA(filenameA);
2962
2963 /* create the file */
2964 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
2965 STGM_READWRITE, 0, &stg);
2966 ok(r==S_OK, "StgCreateDocfile failed\n");
2967
2968 /* create a substorage */
2969 r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
2970 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
2971
2972 /* create a stream in the substorage */
2973 r = IStorage_CreateStream(stg2, stmname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm);
2974 ok(r==S_OK, "IStorage->CreateStream failed, hr=%08x\n", r);
2975 IStream_Release(stm);
2976
2977 /* rename the stream */
2978 r = IStorage_RenameElement(stg2, stmname, stmname2);
2979 ok(r==S_OK, "IStorage->RenameElement failed, hr=%08x\n", r);
2980
2981 /* cannot open stream with old name */
2982 r = IStorage_OpenStream(stg2, stmname, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &stm);
2983 ok(r==STG_E_FILENOTFOUND, "IStorage_OpenStream should fail, hr=%08x\n", r);
2984 if (SUCCEEDED(r)) IStream_Release(stm);
2985
2986 /* can open stream with new name */
2987 r = IStorage_OpenStream(stg2, stmname2, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &stm);
2988 ok(r==S_OK, "IStorage_OpenStream failed, hr=%08x\n", r);
2989 if (SUCCEEDED(r)) IStream_Release(stm);
2990
2991 IStorage_Release(stg2);
2992
2993 /* rename the storage */
2994 IStorage_RenameElement(stg, stgname, stgname2);
2995
2996 /* cannot open storage with old name */
2997 r = IStorage_OpenStorage(stg, stgname, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg2);
2998 ok(r==STG_E_FILENOTFOUND, "IStorage_OpenStream should fail, hr=%08x\n", r);
2999 if (SUCCEEDED(r)) IStorage_Release(stg2);
3000
3001 /* can open storage with new name */
3002 r = IStorage_OpenStorage(stg, stgname2, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg2);
3003 ok(r==S_OK, "IStorage_OpenStream should fail, hr=%08x\n", r);
3004 if (SUCCEEDED(r))
3005 {
3006 /* opened storage still has the stream */
3007 r = IStorage_OpenStream(stg2, stmname2, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &stm);
3008 ok(r==S_OK, "IStorage_OpenStream failed, hr=%08x\n", r);
3009 if (SUCCEEDED(r)) IStream_Release(stm);
3010
3011 IStorage_Release(stg2);
3012 }
3013
3014 IStorage_Release(stg);
3015
3016 ret = DeleteFileA(filenameA);
3017 ok(ret, "deleted file\n");
3018 }
3019
3020 static void test_toplevel_stat(void)
3021 {
3022 IStorage *stg = NULL;
3023 HRESULT r;
3024 STATSTG stat;
3025 char prev_dir[MAX_PATH];
3026 char temp[MAX_PATH];
3027 char full_path[MAX_PATH];
3028 LPSTR rel_pathA;
3029 WCHAR rel_path[MAX_PATH];
3030
3031 DeleteFileA(filenameA);
3032
3033 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
3034 STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
3035 ok(r==S_OK, "StgCreateDocfile failed\n");
3036
3037 r = IStorage_Stat( stg, &stat, STATFLAG_DEFAULT );
3038 ok(r==S_OK, "Storage_Stat failed with error 0x%08x\n", r);
3039 ok(!strcmp_ww(stat.pwcsName, filename), "expected %s, got %s\n",
3040 wine_dbgstr_w(filename), wine_dbgstr_w(stat.pwcsName));
3041 CoTaskMemFree(stat.pwcsName);
3042
3043 IStorage_Release( stg );
3044
3045 r = StgOpenStorage( filename, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg);
3046 ok(r==S_OK, "StgOpenStorage failed with error 0x%08x\n", r);
3047
3048 r = IStorage_Stat( stg, &stat, STATFLAG_DEFAULT );
3049 ok(r==S_OK, "Storage_Stat failed with error 0x%08x\n", r);
3050 ok(!strcmp_ww(stat.pwcsName, filename), "expected %s, got %s\n",
3051 wine_dbgstr_w(filename), wine_dbgstr_w(stat.pwcsName));
3052 CoTaskMemFree(stat.pwcsName);
3053
3054 IStorage_Release( stg );
3055
3056 DeleteFileA(filenameA);
3057
3058 /* Stat always returns the full path, even for files opened with a relative path. */
3059 GetCurrentDirectoryA(MAX_PATH, prev_dir);
3060
3061 GetTempPathA(MAX_PATH, temp);
3062
3063 SetCurrentDirectoryA(temp);
3064
3065 GetFullPathNameA(filenameA, MAX_PATH, full_path, &rel_pathA);
3066 MultiByteToWideChar(CP_ACP, 0, rel_pathA, -1, rel_path, MAX_PATH);
3067
3068 r = StgCreateDocfile( rel_path, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
3069 STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
3070 ok(r==S_OK, "StgCreateDocfile failed\n");
3071
3072 r = IStorage_Stat( stg, &stat, STATFLAG_DEFAULT );
3073 ok(r==S_OK, "Storage_Stat failed with error 0x%08x\n", r);
3074 ok(!strcmp_ww(stat.pwcsName, filename), "expected %s, got %s\n",
3075 wine_dbgstr_w(filename), wine_dbgstr_w(stat.pwcsName));
3076 CoTaskMemFree(stat.pwcsName);
3077
3078 IStorage_Release( stg );
3079
3080 r = StgOpenStorage( rel_path, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg);
3081 ok(r==S_OK, "StgOpenStorage failed with error 0x%08x\n", r);
3082
3083 r = IStorage_Stat( stg, &stat, STATFLAG_DEFAULT );
3084 ok(r==S_OK, "Storage_Stat failed with error 0x%08x\n", r);
3085 ok(!strcmp_ww(stat.pwcsName, filename), "expected %s, got %s\n",
3086 wine_dbgstr_w(filename), wine_dbgstr_w(stat.pwcsName));
3087 CoTaskMemFree(stat.pwcsName);
3088
3089 IStorage_Release( stg );
3090
3091 SetCurrentDirectoryA(prev_dir);
3092
3093 DeleteFileA(filenameA);
3094 }
3095
3096 static void test_substorage_enum(void)
3097 {
3098 IStorage *stg, *stg2;
3099 IEnumSTATSTG *ee;
3100 HRESULT r;
3101 ULONG ref;
3102 static const WCHAR stgname[] = { 'P','E','R','M','S','T','G',0 };
3103 BOOL ret;
3104
3105 DeleteFileA(filenameA);
3106
3107 /* create the file */
3108 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
3109 STGM_READWRITE, 0, &stg);
3110 ok(r==S_OK, "StgCreateDocfile failed\n");
3111
3112 /* create a substorage */
3113 r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
3114 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
3115
3116 /* create an enumelements */
3117 r = IStorage_EnumElements(stg2, 0, NULL, 0, &ee);
3118 ok(r==S_OK, "IStorage->EnumElements failed, hr=%08x\n", r);
3119
3120 /* release the substorage */
3121 ref = IStorage_Release(stg2);
3122 todo_wine ok(ref==0, "storage not released\n");
3123
3124 /* reopening fails, because the substorage is really still open */
3125 r = IStorage_OpenStorage(stg, stgname, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
3126 ok(r==STG_E_ACCESSDENIED, "IStorage->OpenStorage failed, hr=%08x\n", r);
3127
3128 /* destroying the storage invalidates the enumerator */
3129 r = IStorage_DestroyElement(stg, stgname);
3130 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
3131
3132 r = IEnumSTATSTG_Reset(ee);
3133 ok(r==STG_E_REVERTED, "IEnumSTATSTG->Reset failed, hr=%08x\n", r);
3134
3135 IEnumSTATSTG_Release(ee);
3136
3137 IStorage_Release(stg);
3138
3139 ret = DeleteFileA(filenameA);
3140 ok(ret, "deleted file\n");
3141 }
3142
3143 static void test_copyto_locking(void)
3144 {
3145 IStorage *stg, *stg2, *stg3, *stg4;
3146 IStream *stm;
3147 HRESULT r;
3148 static const WCHAR stgname[] = { 'S','T','G','1',0 };
3149 static const WCHAR stgname2[] = { 'S','T','G','2',0 };
3150 static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
3151 BOOL ret;
3152
3153 DeleteFileA(filenameA);
3154
3155 /* create the file */
3156 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
3157 STGM_READWRITE, 0, &stg);
3158 ok(r==S_OK, "StgCreateDocfile failed\n");
3159
3160 /* create a substorage */
3161 r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
3162 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
3163
3164 /* create another substorage */
3165 r = IStorage_CreateStorage(stg, stgname2, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg3);
3166 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
3167
3168 /* add a stream, and leave it open */
3169 r = IStorage_CreateStream(stg2, stmname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm);
3170 ok(r==S_OK, "IStorage->CreateStream failed, hr=%08x\n", r);
3171
3172 /* Try to copy the storage while the stream is open */
3173 r = IStorage_CopyTo(stg2, 0, NULL, NULL, stg3);
3174 ok(r==S_OK, "IStorage->CopyTo failed, hr=%08x\n", r);
3175
3176 IStream_Release(stm);
3177
3178 /* create a substorage */
3179 r = IStorage_CreateStorage(stg2, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg4);
3180 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
3181
3182 /* Try to copy the storage while the substorage is open */
3183 r = IStorage_CopyTo(stg2, 0, NULL, NULL, stg3);
3184 ok(r==S_OK, "IStorage->CopyTo failed, hr=%08x\n", r);
3185
3186 IStorage_Release(stg4);
3187 IStorage_Release(stg3);
3188 IStorage_Release(stg2);
3189 IStorage_Release(stg);
3190
3191 ret = DeleteFileA(filenameA);
3192 ok(ret, "deleted file\n");
3193 }
3194
3195 static void test_copyto_recursive(void)
3196 {
3197 IStorage *stg, *stg2, *stg3, *stg4;
3198 HRESULT r;
3199 static const WCHAR stgname[] = { 'S','T','G','1',0 };
3200 static const WCHAR stgname2[] = { 'S','T','G','2',0 };
3201 BOOL ret;
3202
3203 DeleteFileA(filenameA);
3204
3205 /* create the file */
3206 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
3207 STGM_READWRITE, 0, &stg);
3208 ok(r==S_OK, "StgCreateDocfile failed\n");
3209
3210 /* create a substorage */
3211 r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
3212 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
3213
3214 /* copy the parent to the child */
3215 r = IStorage_CopyTo(stg, 0, NULL, NULL, stg2);
3216 ok(r==STG_E_ACCESSDENIED, "IStorage->CopyTo failed, hr=%08x\n", r);
3217
3218 /* create a transacted substorage */
3219 r = IStorage_CreateStorage(stg, stgname2, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_TRANSACTED, 0, 0, &stg3);
3220 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
3221
3222 /* copy the parent to the transacted child */
3223 r = IStorage_CopyTo(stg, 0, NULL, NULL, stg2);
3224 ok(r==STG_E_ACCESSDENIED, "IStorage->CopyTo failed, hr=%08x\n", r);
3225
3226 /* create a transacted subsubstorage */
3227 r = IStorage_CreateStorage(stg3, stgname2, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_TRANSACTED, 0, 0, &stg4);
3228 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
3229
3230 /* copy the parent to the transacted child of the transacted child */
3231 r = IStorage_CopyTo(stg, 0, NULL, NULL, stg4);
3232 ok(r==STG_E_ACCESSDENIED, "IStorage->CopyTo failed, hr=%08x\n", r);
3233
3234 /* copy the parent but exclude storage objects */
3235 r = IStorage_CopyTo(stg, 1, &IID_IStorage, NULL, stg4);
3236 ok(r==S_OK, "IStorage->CopyTo failed, hr=%08x\n", r);
3237
3238 IStorage_Release(stg4);
3239 IStorage_Release(stg3);
3240 IStorage_Release(stg2);
3241 IStorage_Release(stg);
3242
3243 ret = DeleteFileA(filenameA);
3244 ok(ret, "deleted file\n");
3245 }
3246
3247 static void test_hglobal_storage_creation(void)
3248 {
3249 ILockBytes *ilb = NULL;
3250 IStorage *stg = NULL;
3251 HRESULT r;
3252 STATSTG stat;
3253 char junk[512];
3254 ULARGE_INTEGER offset;
3255
3256 r = CreateILockBytesOnHGlobal(NULL, TRUE, &ilb);
3257 ok(r == S_OK, "CreateILockBytesOnHGlobal failed, hr=%x\n", r);
3258
3259 offset.QuadPart = 0;
3260 memset(junk, 0xaa, 512);
3261 r = ILockBytes_WriteAt(ilb, offset, junk, 512, NULL);
3262 ok(r == S_OK, "ILockBytes_WriteAt failed, hr=%x\n", r);
3263
3264 offset.QuadPart = 2000;
3265 r = ILockBytes_WriteAt(ilb, offset, junk, 512, NULL);
3266 ok(r == S_OK, "ILockBytes_WriteAt failed, hr=%x\n", r);
3267
3268 r = StgCreateDocfileOnILockBytes(ilb, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stg);
3269 ok(r == S_OK, "StgCreateDocfileOnILockBytes failed, hr=%x\n", r);
3270
3271 IStorage_Release(stg);
3272
3273 r = StgOpenStorageOnILockBytes(ilb, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE,
3274 NULL, 0, &stg);
3275 ok(r == S_OK, "StgOpenStorageOnILockBytes failed, hr=%x\n", r);
3276
3277 if (SUCCEEDED(r))
3278 {
3279 r = IStorage_Stat(stg, &stat, STATFLAG_NONAME);
3280 ok(r == S_OK, "StgOpenStorageOnILockBytes failed, hr=%x\n", r);
3281 ok(IsEqualCLSID(&stat.clsid, &GUID_NULL), "unexpected CLSID value\n");
3282
3283 IStorage_Release(stg);
3284 }
3285
3286 r = ILockBytes_Stat(ilb, &stat, STATFLAG_NONAME);
3287 ok(r == S_OK, "ILockBytes_Stat failed, hr=%x\n", r);
3288 ok(stat.cbSize.u.LowPart < 2512, "expected truncated size, got %d\n", stat.cbSize.u.LowPart);
3289
3290 ILockBytes_Release(ilb);
3291 }
3292
3293 static void test_convert(void)
3294 {
3295 static const WCHAR filename[] = {'s','t','o','r','a','g','e','.','s','t','g',0};
3296 IStorage *stg;
3297 HRESULT hr;
3298
3299 hr = GetConvertStg(NULL);
3300 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3301
3302 hr = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &stg);
3303 ok(hr == S_OK, "StgCreateDocfile failed\n");
3304 hr = GetConvertStg(stg);
3305 ok(hr == STG_E_FILENOTFOUND, "got 0x%08x\n", hr);
3306 hr = SetConvertStg(stg, TRUE);
3307 ok(hr == S_OK, "got 0x%08x\n", hr);
3308 hr = SetConvertStg(stg, TRUE);
3309 ok(hr == S_OK, "got 0x%08x\n", hr);
3310 hr = GetConvertStg(stg);
3311 ok(hr == S_OK, "got 0x%08x\n", hr);
3312 hr = SetConvertStg(stg, FALSE);
3313 ok(hr == S_OK, "got 0x%08x\n", hr);
3314 hr = GetConvertStg(stg);
3315 ok(hr == S_FALSE, "got 0x%08x\n", hr);
3316
3317 IStorage_Release(stg);
3318
3319 DeleteFileW(filename);
3320 }
3321
3322 static void test_direct_swmr(void)
3323 {
3324 static const WCHAR fileW[] = {'w','i','n','e','t','e','s','t',0};
3325 IDirectWriterLock *dwlock;
3326 ULONG ref, ref2;
3327 IStorage *stg;
3328 HRESULT hr;
3329
3330 /* it's possible to create in writer mode */
3331 hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE | STGM_SHARE_DENY_WRITE | STGM_DIRECT_SWMR, 0, &stg);
3332 todo_wine
3333 ok(hr == S_OK, "got %08x\n", hr);
3334 if (hr == S_OK) {
3335 IStorage_Release(stg);
3336 DeleteFileW(fileW);
3337 }
3338
3339 hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE | STGM_SHARE_DENY_WRITE | STGM_TRANSACTED, 0, &stg);
3340 ok(hr == S_OK, "got %08x\n", hr);
3341 IStorage_Release(stg);
3342
3343 /* reader mode */
3344 hr = StgOpenStorage(fileW, NULL, STGM_DIRECT_SWMR | STGM_READ | STGM_SHARE_DENY_NONE, NULL, 0, &stg);
3345 ok(hr == S_OK || broken(hr == STG_E_INVALIDFLAG), "got %08x\n", hr);
3346 if(hr == S_OK)
3347 {
3348 hr = IStorage_QueryInterface(stg, &IID_IDirectWriterLock, (void**)&dwlock);
3349 ok(hr == E_NOINTERFACE, "got %08x\n", hr);
3350 IStorage_Release(stg);
3351 }
3352
3353 /* writer mode */
3354 hr = StgOpenStorage(fileW, NULL, STGM_DIRECT_SWMR | STGM_READWRITE | STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
3355 ok(hr == S_OK, "got %08x\n", hr);
3356 if(hr == S_OK)
3357 {
3358 ref = IStorage_AddRef(stg);
3359 IStorage_Release(stg);
3360
3361 hr = IStorage_QueryInterface(stg, &IID_IDirectWriterLock, (void**)&dwlock);
3362 ok(hr == S_OK, "got %08x\n", hr);
3363
3364 ref2 = IStorage_AddRef(stg);
3365 IStorage_Release(stg);
3366 ok(ref2 == ref + 1, "got %u\n", ref2);
3367
3368 IDirectWriterLock_Release(dwlock);
3369 IStorage_Release(stg);
3370 }
3371
3372 DeleteFileW(fileW);
3373 }
3374
3375 struct lock_test
3376 {
3377 DWORD stg_mode;
3378 BOOL create;
3379 DWORD access;
3380 DWORD sharing;
3381 const int *locked_bytes;
3382 const int *fail_ranges;
3383 BOOL todo;
3384 };
3385
3386 static const int priority_locked_bytes[] = { 0x158, 0x181, 0x193, -1 };
3387 static const int rwex_locked_bytes[] = { 0x193, 0x1a7, 0x1bb, 0x1cf, -1 };
3388 static const int rw_locked_bytes[] = { 0x193, 0x1a7, -1 };
3389 static const int nosn_locked_bytes[] = { 0x16c, 0x193, 0x1a7, 0x1cf, -1 };
3390 static const int rwdw_locked_bytes[] = { 0x193, 0x1a7, 0x1cf, -1 };
3391 static const int wodw_locked_bytes[] = { 0x1a7, 0x1cf, -1 };
3392 static const int tr_locked_bytes[] = { 0x193, -1 };
3393 static const int no_locked_bytes[] = { -1 };
3394 static const int roex_locked_bytes[] = { 0x193, 0x1bb, 0x1cf, -1 };
3395
3396 static const int rwex_fail_ranges[] = { 0x193,0x1e3, -1 };
3397 static const int rw_fail_ranges[] = { 0x1bb,0x1e3, -1 };
3398 static const int rwdw_fail_ranges[] = { 0x1a7,0x1e3, -1 };
3399 static const int dw_fail_ranges[] = { 0x1a7,0x1cf, -1 };
3400 static const int tr_fail_ranges[] = { 0x1bb,0x1cf, -1 };
3401 static const int pr_fail_ranges[] = { 0x180,0x181, 0x1bb,0x1cf, -1 };
3402 static const int roex_fail_ranges[] = { 0x0,-1 };
3403
3404 static const struct lock_test lock_tests[] = {
3405 { STGM_PRIORITY, FALSE, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, priority_locked_bytes, pr_fail_ranges, FALSE },
3406 { STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, TRUE, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, rwex_locked_bytes, 0, FALSE },
3407 { STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE|STGM_TRANSACTED, TRUE, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, rwex_locked_bytes, 0, FALSE },
3408 { STGM_CREATE|STGM_READWRITE|STGM_TRANSACTED, TRUE, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, rw_locked_bytes, 0, FALSE },
3409 { STGM_CREATE|STGM_READWRITE|STGM_SHARE_DENY_WRITE|STGM_TRANSACTED, TRUE, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, rwdw_locked_bytes, 0, FALSE },
3410 { STGM_CREATE|STGM_WRITE|STGM_SHARE_DENY_WRITE|STGM_TRANSACTED, TRUE, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, wodw_locked_bytes, 0, FALSE },
3411 { STGM_SHARE_EXCLUSIVE|STGM_READWRITE, FALSE, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, rwex_locked_bytes, rwex_fail_ranges, FALSE },
3412 { STGM_SHARE_EXCLUSIVE|STGM_READWRITE|STGM_TRANSACTED, FALSE, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, rwex_locked_bytes, rwex_fail_ranges, FALSE },
3413 { STGM_READWRITE|STGM_TRANSACTED, FALSE, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, rw_locked_bytes, rw_fail_ranges, FALSE },
3414 { STGM_READWRITE|STGM_TRANSACTED|STGM_NOSNAPSHOT, FALSE, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, nosn_locked_bytes, rwdw_fail_ranges, FALSE },
3415 { STGM_READWRITE|STGM_TRANSACTED|STGM_SHARE_DENY_WRITE, FALSE, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, rwdw_locked_bytes, rwdw_fail_ranges, FALSE },
3416 { STGM_READ|STGM_SHARE_DENY_WRITE, FALSE, GENERIC_READ, FILE_SHARE_READ, no_locked_bytes, dw_fail_ranges, TRUE },
3417 { STGM_READ|STGM_TRANSACTED, FALSE, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, tr_locked_bytes, tr_fail_ranges, FALSE },
3418 { STGM_READ|STGM_SHARE_EXCLUSIVE, FALSE, GENERIC_READ, FILE_SHARE_READ, roex_locked_bytes, roex_fail_ranges, FALSE },
3419 { STGM_READ|STGM_SHARE_EXCLUSIVE|STGM_TRANSACTED, FALSE, GENERIC_READ, FILE_SHARE_READ, roex_locked_bytes, roex_fail_ranges, FALSE },
3420 };
3421
3422 static BOOL can_open(LPCWSTR filename, DWORD access, DWORD sharing)
3423 {
3424 HANDLE hfile;
3425
3426 hfile = CreateFileW(filename, access, sharing, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3427
3428 if (hfile == INVALID_HANDLE_VALUE)
3429 return FALSE;
3430
3431 CloseHandle(hfile);
3432 return TRUE;
3433 }
3434
3435 static void check_sharing(LPCWSTR filename, const struct lock_test *current,
3436 DWORD access, DWORD sharing, const char *desc, DWORD *open_mode, BOOL *any_failure)
3437 {
3438 if (can_open(filename, access, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE))
3439 {
3440 *open_mode = access;
3441 if (!current->todo || (current->sharing & sharing))
3442 ok(current->sharing & sharing ||
3443 broken(!(current->sharing & sharing) && access == GENERIC_WRITE && (current->stg_mode & 0xf) != STGM_READ) /* win2k */,
3444 "file with mode %x should not be openable with %s permission\n", current->stg_mode, desc);
3445 else
3446 {
3447 todo_wine ok(current->sharing & sharing ||
3448 broken(!(current->sharing & sharing) && access == GENERIC_WRITE && (current->stg_mode & 0xf) != STGM_READ) /* win2k */,
3449 "file with mode %x should not be openable with %s permission\n", current->stg_mode, desc);
3450 *any_failure = TRUE;
3451 }
3452 }
3453 else
3454 {
3455 if (!current->todo || !(current->sharing & sharing))
3456 ok(!(current->sharing & sharing), "file with mode %x should be openable with %s permission\n", current->stg_mode, desc);
3457 else
3458 {
3459 todo_wine ok(!(current->sharing & sharing), "file with mode %x should be openable with %s permission\n", current->stg_mode, desc);
3460 *any_failure = TRUE;
3461 }
3462 }
3463 }
3464
3465 static void check_access(LPCWSTR filename, const struct lock_test *current,
3466 DWORD access, DWORD sharing, const char *desc, DWORD open_mode, BOOL *any_failure)
3467 {
3468 if (can_open(filename, open_mode, (FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE) & ~sharing))
3469 {
3470 if (!current->todo || !(current->access & access))
3471 ok(!(current->access & access), "file with mode %x should not be openable without %s sharing\n", current->stg_mode, desc);
3472 else
3473 {
3474 todo_wine ok(!(current->access & access), "file with mode %x should not be openable without %s sharing\n", current->stg_mode, desc);
3475 *any_failure = TRUE;
3476 }
3477 }
3478 else
3479 {
3480 if (!current->todo || (current->access & access))
3481 ok(current->access & access, "file with mode %x should be openable without %s sharing\n", current->stg_mode, desc);
3482 else
3483 {
3484 todo_wine ok(current->access & access, "file with mode %x should be openable without %s sharing\n", current->stg_mode, desc);
3485 *any_failure = TRUE;
3486 }
3487 }
3488 }
3489
3490 static void test_locking(void)
3491 {
3492 static const WCHAR filename[] = {'w','i','n','e','t','e','s','t',0};
3493 int i;
3494 IStorage *stg;
3495 HRESULT hr;
3496
3497 for (i = 0; i < ARRAY_SIZE(lock_tests); i++)
3498 {
3499 const struct lock_test *current = &lock_tests[i];
3500 BOOL any_failure = FALSE;
3501 DWORD open_mode = 0;
3502
3503 if (current->create)
3504 {
3505 hr = StgCreateDocfile(filename, current->stg_mode, 0, &stg);
3506 ok(SUCCEEDED(hr), "StgCreateDocfile with mode %x failed with hr %x\n", current->stg_mode, hr);
3507 if (FAILED(hr)) continue;
3508 }
3509 else
3510 {
3511 hr = StgCreateDocfile(filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &stg);
3512 ok(SUCCEEDED(hr), "StgCreateDocfile failed with hr %x\n", hr);
3513 if (FAILED(hr)) continue;
3514 IStorage_Release(stg);
3515
3516 hr = StgOpenStorage(filename, NULL, current->stg_mode, NULL, 0, &stg);
3517 ok(SUCCEEDED(hr), "StgOpenStorage with mode %x failed with hr %x\n", current->stg_mode, hr);
3518 if (FAILED(hr))
3519 {
3520 DeleteFileW(filename);
3521 continue;
3522 }
3523 }
3524
3525 check_sharing(filename, current, GENERIC_READ, FILE_SHARE_READ, "READ", &open_mode, &any_failure);
3526 check_sharing(filename, current, GENERIC_WRITE, FILE_SHARE_WRITE, "WRITE", &open_mode, &any_failure);
3527 check_sharing(filename, current, DELETE, FILE_SHARE_DELETE, "DELETE", &open_mode, &any_failure);
3528
3529 if (open_mode != 0)
3530 {
3531 HANDLE hfile;
3532 BOOL locked, expect_locked;
3533 OVERLAPPED ol;
3534 const int* next_lock = current->locked_bytes;
3535
3536 check_access(filename, current, GENERIC_READ, FILE_SHARE_READ, "READ", open_mode, &any_failure);
3537 check_access(filename, current, GENERIC_WRITE, FILE_SHARE_WRITE, "WRITE", open_mode, &any_failure);
3538 check_access(filename, current, DELETE, FILE_SHARE_DELETE, "DELETE", open_mode, &any_failure);
3539
3540 hfile = CreateFileW(filename, open_mode, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3541 ok(hfile != INVALID_HANDLE_VALUE, "couldn't open file with mode %x\n", current->stg_mode);
3542
3543 ol.OffsetHigh = 0;
3544 ol.hEvent = NULL;
3545
3546 for (ol.Offset = 0x7ffffe00; ol.Offset != 0x80000000; ol.Offset++)
3547 {
3548 if (LockFileEx(hfile, LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY, 0, 1, 0, &ol))
3549 locked = FALSE;
3550 else
3551 {
3552 ok(!LockFileEx(hfile, LOCKFILE_FAIL_IMMEDIATELY, 0, 1, 0, &ol), "shared locks should not be used\n");
3553 locked = TRUE;
3554 }
3555
3556 UnlockFileEx(hfile, 0, 1, 0, &ol);
3557
3558 if ((ol.Offset&0x1ff) == *next_lock)
3559 {
3560 expect_locked = TRUE;
3561 next_lock++;
3562 }
3563 else
3564 expect_locked = FALSE;
3565
3566 if (!current->todo || locked == expect_locked)
3567 ok(locked == expect_locked, "byte %x of file with mode %x is %slocked but should %sbe\n",
3568 ol.Offset, current->stg_mode, locked?"":"not ", expect_locked?"":"not ");
3569 else
3570 {
3571 any_failure = TRUE;
3572 todo_wine ok(locked == expect_locked, "byte %x of file with mode %x is %slocked but should %sbe\n",
3573 ol.Offset, current->stg_mode, locked?"":"not ", expect_locked?"":"not ");
3574 }
3575 }
3576
3577 CloseHandle(hfile);
3578 }
3579
3580 IStorage_Release( stg );
3581
3582 if (!current->create)
3583 {
3584 HANDLE hfile;
3585 BOOL failed, expect_failed=FALSE;
3586 OVERLAPPED ol;
3587 const int* next_range = current->fail_ranges;
3588
3589 hfile = CreateFileW(filename, open_mode, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3590 ok(hfile != INVALID_HANDLE_VALUE, "couldn't open file with mode %x\n", current->stg_mode);
3591
3592 ol.OffsetHigh = 0;
3593 ol.hEvent = NULL;
3594
3595 for (ol.Offset = 0x7ffffe00; ol.Offset != 0x80000000; ol.Offset++)
3596 {
3597 if (ol.Offset == 0x7fffff92 ||
3598 (ol.Offset == 0x7fffff80 && current->stg_mode == (STGM_TRANSACTED|STGM_READWRITE)) ||
3599 (ol.Offset == 0x7fffff80 && current->stg_mode == (STGM_TRANSACTED|STGM_READ)))
3600 continue; /* This makes opens hang */
3601
3602 if (ol.Offset < 0x7fffff00)
3603 LockFileEx(hfile, 0, 0, 1, 0, &ol);
3604 else
3605 LockFileEx(hfile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &ol);
3606
3607 hr = StgOpenStorage(filename, NULL, current->stg_mode, NULL, 0, &stg);
3608 ok(hr == S_OK || hr == STG_E_LOCKVIOLATION || hr == STG_E_SHAREVIOLATION, "failed with unexpected hr %x\n", hr);
3609 if (SUCCEEDED(hr)) IStorage_Release(stg);
3610
3611 UnlockFileEx(hfile, 0, 1, 0, &ol);
3612
3613 failed = FAILED(hr);
3614
3615 if (!expect_failed && (ol.Offset&0x1ff) == next_range[0])
3616 {
3617 expect_failed = TRUE;
3618 }
3619 else if (expect_failed && (ol.Offset&0x1ff) == next_range[1])
3620 {
3621 expect_failed = FALSE;
3622 next_range += 2;
3623 }
3624
3625 if (!current->todo || failed == expect_failed)
3626 ok(failed == expect_failed, "open with byte %x locked, mode %x %s but should %s\n",
3627 ol.Offset, current->stg_mode, failed?"failed":"succeeded", expect_failed?"fail":"succeed");
3628 else
3629 {
3630 any_failure = TRUE;
3631 todo_wine ok(failed == expect_failed, "open with byte %x locked, mode %x %s but should %s\n",
3632 ol.Offset, current->stg_mode, failed?"failed":"succeeded", expect_failed?"fail":"succeed");
3633 }
3634 }
3635
3636 CloseHandle(hfile);
3637 }
3638
3639 DeleteFileW(filename);
3640
3641 if (current->todo && !any_failure)
3642 todo_wine ok(1, "tests succeeded for mode %x\n", current->stg_mode);
3643 }
3644 }
3645
3646 static void test_transacted_shared(void)
3647 {
3648 IStorage *stg = NULL;
3649 IStorage *stgrw = NULL;
3650 HRESULT r;
3651 IStream *stm = NULL;
3652 static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
3653 LARGE_INTEGER pos;
3654 ULARGE_INTEGER upos;
3655 char buffer[10];
3656 ULONG bytesread;
3657
3658 DeleteFileA(filenameA);
3659
3660 /* create a new transacted storage with a stream */
3661 r = StgCreateDocfile(filename, STGM_CREATE |
3662 STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
3663 ok(r==S_OK, "StgCreateDocfile failed %x\n", r);
3664
3665 r = WriteClassStg(stg, &test_stg_cls);
3666 ok(r == S_OK, "WriteClassStg failed %x\n", r);
3667
3668 r = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm);
3669 ok(r==S_OK, "IStorage->CreateStream failed %x\n", r);
3670
3671 pos.QuadPart = 0;
3672 r = IStream_Seek(stm, pos, 0, &upos);
3673 ok(r==S_OK, "IStream->Seek failed %x\n", r);
3674
3675 r = IStream_Write(stm, "aaa", 3, NULL);
3676 ok(r==S_OK, "IStream->Write failed %x\n", r);
3677
3678 r = IStorage_Commit(stg, STGC_ONLYIFCURRENT);
3679 ok(r==S_OK, "IStorage->Commit failed %x\n", r);
3680
3681 /* open a second transacted read/write storage */
3682 r = StgOpenStorage(filename, NULL, STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_DENY_NONE, NULL, 0, &stgrw);
3683 ok(r==S_OK, "StgOpenStorage failed %x\n", r);
3684
3685 /* update stream on the first storage and commit */
3686 pos.QuadPart = 0;
3687 r = IStream_Seek(stm, pos, 0, &upos);
3688 ok(r==S_OK, "IStream->Seek failed %x\n", r);
3689
3690 r = IStream_Write(stm, "ccc", 3, NULL);
3691 ok(r==S_OK, "IStream->Write failed %x\n", r);
3692
3693 r = IStorage_Commit(stg, STGC_ONLYIFCURRENT);
3694 ok(r==S_OK, "IStorage->Commit failed %x\n", r);
3695
3696 /* update again without committing */
3697 pos.QuadPart = 0;
3698 r = IStream_Seek(stm, pos, 0, &upos);
3699 ok(r==S_OK, "IStream->Seek failed %x\n", r);
3700
3701 r = IStream_Write(stm, "ddd", 3, NULL);
3702 ok(r==S_OK, "IStream->Write failed %x\n", r);
3703
3704 IStream_Release(stm);
3705
3706 /* we can still read the old content from the second storage */
3707 r = IStorage_OpenStream(stgrw, stmname, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &stm);
3708 ok(r==S_OK, "IStorage->OpenStream failed %x\n", r);
3709
3710 pos.QuadPart = 0;
3711 r = IStream_Seek(stm, pos, 0, &upos);
3712 ok(r==S_OK, "IStream->Seek failed %x\n", r);
3713
3714 r = IStream_Read(stm, buffer, sizeof(buffer), &bytesread);
3715 ok(r==S_OK, "IStream->Read failed %x\n", r);
3716 ok(bytesread == 3, "read wrong number of bytes %i\n", bytesread);
3717 ok(memcmp(buffer, "aaa", 3) == 0, "wrong data\n");
3718
3719 /* and overwrite the data */
3720 pos.QuadPart = 0;
3721 r = IStream_Seek(stm, pos, 0, &upos);
3722 ok(r==S_OK, "IStream->Seek failed %x\n", r);
3723
3724 r = IStream_Write(stm, "bbb", 3, NULL);
3725 ok(r==S_OK, "IStream->Write failed %x\n", r);
3726
3727 IStream_Release(stm);
3728
3729 /* commit fails because we're out of date */
3730 r = IStorage_Commit(stgrw, STGC_ONLYIFCURRENT);
3731 ok(r==STG_E_NOTCURRENT, "IStorage->Commit failed %x\n", r);
3732
3733 /* unless we force it */
3734 r = IStorage_Commit(stgrw, STGC_DEFAULT);
3735 ok(r==S_OK, "IStorage->Commit failed %x\n", r);
3736
3737 /* reverting gets us back to the last commit from the same storage */
3738 r = IStorage_Revert(stg);
3739 ok(r==S_OK, "IStorage->Revert failed %x\n", r);
3740
3741 r = IStorage_OpenStream(stg, stmname, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &stm);
3742 ok(r==S_OK, "IStorage->CreateStream failed %x\n", r);
3743
3744 pos.QuadPart = 0;
3745 r = IStream_Seek(stm, pos, 0, &upos);
3746 ok(r==S_OK, "IStream->Seek failed %x\n", r);
3747
3748 r = IStream_Read(stm, buffer, sizeof(buffer), &bytesread);
3749 ok(r==S_OK, "IStream->Read failed %x\n", r);
3750 ok(bytesread == 3, "read wrong number of bytes %i\n", bytesread);
3751 ok(memcmp(buffer, "ccc", 3) == 0, "wrong data\n");
3752
3753 /* and committing fails forever */
3754 r = IStorage_Commit(stg, STGC_ONLYIFCURRENT);
3755 ok(r==STG_E_NOTCURRENT, "IStorage->Commit failed %x\n", r);
3756
3757 IStream_Release(stm);
3758
3759 IStorage_Release(stg);
3760 IStorage_Release(stgrw);
3761
3762 DeleteFileA(filenameA);
3763 }
3764
3765 static void test_overwrite(void)
3766 {
3767 IStorage *stg = NULL;
3768 HRESULT r;
3769 IStream *stm = NULL;
3770 static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
3771 static const WCHAR stmname2[] = { 'C','O','N','T','E','N','T','2',0 };
3772 LARGE_INTEGER pos;
3773 ULARGE_INTEGER upos;
3774 char buffer[4096];
3775 DWORD orig_size, new_size;
3776 ULONG bytesread;
3777 HANDLE hfile;
3778 int i;
3779
3780 DeleteFileA(filenameA);
3781
3782 r = StgCreateDocfile(filename, STGM_CREATE | STGM_READWRITE | STGM_TRANSACTED, 0, &stg);
3783 ok(r==S_OK, "StgCreateDocfile failed %x\n", r);
3784
3785 r = WriteClassStg(stg, &test_stg_cls);
3786 ok(r == S_OK, "WriteClassStg failed %x\n", r);
3787
3788 r = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm);
3789 ok(r==S_OK, "IStorage->CreateStream failed %x\n", r);
3790
3791 pos.QuadPart = 0;
3792 r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &upos);
3793 ok(r==S_OK, "IStream->Seek failed %x\n", r);
3794
3795 memset(buffer, 'a', sizeof(buffer));
3796 for (i=0; i<4; i++)
3797 {
3798 /* Write enough bytes to pass the minimum storage file size */
3799 r = IStream_Write(stm, buffer, sizeof(buffer), NULL);
3800 ok(r==S_OK, "IStream->Write failed %x\n", r);
3801 }
3802
3803 r = IStorage_Commit(stg, STGC_DEFAULT);
3804 ok(r==S_OK, "IStorage->Commit failed %x\n", r);
3805
3806 hfile = CreateFileA(filenameA, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
3807 NULL, OPEN_EXISTING, 0, NULL);
3808 ok(hfile != NULL, "couldn't open file %d\n", GetLastError());
3809
3810 orig_size = GetFileSize(hfile, NULL);
3811
3812 pos.QuadPart = 0;
3813 r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &upos);
3814 ok(r==S_OK, "IStream->Seek failed %x\n", r);
3815
3816 r = IStream_Write(stm, "b", 1, NULL);
3817 ok(r==S_OK, "IStream->Write failed %x\n", r);
3818
3819 r = IStorage_Commit(stg, STGC_OVERWRITE);
3820 ok(r==S_OK, "IStorage->Commit failed %x\n", r);
3821
3822 new_size = GetFileSize(hfile, NULL);
3823
3824 todo_wine ok(new_size == orig_size, "file grew from %d bytes to %d\n", orig_size, new_size);
3825
3826 IStream_Release(stm);
3827
3828 IStorage_RenameElement(stg, stmname, stmname2);
3829
3830 r = IStorage_Commit(stg, STGC_OVERWRITE);
3831 ok(r==S_OK, "IStorage->Commit failed %x\n", r);
3832
3833 new_size = GetFileSize(hfile, NULL);
3834
3835 todo_wine ok(new_size == orig_size, "file grew from %d bytes to %d\n", orig_size, new_size);
3836
3837 IStorage_Release(stg);
3838
3839 r = StgOpenStorage(filename, NULL, STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg);
3840 ok(r==S_OK, "StgOpenStorage failed %x\n", r);
3841
3842 r = IStorage_OpenStream(stg, stmname2, NULL, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &stm);
3843 ok(r==S_OK, "IStorage->CreateStream failed %x\n", r);
3844
3845 r = IStream_Read(stm, buffer, sizeof(buffer), &bytesread);
3846 ok(r==S_OK, "IStream->Write failed %x\n", r);
3847 ok(bytesread == sizeof(buffer), "only read %d bytes\n", bytesread);
3848 ok(buffer[0] == 'b', "unexpected data at byte 0\n");
3849
3850 for (i=1; i<sizeof(buffer); i++)
3851 if (buffer[i] != 'a')
3852 break;
3853 ok(i == sizeof(buffer), "unexpected data at byte %i\n", i);
3854
3855 pos.QuadPart = 0;
3856 r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &upos);
3857 ok(r==S_OK, "IStream->Seek failed %x\n", r);
3858
3859 r = IStream_Write(stm, "c", 1, NULL);
3860 ok(r==S_OK, "IStream->Write failed %x\n", r);
3861
3862 r = IStorage_Commit(stg, STGC_OVERWRITE);
3863 ok(r==S_OK, "IStorage->Commit failed %x\n", r);
3864
3865 new_size = GetFileSize(hfile, NULL);
3866
3867 todo_wine ok(new_size == orig_size, "file grew from %d bytes to %d\n", orig_size, new_size);
3868
3869 IStream_Release(stm);
3870
3871 IStorage_Release(stg);
3872
3873 CloseHandle(hfile);
3874
3875 DeleteFileA(filenameA);
3876 }
3877
3878 static void test_custom_lockbytes(void)
3879 {
3880 static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
3881 TestLockBytes* lockbytes;
3882 HRESULT hr;
3883 IStorage* stg;
3884 IStream* stm;
3885
3886 CreateTestLockBytes(&lockbytes);
3887
3888 hr = StgCreateDocfileOnILockBytes(&lockbytes->ILockBytes_iface, STGM_CREATE|STGM_READWRITE|STGM_TRANSACTED, 0, &stg);
3889 ok(hr==S_OK, "StgCreateDocfileOnILockBytes failed %x\n", hr);
3890
3891 hr = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &stm);
3892 ok(hr==S_OK, "IStorage_CreateStream failed %x\n", hr);
3893
3894 IStream_Release(stm);
3895
3896 hr = IStorage_Commit(stg, 0);
3897
3898 IStorage_Release(stg);
3899
3900 ok(!lockbytes->lock_called, "unexpected call to LockRegion\n");
3901
3902 lockbytes->locks_supported = LOCK_WRITE|LOCK_EXCLUSIVE|LOCK_ONLYONCE;
3903
3904 hr = StgCreateDocfileOnILockBytes(&lockbytes->ILockBytes_iface, STGM_CREATE|STGM_READWRITE|STGM_TRANSACTED, 0, &stg);
3905 ok(hr==S_OK, "StgCreateDocfileOnILockBytes failed %x\n", hr);
3906
3907 hr = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &stm);
3908 ok(hr==S_OK, "IStorage_CreateStream failed %x\n", hr);
3909
3910 IStream_Release(stm);
3911
3912 hr = IStorage_Commit(stg, 0);
3913
3914 IStorage_Release(stg);
3915
3916 ok(lockbytes->lock_called, "expected LockRegion to be called\n");
3917
3918 lockbytes->lock_hr = STG_E_INVALIDFUNCTION;
3919
3920 hr = StgCreateDocfileOnILockBytes(&lockbytes->ILockBytes_iface, STGM_CREATE|STGM_READWRITE|STGM_TRANSACTED, 0, &stg);
3921 ok(hr==STG_E_INVALIDFUNCTION, "StgCreateDocfileOnILockBytes failed %x\n", hr);
3922
3923 DeleteTestLockBytes(lockbytes);
3924 }
3925
3926 START_TEST(storage32)
3927 {
3928 CHAR temp[MAX_PATH];
3929
3930 GetTempPathA(MAX_PATH, temp);
3931 if(!GetTempFileNameA(temp, "stg", 0, filenameA))
3932 {
3933 win_skip("Could not create temp file, %u\n", GetLastError());
3934 return;
3935 }
3936 MultiByteToWideChar(CP_ACP, 0, filenameA, -1, filename, MAX_PATH);
3937 DeleteFileA(filenameA);
3938
3939 test_hglobal_storage_stat();
3940 test_create_storage_modes();
3941 test_stgcreatestorageex();
3942 test_storage_stream();
3943 test_open_storage();
3944 test_storage_suminfo();
3945 test_storage_refcount();
3946 test_streamenum();
3947 test_transact();
3948 test_substorage_share();
3949 test_revert();
3950 test_parent_free();
3951 test_nonroot_transacted();
3952 test_ReadClassStm();
3953 test_access();
3954 test_writeclassstg();
3955 test_readonly();
3956 test_simple();
3957 test_fmtusertypestg();
3958 test_references();
3959 test_copyto();
3960 test_copyto_snbexclusions();
3961 test_copyto_iidexclusions_storage();
3962 test_copyto_iidexclusions_stream();
3963 test_rename();
3964 test_toplevel_stat();
3965 test_substorage_enum();
3966 test_copyto_locking();
3967 test_copyto_recursive();
3968 test_hglobal_storage_creation();
3969 test_convert();
3970 test_direct_swmr();
3971 test_locking();
3972 test_transacted_shared();
3973 test_overwrite();
3974 test_custom_lockbytes();
3975 }