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