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