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