[CREDUI_WINETEST] Sync with Wine Staging 1.9.4. CORE-10912
[reactos.git] / rostests / winetests / ole32 / storage32.c
1 /*
2 * Unit tests for OLE storage
3 *
4 * Copyright (c) 2004 Mike McCormack
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #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;
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 r = ReadClassStg( stg, NULL );
1196 ok(r == E_INVALIDARG, "ReadClassStg should return E_INVALIDARG instead of 0x%08X\n", r);
1197
1198 temp_cls.Data1 = 0xdeadbeef;
1199 r = ReadClassStg( stg, &temp_cls );
1200 ok(r == S_OK, "ReadClassStg failed with 0x%08X\n", r);
1201
1202 ok(IsEqualCLSID(&temp_cls, &CLSID_NULL), "ReadClassStg returned wrong clsid\n");
1203
1204 r = WriteClassStg( NULL, NULL );
1205 ok(r == E_INVALIDARG, "WriteClassStg should return E_INVALIDARG instead of 0x%08X\n", r);
1206
1207 r = WriteClassStg( stg, NULL );
1208 ok(r == STG_E_INVALIDPOINTER, "WriteClassStg should return STG_E_INVALIDPOINTER instead of 0x%08X\n", r);
1209
1210 r = WriteClassStg( stg, &test_stg_cls );
1211 ok( r == S_OK, "WriteClassStg failed with 0x%08X\n", r);
1212
1213 r = ReadClassStg( stg, &temp_cls );
1214 ok( r == S_OK, "ReadClassStg failed with 0x%08X\n", r);
1215 ok(IsEqualCLSID(&temp_cls, &test_stg_cls), "ReadClassStg returned wrong clsid\n");
1216
1217 r = IStorage_Release( stg );
1218 ok (r == 0, "storage not released\n");
1219
1220 DeleteFileA(filenameA);
1221 }
1222
1223 static void test_streamenum(void)
1224 {
1225 IStorage *stg = NULL;
1226 HRESULT r;
1227 IStream *stm = NULL;
1228 static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
1229 static const WCHAR stmname2[] = { 'A','B','C','D','E','F','G','H','I',0 };
1230 static const WCHAR stmname3[] = { 'A','B','C','D','E','F','G','H','I','J',0 };
1231 static const STATSTG stat_null;
1232 STATSTG stat;
1233 IEnumSTATSTG *ee = NULL;
1234 ULONG count;
1235
1236 DeleteFileA(filenameA);
1237
1238 /* create the file */
1239 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
1240 STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
1241 ok(r==S_OK, "StgCreateDocfile failed\n");
1242
1243 r = WriteClassStg( stg, &test_stg_cls );
1244 ok( r == S_OK, "WriteClassStg failed\n");
1245
1246 r = IStorage_Commit( stg, STGC_DEFAULT );
1247 ok( r == S_OK, "IStorage_Commit failed\n");
1248
1249 /* now create a stream */
1250 r = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
1251 ok(r==S_OK, "IStorage->CreateStream failed\n");
1252
1253 IStream_Release(stm);
1254
1255 /* first enum ... should be 1 stream */
1256 r = IStorage_EnumElements(stg, 0, NULL, 0, &ee);
1257 ok(r==S_OK, "IStorage->EnumElements failed\n");
1258
1259 count = 0xf00;
1260 r = IEnumSTATSTG_Next(ee, 1, &stat, &count);
1261 ok(r==S_OK, "IEnumSTATSTG->Next failed\n");
1262 ok(count == 1, "count wrong\n");
1263
1264 if (r == S_OK)
1265 CoTaskMemFree(stat.pwcsName);
1266
1267 r = IEnumSTATSTG_Release(ee);
1268 ok(r==S_OK, "EnumSTATSTG_Release failed with error 0x%08x\n", r);
1269
1270 /* second enum... destroy the stream before reading */
1271 r = IStorage_EnumElements(stg, 0, NULL, 0, &ee);
1272 ok(r==S_OK, "IStorage->EnumElements failed\n");
1273
1274 r = IStorage_DestroyElement(stg, stmname);
1275 ok(r==S_OK, "IStorage->DestroyElement failed\n");
1276
1277 memset(&stat, 0xad, sizeof(stat));
1278 count = 0xf00;
1279 r = IEnumSTATSTG_Next(ee, 1, &stat, &count);
1280 ok(r==S_FALSE, "IEnumSTATSTG->Next failed\n");
1281 ok(count == 0, "count wrong\n");
1282 ok(memcmp(&stat, &stat_null, sizeof(stat)) == 0, "stat is not zeroed\n");
1283
1284 /* reset and try again */
1285 r = IEnumSTATSTG_Reset(ee);
1286 ok(r==S_OK, "IEnumSTATSTG->Reset failed\n");
1287
1288 count = 0xf00;
1289 r = IEnumSTATSTG_Next(ee, 1, &stat, &count);
1290 ok(r==S_FALSE, "IEnumSTATSTG->Next failed\n");
1291 ok(count == 0, "count wrong\n");
1292
1293 /* add a stream before reading */
1294 r = IEnumSTATSTG_Reset(ee);
1295 ok(r==S_OK, "IEnumSTATSTG->Reset failed\n");
1296
1297 r = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
1298 ok(r==S_OK, "IStorage->CreateStream failed\n");
1299
1300 r = IStream_Release(stm);
1301 ok(r==S_OK, "Stream_Release failed with error 0x%08x\n", r);
1302
1303 count = 0xf00;
1304 r = IEnumSTATSTG_Next(ee, 1, &stat, &count);
1305 ok(r==S_OK, "IEnumSTATSTG->Next failed\n");
1306 ok(count == 1, "count wrong\n");
1307
1308 if (r == S_OK)
1309 {
1310 ok(lstrcmpiW(stat.pwcsName, stmname) == 0, "expected CONTENTS, got %s\n", wine_dbgstr_w(stat.pwcsName));
1311 CoTaskMemFree(stat.pwcsName);
1312 }
1313
1314 r = IStorage_CreateStream(stg, stmname2, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
1315 ok(r==S_OK, "IStorage->CreateStream failed\n");
1316
1317 r = IStream_Release(stm);
1318 ok(r==S_OK, "Stream_Release failed with error 0x%08x\n", r);
1319
1320 count = 0xf00;
1321 r = IEnumSTATSTG_Next(ee, 1, &stat, &count);
1322 ok(r==S_OK, "IEnumSTATSTG->Next failed\n");
1323 ok(count == 1, "count wrong\n");
1324
1325 if (r == S_OK)
1326 {
1327 ok(lstrcmpiW(stat.pwcsName, stmname2) == 0, "expected ABCDEFGHI, got %s\n", wine_dbgstr_w(stat.pwcsName));
1328 CoTaskMemFree(stat.pwcsName);
1329 }
1330
1331 /* delete previous and next stream after reading */
1332 r = IStorage_CreateStream(stg, stmname3, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
1333 ok(r==S_OK, "IStorage->CreateStream failed\n");
1334
1335 r = IStream_Release(stm);
1336 ok(r==S_OK, "Stream_Release failed with error 0x%08x\n", r);
1337
1338 r = IEnumSTATSTG_Reset(ee);
1339 ok(r==S_OK, "IEnumSTATSTG->Reset failed\n");
1340
1341 count = 0xf00;
1342 r = IEnumSTATSTG_Next(ee, 1, &stat, &count);
1343 ok(r==S_OK, "IEnumSTATSTG->Next failed\n");
1344 ok(count == 1, "count wrong\n");
1345
1346 if (r == S_OK)
1347 {
1348 ok(lstrcmpiW(stat.pwcsName, stmname) == 0, "expected CONTENTS, got %s\n", wine_dbgstr_w(stat.pwcsName));
1349 CoTaskMemFree(stat.pwcsName);
1350 }
1351
1352 r = IStorage_DestroyElement(stg, stmname);
1353 ok(r==S_OK, "IStorage->DestroyElement failed\n");
1354
1355 r = IStorage_DestroyElement(stg, stmname2);
1356 ok(r==S_OK, "IStorage->DestroyElement failed\n");
1357
1358 count = 0xf00;
1359 r = IEnumSTATSTG_Next(ee, 1, &stat, &count);
1360 ok(r==S_OK, "IEnumSTATSTG->Next failed\n");
1361 ok(count == 1, "count wrong\n");
1362
1363 if (r == S_OK)
1364 {
1365 ok(lstrcmpiW(stat.pwcsName, stmname3) == 0, "expected ABCDEFGHIJ, got %s\n", wine_dbgstr_w(stat.pwcsName));
1366 CoTaskMemFree(stat.pwcsName);
1367 }
1368
1369 r = IStorage_Release( stg );
1370 todo_wine ok (r == 0, "storage not released\n");
1371
1372 /* enumerator is still valid and working after the storage is released */
1373 r = IEnumSTATSTG_Reset(ee);
1374 ok(r==S_OK, "IEnumSTATSTG->Reset failed\n");
1375
1376 count = 0xf00;
1377 r = IEnumSTATSTG_Next(ee, 1, &stat, &count);
1378 ok(r==S_OK, "IEnumSTATSTG->Next failed\n");
1379 ok(count == 1, "count wrong\n");
1380
1381 if (r == S_OK)
1382 {
1383 ok(lstrcmpiW(stat.pwcsName, stmname3) == 0, "expected ABCDEFGHIJ, got %s\n", wine_dbgstr_w(stat.pwcsName));
1384 CoTaskMemFree(stat.pwcsName);
1385 }
1386
1387 /* the storage is left open until the enumerator is freed */
1388 r = StgOpenStorage( filename, NULL, STGM_SHARE_EXCLUSIVE |
1389 STGM_READWRITE |STGM_TRANSACTED, NULL, 0, &stg);
1390 ok(r==STG_E_SHAREVIOLATION ||
1391 r==STG_E_LOCKVIOLATION, /* XP-SP2/W2K3-SP1 and below */
1392 "StgCreateDocfile failed, res=%x\n", r);
1393
1394 r = IEnumSTATSTG_Release(ee);
1395 ok (r == 0, "enum not released\n");
1396
1397 DeleteFileA(filenameA);
1398 }
1399
1400 static void test_transact(void)
1401 {
1402 IStorage *stg = NULL, *stg2 = NULL, *stg3 = NULL;
1403 HRESULT r;
1404 IStream *stm = NULL;
1405 static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
1406 static const WCHAR stmname2[] = { 'F','O','O',0 };
1407 static const WCHAR stgname[] = { 'P','E','R','M','S','T','G',0 };
1408 static const WCHAR stgname2[] = { 'T','E','M','P','S','T','G',0 };
1409 BOOL ret;
1410
1411 DeleteFileA(filenameA);
1412
1413 /* create the file */
1414 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
1415 STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
1416 ok(r==S_OK, "StgCreateDocfile failed\n");
1417
1418 /* commit a new stream and storage */
1419 r = IStorage_CreateStream(stg, stmname2, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
1420 ok(r==S_OK, "IStorage->CreateStream failed\n");
1421
1422 r = IStream_Write(stm, "this is stream 1\n", 16, NULL);
1423 ok(r==S_OK, "IStream->Write failed\n");
1424
1425 IStream_Release(stm);
1426
1427 r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
1428 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
1429
1430 if (r == S_OK)
1431 {
1432 /* Create two substorages but only commit one */
1433 r = IStorage_CreateStorage(stg2, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg3);
1434 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
1435
1436 if (r == S_OK)
1437 IStorage_Release(stg3);
1438
1439 r = IStorage_Commit(stg, 0);
1440 ok(r==S_OK, "IStorage->Commit failed\n");
1441
1442 r = IStorage_CreateStorage(stg2, stgname2, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg3);
1443 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
1444
1445 if (r == S_OK)
1446 IStorage_Release(stg3);
1447
1448 IStorage_Release(stg2);
1449 }
1450
1451 /* now create a stream and storage, but don't commit them */
1452 stm = NULL;
1453 r = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
1454 ok(r==S_OK, "IStorage->CreateStream failed\n");
1455
1456 r = IStream_Write(stm, "this is stream 2\n", 16, NULL);
1457 ok(r==S_OK, "IStream->Write failed\n");
1458
1459 /* IStream::Commit does nothing for OLE storage streams */
1460 r = IStream_Commit(stm, STGC_ONLYIFCURRENT | STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE);
1461 ok(r==S_OK, "IStream->Commit failed\n");
1462
1463 r = IStorage_CreateStorage(stg, stgname2, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
1464 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
1465
1466 if (r == S_OK)
1467 IStorage_Release(stg2);
1468
1469 IStream_Release(stm);
1470
1471 IStorage_Release(stg);
1472
1473 stm = NULL;
1474 stg = NULL;
1475 r = StgOpenStorage( filename, NULL, STGM_SHARE_DENY_NONE | STGM_READ | STGM_TRANSACTED, NULL, 0, &stg);
1476 ok(r==S_OK, "StgOpenStorage failed\n");
1477
1478 if (!stg)
1479 return;
1480
1481 r = IStorage_OpenStream(stg, stmname, NULL, STGM_SHARE_DENY_NONE|STGM_READ, 0, &stm );
1482 ok(r==STG_E_INVALIDFLAG, "IStorage->OpenStream failed %08x\n", r);
1483
1484 r = IStorage_OpenStream(stg, stmname, NULL, STGM_DELETEONRELEASE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
1485 ok(r==STG_E_INVALIDFUNCTION, "IStorage->OpenStream failed %08x\n", r);
1486
1487 r = IStorage_OpenStream(stg, stmname, NULL, STGM_TRANSACTED|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
1488 ok(r==STG_E_INVALIDFUNCTION, "IStorage->OpenStream failed %08x\n", r);
1489
1490 r = IStorage_OpenStorage(stg, stmname, NULL, STGM_TRANSACTED|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg2 );
1491 ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStream failed %08x\n", r);
1492
1493 r = IStorage_OpenStream(stg, stmname, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
1494 ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStream should fail %08x\n", r);
1495 if (r == S_OK)
1496 IStream_Release(stm);
1497
1498 r = IStorage_OpenStorage(stg, stgname2, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg2 );
1499 ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStorage should fail %08x\n", r);
1500 if (r == S_OK)
1501 IStorage_Release(stg2);
1502
1503 r = IStorage_OpenStorage(stg, stmname2, NULL, STGM_TRANSACTED|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg2 );
1504 ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStream failed %08x\n", r);
1505
1506 r = IStorage_OpenStream(stg, stmname2, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
1507 ok(r==S_OK, "IStorage->OpenStream should succeed %08x\n", r);
1508 if (r == S_OK)
1509 IStream_Release(stm);
1510
1511 r = IStorage_OpenStorage(stg, stgname, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg2 );
1512 ok(r==S_OK, "IStorage->OpenStorage should succeed %08x\n", r);
1513 if (r == S_OK)
1514 {
1515 r = IStorage_OpenStorage(stg2, stgname, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg3 );
1516 ok(r==S_OK, "IStorage->OpenStorage should succeed %08x\n", r);
1517 if (r == S_OK)
1518 IStorage_Release(stg3);
1519
1520 r = IStorage_OpenStorage(stg2, stgname2, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg3 );
1521 ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStorage should fail %08x\n", r);
1522 if (r == S_OK)
1523 IStorage_Release(stg3);
1524
1525 IStorage_Release(stg2);
1526 }
1527
1528 IStorage_Release(stg);
1529
1530 ret = DeleteFileA(filenameA);
1531 ok(ret, "deleted file\n");
1532 }
1533
1534 static void test_substorage_share(void)
1535 {
1536 IStorage *stg, *stg2, *stg3;
1537 IStream *stm, *stm2;
1538 HRESULT r;
1539 static const WCHAR stgname[] = { 'P','E','R','M','S','T','G',0 };
1540 static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
1541 static const WCHAR othername[] = { 'N','E','W','N','A','M','E',0 };
1542 BOOL ret;
1543
1544 DeleteFileA(filenameA);
1545
1546 /* create the file */
1547 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
1548 STGM_READWRITE, 0, &stg);
1549 ok(r==S_OK, "StgCreateDocfile failed\n");
1550
1551 /* create a read/write storage and try to open it again */
1552 r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
1553 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
1554
1555 if (r == S_OK)
1556 {
1557 r = IStorage_OpenStorage(stg, stgname, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg3);
1558 ok(r==STG_E_ACCESSDENIED, "IStorage->OpenStorage should fail %08x\n", r);
1559
1560 if (r == S_OK)
1561 IStorage_Release(stg3);
1562
1563 r = IStorage_OpenStorage(stg, stgname, NULL, STGM_READ | 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 /* cannot rename the storage while it's open */
1570 r = IStorage_RenameElement(stg, stgname, othername);
1571 ok(r==STG_E_ACCESSDENIED, "IStorage->RenameElement should fail %08x\n", r);
1572 if (SUCCEEDED(r)) IStorage_RenameElement(stg, othername, stgname);
1573
1574 /* destroying an object while it's open invalidates it */
1575 r = IStorage_DestroyElement(stg, stgname);
1576 ok(r==S_OK, "IStorage->DestroyElement failed, hr=%08x\n", r);
1577
1578 r = IStorage_CreateStream(stg2, stmname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm);
1579 ok(r==STG_E_REVERTED, "IStorage->CreateStream failed, hr=%08x\n", r);
1580
1581 if (r == S_OK)
1582 IStream_Release(stm);
1583
1584 IStorage_Release(stg2);
1585 }
1586
1587 /* create a read/write stream and try to open it again */
1588 r = IStorage_CreateStream(stg, stmname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm);
1589 ok(r==S_OK, "IStorage->CreateStream failed, hr=%08x\n", r);
1590
1591 if (r == S_OK)
1592 {
1593 r = IStorage_OpenStream(stg, stmname, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &stm2);
1594 ok(r==STG_E_ACCESSDENIED, "IStorage->OpenStream should fail %08x\n", r);
1595
1596 if (r == S_OK)
1597 IStream_Release(stm2);
1598
1599 r = IStorage_OpenStream(stg, stmname, NULL, STGM_READ | 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 /* cannot rename the stream while it's open */
1606 r = IStorage_RenameElement(stg, stmname, othername);
1607 ok(r==STG_E_ACCESSDENIED, "IStorage->RenameElement should fail %08x\n", r);
1608 if (SUCCEEDED(r)) IStorage_RenameElement(stg, othername, stmname);
1609
1610 /* destroying an object while it's open invalidates it */
1611 r = IStorage_DestroyElement(stg, stmname);
1612 ok(r==S_OK, "IStorage->DestroyElement failed, hr=%08x\n", r);
1613
1614 r = IStream_Write(stm, "this shouldn't work\n", 20, NULL);
1615 ok(r==STG_E_REVERTED, "IStream_Write should fail %08x\n", r);
1616
1617 IStream_Release(stm);
1618 }
1619
1620 IStorage_Release(stg);
1621
1622 ret = DeleteFileA(filenameA);
1623 ok(ret, "deleted file\n");
1624 }
1625
1626 static void test_revert(void)
1627 {
1628 IStorage *stg = NULL, *stg2 = NULL, *stg3 = NULL;
1629 HRESULT r;
1630 IStream *stm = NULL, *stm2 = NULL;
1631 static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
1632 static const WCHAR stmname2[] = { 'F','O','O',0 };
1633 static const WCHAR stgname[] = { 'P','E','R','M','S','T','G',0 };
1634 static const WCHAR stgname2[] = { 'T','E','M','P','S','T','G',0 };
1635 STATSTG statstg;
1636 BOOL ret;
1637
1638 DeleteFileA(filenameA);
1639
1640 /* create the file */
1641 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
1642 STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
1643 ok(r==S_OK, "StgCreateDocfile failed\n");
1644
1645 /* commit a new stream and storage */
1646 r = IStorage_CreateStream(stg, stmname2, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
1647 ok(r==S_OK, "IStorage->CreateStream failed\n");
1648
1649 r = IStream_Write(stm, "this is stream 1\n", 16, NULL);
1650 ok(r==S_OK, "IStream->Write failed\n");
1651
1652 r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
1653 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
1654
1655 if (r == S_OK)
1656 {
1657 /* Create two substorages but only commit one */
1658 r = IStorage_CreateStorage(stg2, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg3);
1659 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
1660
1661 if (r == S_OK)
1662 IStorage_Release(stg3);
1663
1664 r = IStorage_Commit(stg, 0);
1665 ok(r==S_OK, "IStorage->Commit failed\n");
1666
1667 r = IStorage_CreateStorage(stg2, stgname2, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg3);
1668 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
1669
1670 if (r == S_OK)
1671 IStorage_Release(stg3);
1672 }
1673
1674 /* now create a stream and storage, then revert */
1675 r = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm2 );
1676 ok(r==S_OK, "IStorage->CreateStream failed\n");
1677
1678 r = IStream_Write(stm2, "this is stream 2\n", 16, NULL);
1679 ok(r==S_OK, "IStream->Write failed\n");
1680
1681 r = IStorage_CreateStorage(stg, stgname2, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg3);
1682 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
1683
1684 r = IStorage_Revert(stg);
1685 ok(r==S_OK, "Storage_Revert failed with error 0x%08x\n", r);
1686
1687 /* all open objects become invalid */
1688 r = IStream_Write(stm, "this shouldn't work\n", 20, NULL);
1689 ok(r==STG_E_REVERTED, "IStream_Write should fail %08x\n", r);
1690
1691 r = IStream_Write(stm2, "this shouldn't work\n", 20, NULL);
1692 ok(r==STG_E_REVERTED, "IStream_Write should fail %08x\n", r);
1693
1694 r = IStorage_Stat(stg2, &statstg, STATFLAG_NONAME);
1695 ok(r==STG_E_REVERTED, "IStorage_Stat should fail %08x\n", r);
1696
1697 r = IStorage_Stat(stg3, &statstg, STATFLAG_NONAME);
1698 ok(r==STG_E_REVERTED, "IStorage_Stat should fail %08x\n", r);
1699
1700 IStream_Release(stm);
1701 IStream_Release(stm2);
1702 IStorage_Release(stg2);
1703 IStorage_Release(stg3);
1704
1705 r = IStorage_OpenStream(stg, stmname, NULL, STGM_SHARE_DENY_NONE|STGM_READ, 0, &stm );
1706 ok(r==STG_E_INVALIDFLAG, "IStorage->OpenStream failed %08x\n", r);
1707
1708 r = IStorage_OpenStream(stg, stmname, NULL, STGM_DELETEONRELEASE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
1709 ok(r==STG_E_INVALIDFUNCTION, "IStorage->OpenStream failed %08x\n", r);
1710
1711 r = IStorage_OpenStream(stg, stmname, NULL, STGM_TRANSACTED|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
1712 ok(r==STG_E_INVALIDFUNCTION, "IStorage->OpenStream failed %08x\n", r);
1713
1714 r = IStorage_OpenStorage(stg, stmname, NULL, STGM_TRANSACTED|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg2 );
1715 ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStream failed %08x\n", r);
1716
1717 r = IStorage_OpenStream(stg, stmname, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
1718 ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStream should fail %08x\n", r);
1719 if (r == S_OK)
1720 IStream_Release(stm);
1721
1722 r = IStorage_OpenStorage(stg, stgname2, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg2 );
1723 ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStorage should fail %08x\n", r);
1724 if (r == S_OK)
1725 IStorage_Release(stg2);
1726
1727 r = IStorage_OpenStorage(stg, stmname2, NULL, STGM_TRANSACTED|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg2 );
1728 ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStream failed %08x\n", r);
1729
1730 r = IStorage_OpenStream(stg, stmname2, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
1731 ok(r==S_OK, "IStorage->OpenStream should succeed %08x\n", r);
1732 if (r == S_OK)
1733 IStream_Release(stm);
1734
1735 r = IStorage_OpenStorage(stg, stgname, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg2 );
1736 ok(r==S_OK, "IStorage->OpenStorage should succeed %08x\n", r);
1737 if (r == S_OK)
1738 {
1739 r = IStorage_OpenStorage(stg2, stgname, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg3 );
1740 ok(r==S_OK, "IStorage->OpenStorage should succeed %08x\n", r);
1741 if (r == S_OK)
1742 IStorage_Release(stg3);
1743
1744 r = IStorage_OpenStorage(stg2, stgname2, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg3 );
1745 ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStorage should fail %08x\n", r);
1746 if (r == S_OK)
1747 IStorage_Release(stg3);
1748
1749 IStorage_Release(stg2);
1750 }
1751
1752 IStorage_Release(stg);
1753
1754 ret = DeleteFileA(filenameA);
1755 ok(ret, "deleted file\n");
1756
1757 /* Revert only invalidates objects in transacted mode */
1758 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
1759 STGM_READWRITE, 0, &stg);
1760 ok(r==S_OK, "StgCreateDocfile failed\n");
1761
1762 r = IStorage_CreateStream(stg, stmname2, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
1763 ok(r==S_OK, "IStorage->CreateStream failed\n");
1764
1765 r = IStorage_Revert(stg);
1766 ok(r==S_OK, "IStorage->Revert failed %08x\n", r);
1767
1768 r = IStream_Write(stm, "this works\n", 11, NULL);
1769 ok(r==S_OK, "IStream_Write should succeed %08x\n", r);
1770
1771 IStream_Release(stm);
1772 IStorage_Release(stg);
1773
1774 ret = DeleteFileA(filenameA);
1775 ok(ret, "deleted file\n");
1776 }
1777
1778 static void test_parent_free(void)
1779 {
1780 IStorage *stg = NULL, *stg2 = NULL, *stg3 = NULL;
1781 HRESULT r;
1782 IStream *stm = NULL;
1783 static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
1784 static const WCHAR stgname[] = { 'P','E','R','M','S','T','G',0 };
1785 ULONG ref;
1786 STATSTG statstg;
1787 BOOL ret;
1788
1789 DeleteFileA(filenameA);
1790
1791 /* create the file */
1792 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
1793 STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
1794 ok(r==S_OK, "StgCreateDocfile failed\n");
1795
1796 /* create a new storage */
1797 r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
1798 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
1799
1800 if (r == S_OK)
1801 {
1802 /* now create a stream inside the new storage */
1803 r = IStorage_CreateStream(stg2, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
1804 ok(r==S_OK, "IStorage->CreateStream failed\n");
1805
1806 if (r == S_OK)
1807 {
1808 /* create a storage inside the new storage */
1809 r = IStorage_CreateStorage(stg2, stgname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stg3 );
1810 ok(r==S_OK, "IStorage->CreateStorage failed\n");
1811 }
1812
1813 /* free the parent */
1814 ref = IStorage_Release(stg2);
1815 ok(ref == 0, "IStorage still has %u references\n", ref);
1816
1817 /* child objects are invalid */
1818 if (r == S_OK)
1819 {
1820 r = IStream_Write(stm, "this should fail\n", 17, NULL);
1821 ok(r==STG_E_REVERTED, "IStream->Write should fail, hr=%x\n", r);
1822
1823 IStream_Release(stm);
1824
1825 r = IStorage_Stat(stg3, &statstg, STATFLAG_NONAME);
1826 ok(r==STG_E_REVERTED, "IStorage_Stat should fail %08x\n", r);
1827
1828 r = IStorage_SetStateBits(stg3, 1, 1);
1829 ok(r==STG_E_REVERTED, "IStorage_Stat should fail %08x\n", r);
1830
1831 IStorage_Release(stg3);
1832 }
1833 }
1834
1835 IStorage_Release(stg);
1836
1837 ret = DeleteFileA(filenameA);
1838 ok(ret, "deleted file\n");
1839 }
1840
1841 static void test_nonroot_transacted(void)
1842 {
1843 IStorage *stg = NULL, *stg2 = NULL, *stg3 = NULL;
1844 HRESULT r;
1845 IStream *stm = NULL;
1846 static const WCHAR stgname[] = { 'P','E','R','M','S','T','G',0 };
1847 static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
1848 static const WCHAR stmname2[] = { 'F','O','O',0 };
1849 BOOL ret;
1850
1851 DeleteFileA(filenameA);
1852
1853 /* create a transacted file */
1854 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
1855 STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
1856 ok(r==S_OK, "StgCreateDocfile failed\n");
1857
1858 /* create a transacted substorage */
1859 r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_TRANSACTED, 0, 0, &stg2);
1860 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
1861
1862 if (r == S_OK)
1863 {
1864 /* create and commit stmname */
1865 r = IStorage_CreateStream(stg2, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
1866 ok(r==S_OK, "IStorage->CreateStream failed\n");
1867 if (r == S_OK)
1868 IStream_Release(stm);
1869
1870 IStorage_Commit(stg2, 0);
1871
1872 /* create and revert stmname2 */
1873 r = IStorage_CreateStream(stg2, stmname2, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
1874 ok(r==S_OK, "IStorage->CreateStream failed\n");
1875 if (r == S_OK)
1876 IStream_Release(stm);
1877
1878 IStorage_Revert(stg2);
1879
1880 /* check that Commit and Revert really worked */
1881 r = IStorage_OpenStream(stg2, stmname, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
1882 ok(r==S_OK, "IStorage->OpenStream should succeed %08x\n", r);
1883 if (r == S_OK)
1884 IStream_Release(stm);
1885
1886 r = IStorage_OpenStream(stg2, stmname2, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
1887 ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStream should fail %08x\n", r);
1888 if (r == S_OK)
1889 IStream_Release(stm);
1890
1891 IStorage_Release(stg2);
1892 }
1893
1894 /* create a read-only transacted substorage */
1895 r = IStorage_OpenStorage(stg, stgname, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE | STGM_TRANSACTED, NULL, 0, &stg2);
1896 ok(r==S_OK, "IStorage->OpenStorage failed, hr=%08x\n", r);
1897
1898 if (r == S_OK)
1899 {
1900 /* The storage can be modified. */
1901 r = IStorage_CreateStorage(stg2, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg3);
1902 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
1903 if (r == S_OK)
1904 IStorage_Release(stg3);
1905
1906 /* But changes cannot be committed. */
1907 r = IStorage_Commit(stg2, 0);
1908 ok(r==STG_E_ACCESSDENIED, "IStorage->Commit should fail, hr=%08x\n", r);
1909
1910 IStorage_Release(stg2);
1911 }
1912
1913 IStorage_Release(stg);
1914
1915 /* create a non-transacted file */
1916 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
1917 STGM_READWRITE, 0, &stg);
1918 ok(r==S_OK, "StgCreateDocfile failed\n");
1919
1920 /* create a transacted substorage */
1921 r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_TRANSACTED, 0, 0, &stg2);
1922 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
1923
1924 if (r == S_OK)
1925 {
1926 /* create and commit stmname */
1927 r = IStorage_CreateStream(stg2, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
1928 ok(r==S_OK, "IStorage->CreateStream failed\n");
1929 if (r == S_OK)
1930 IStream_Release(stm);
1931
1932 IStorage_Commit(stg2, 0);
1933
1934 /* create and revert stmname2 */
1935 r = IStorage_CreateStream(stg2, stmname2, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
1936 ok(r==S_OK, "IStorage->CreateStream failed\n");
1937 if (r == S_OK)
1938 IStream_Release(stm);
1939
1940 IStorage_Revert(stg2);
1941
1942 /* check that Commit and Revert really worked */
1943 r = IStorage_OpenStream(stg2, stmname, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
1944 ok(r==S_OK, "IStorage->OpenStream should succeed %08x\n", r);
1945 if (r == S_OK)
1946 IStream_Release(stm);
1947
1948 r = IStorage_OpenStream(stg2, stmname2, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
1949 ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStream should fail %08x\n", r);
1950 if (r == S_OK)
1951 IStream_Release(stm);
1952
1953 IStorage_Release(stg2);
1954 }
1955
1956 IStorage_Release(stg);
1957
1958 ret = DeleteFileA(filenameA);
1959 ok(ret, "deleted file\n");
1960 }
1961
1962 static void test_ReadClassStm(void)
1963 {
1964 CLSID clsid;
1965 HRESULT hr;
1966 IStream *pStream;
1967 static const LARGE_INTEGER llZero;
1968
1969 hr = ReadClassStm(NULL, &clsid);
1970 ok(hr == E_INVALIDARG, "ReadClassStm should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1971
1972 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1973 ok_ole_success(hr, "CreateStreamOnHGlobal");
1974 hr = WriteClassStm(pStream, &test_stg_cls);
1975 ok_ole_success(hr, "WriteClassStm");
1976
1977 hr = ReadClassStm(pStream, NULL);
1978 ok(hr == E_INVALIDARG, "ReadClassStm should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1979
1980 /* test not rewound stream */
1981 hr = ReadClassStm(pStream, &clsid);
1982 ok(hr == STG_E_READFAULT, "ReadClassStm should have returned STG_E_READFAULT instead of 0x%08x\n", hr);
1983 ok(IsEqualCLSID(&clsid, &CLSID_NULL), "clsid should have been zeroed\n");
1984
1985 hr = IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
1986 ok_ole_success(hr, "IStream_Seek");
1987 hr = ReadClassStm(pStream, &clsid);
1988 ok_ole_success(hr, "ReadClassStm");
1989 ok(IsEqualCLSID(&clsid, &test_stg_cls), "clsid should have been set to CLSID_WineTest\n");
1990
1991 IStream_Release(pStream);
1992 }
1993
1994 struct access_res
1995 {
1996 BOOL gothandle;
1997 DWORD lasterr;
1998 BOOL ignore;
1999 };
2000
2001 static const struct access_res create[16] =
2002 {
2003 { TRUE, ERROR_SUCCESS, TRUE },
2004 { TRUE, ERROR_SUCCESS, TRUE },
2005 { TRUE, ERROR_SUCCESS, FALSE },
2006 { TRUE, ERROR_SUCCESS, FALSE },
2007 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2008 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2009 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2010 { TRUE, ERROR_SUCCESS, FALSE },
2011 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2012 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2013 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2014 { TRUE, ERROR_SUCCESS, TRUE },
2015 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2016 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2017 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2018 { TRUE, ERROR_SUCCESS, TRUE }
2019 };
2020
2021 static const struct access_res create_commit[16] =
2022 {
2023 { TRUE, ERROR_SUCCESS, TRUE },
2024 { TRUE, ERROR_SUCCESS, TRUE },
2025 { TRUE, ERROR_SUCCESS, FALSE },
2026 { TRUE, ERROR_SUCCESS, FALSE },
2027 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2028 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2029 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2030 { TRUE, ERROR_SUCCESS, FALSE },
2031 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2032 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2033 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2034 { TRUE, ERROR_SUCCESS, TRUE },
2035 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2036 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2037 { FALSE, ERROR_SHARING_VIOLATION, FALSE },
2038 { TRUE, ERROR_SUCCESS, TRUE }
2039 };
2040
2041 static const struct access_res create_close[16] =
2042 {
2043 { TRUE, ERROR_SUCCESS, FALSE },
2044 { TRUE, ERROR_SUCCESS, FALSE },
2045 { TRUE, ERROR_SUCCESS, FALSE },
2046 { TRUE, ERROR_SUCCESS, FALSE },
2047 { TRUE, ERROR_SUCCESS, FALSE },
2048 { TRUE, ERROR_SUCCESS, FALSE },
2049 { TRUE, ERROR_SUCCESS, FALSE },
2050 { TRUE, ERROR_SUCCESS, FALSE },
2051 { TRUE, ERROR_SUCCESS, FALSE },
2052 { TRUE, ERROR_SUCCESS, FALSE },
2053 { TRUE, ERROR_SUCCESS, FALSE },
2054 { TRUE, ERROR_SUCCESS, FALSE },
2055 { TRUE, ERROR_SUCCESS, FALSE },
2056 { TRUE, ERROR_SUCCESS, FALSE },
2057 { TRUE, ERROR_SUCCESS, FALSE },
2058 { TRUE, ERROR_SUCCESS }
2059 };
2060
2061 static const DWORD access_modes[4] = {
2062 0,
2063 GENERIC_READ,
2064 GENERIC_WRITE,
2065 GENERIC_READ | GENERIC_WRITE
2066 };
2067
2068 static const DWORD share_modes[4] = {
2069 0,
2070 FILE_SHARE_READ,
2071 FILE_SHARE_WRITE,
2072 FILE_SHARE_READ | FILE_SHARE_WRITE
2073 };
2074
2075 static void _test_file_access(LPCSTR file, const struct access_res *ares, DWORD line)
2076 {
2077 int i, j, idx = 0;
2078
2079 for (i = 0; i < sizeof(access_modes)/sizeof(access_modes[0]); i++)
2080 {
2081 for (j = 0; j < sizeof(share_modes)/sizeof(share_modes[0]); j++)
2082 {
2083 DWORD lasterr;
2084 HANDLE hfile;
2085
2086 if (ares[idx].ignore)
2087 continue;
2088
2089 SetLastError(0xdeadbeef);
2090 hfile = CreateFileA(file, access_modes[i], share_modes[j], NULL, OPEN_EXISTING,
2091 FILE_ATTRIBUTE_NORMAL, 0);
2092 lasterr = GetLastError();
2093
2094 ok((hfile != INVALID_HANDLE_VALUE) == ares[idx].gothandle,
2095 "(%d, handle, %d): Expected %d, got %d\n",
2096 line, idx, ares[idx].gothandle,
2097 (hfile != INVALID_HANDLE_VALUE));
2098
2099 ok(lasterr == ares[idx].lasterr ||
2100 broken(lasterr == 0xdeadbeef) /* win9x */,
2101 "(%d, lasterr, %d): Expected %d, got %d\n",
2102 line, idx, ares[idx].lasterr, lasterr);
2103
2104 CloseHandle(hfile);
2105 idx++;
2106 }
2107 }
2108 }
2109
2110 #define test_file_access(file, ares) _test_file_access(file, ares, __LINE__)
2111
2112 static void test_access(void)
2113 {
2114 static const WCHAR fileW[] = {'w','i','n','e','t','e','s','t',0};
2115 static const char fileA[] = "winetest";
2116 IStorage *stg;
2117 HRESULT hr;
2118
2119 /* STGM_TRANSACTED */
2120 hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE |
2121 STGM_SHARE_EXCLUSIVE | STGM_TRANSACTED, 0, &stg);
2122 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2123
2124 test_file_access(fileA, create);
2125
2126 hr = IStorage_Commit(stg, STGC_DEFAULT);
2127 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2128
2129 test_file_access(fileA, create_commit);
2130
2131 IStorage_Release(stg);
2132
2133 test_file_access(fileA, create_close);
2134
2135 DeleteFileA(fileA);
2136
2137 /* STGM_DIRECT */
2138 hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE |
2139 STGM_SHARE_EXCLUSIVE | STGM_DIRECT, 0, &stg);
2140 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2141
2142 test_file_access(fileA, create);
2143
2144 hr = IStorage_Commit(stg, STGC_DEFAULT);
2145 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2146
2147 test_file_access(fileA, create_commit);
2148
2149 IStorage_Release(stg);
2150
2151 test_file_access(fileA, create_close);
2152
2153 DeleteFileA(fileA);
2154
2155 /* STGM_SHARE_DENY_NONE */
2156 hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE |
2157 STGM_SHARE_DENY_NONE | STGM_TRANSACTED, 0, &stg);
2158 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2159
2160 test_file_access(fileA, create);
2161
2162 hr = IStorage_Commit(stg, STGC_DEFAULT);
2163 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2164
2165 test_file_access(fileA, create_commit);
2166
2167 IStorage_Release(stg);
2168
2169 test_file_access(fileA, create_close);
2170
2171 DeleteFileA(fileA);
2172
2173 /* STGM_SHARE_DENY_READ */
2174 hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE |
2175 STGM_SHARE_DENY_READ | STGM_TRANSACTED, 0, &stg);
2176 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2177
2178 test_file_access(fileA, create);
2179
2180 hr = IStorage_Commit(stg, STGC_DEFAULT);
2181 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2182
2183 test_file_access(fileA, create_commit);
2184
2185 IStorage_Release(stg);
2186
2187 test_file_access(fileA, create_close);
2188
2189 DeleteFileA(fileA);
2190
2191 /* STGM_SHARE_DENY_WRITE */
2192 hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE |
2193 STGM_SHARE_DENY_WRITE | STGM_TRANSACTED, 0, &stg);
2194 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2195
2196 test_file_access(fileA, create);
2197
2198 hr = IStorage_Commit(stg, STGC_DEFAULT);
2199 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2200
2201 test_file_access(fileA, create_commit);
2202
2203 IStorage_Release(stg);
2204
2205 test_file_access(fileA, create_close);
2206
2207 DeleteFileA(fileA);
2208
2209 /* STGM_DIRECT_SWMR | STGM_READ | STGM_SHARE_DENY_NONE - reader mode for direct SWMR mode */
2210 hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE | STGM_SHARE_DENY_WRITE | STGM_TRANSACTED, 0, &stg);
2211 ok(hr == S_OK, "got %08x\n", hr);
2212 IStorage_Release(stg);
2213
2214 hr = StgOpenStorage(fileW, NULL, STGM_DIRECT_SWMR | STGM_READ | STGM_SHARE_DENY_NONE, NULL, 0, &stg);
2215 ok(hr == S_OK || broken(hr == STG_E_INVALIDFLAG), "got %08x\n", hr);
2216 if(hr != S_OK)
2217 return;
2218
2219 test_file_access(fileA, create);
2220
2221 IStorage_Release(stg);
2222 test_file_access(fileA, create_close);
2223
2224 DeleteFileA(fileA);
2225 }
2226
2227 static void test_readonly(void)
2228 {
2229 IStorage *stg, *stg2, *stg3;
2230 IStream *stream;
2231 HRESULT hr;
2232 static const WCHAR fileW[] = {'w','i','n','e','t','e','s','t',0};
2233 static const WCHAR storageW[] = {'s','t','o','r','a','g','e',0};
2234 static const WCHAR streamW[] = {'s','t','r','e','a','m',0};
2235
2236 hr = StgCreateDocfile( fileW, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &stg);
2237 ok(hr == S_OK, "should succeed, res=%x\n", hr);
2238 if (SUCCEEDED(hr))
2239 {
2240 hr = IStorage_CreateStorage( stg, storageW, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stg2 );
2241 ok(hr == S_OK, "should succeed, res=%x\n", hr);
2242 if (SUCCEEDED(hr))
2243 {
2244 hr = IStorage_CreateStream( stg2, streamW, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stream );
2245 ok(hr == S_OK, "should succeed, res=%x\n", hr);
2246 if (SUCCEEDED(hr))
2247 IStream_Release(stream);
2248 IStorage_Release(stg2);
2249 }
2250 IStorage_Release(stg);
2251 }
2252
2253 /* re-open read only */
2254 hr = StgOpenStorage( fileW, NULL, STGM_TRANSACTED | STGM_SHARE_DENY_NONE | STGM_READ, NULL, 0, &stg);
2255 ok(hr == S_OK, "should succeed, res=%x\n", hr);
2256 if (SUCCEEDED(hr))
2257 {
2258 hr = IStorage_OpenStorage( stg, storageW, NULL, STGM_SHARE_EXCLUSIVE | STGM_READ, NULL, 0, &stg2 );
2259 ok(hr == S_OK, "should succeed, res=%x\n", hr);
2260 if (SUCCEEDED(hr))
2261 {
2262 /* CreateStream on read-only storage, name exists */
2263 hr = IStorage_CreateStream( stg2, streamW, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READ, 0, 0, &stream );
2264 ok(hr == STG_E_ACCESSDENIED, "should fail, res=%x\n", hr);
2265 if (SUCCEEDED(hr))
2266 IStream_Release(stream);
2267
2268 /* CreateStream on read-only storage, name does not exist */
2269 hr = IStorage_CreateStream( stg2, storageW, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READ, 0, 0, &stream );
2270 ok(hr == STG_E_ACCESSDENIED, "should fail, res=%x\n", hr);
2271 if (SUCCEEDED(hr))
2272 IStream_Release(stream);
2273
2274 /* CreateStorage on read-only storage, name exists */
2275 hr = IStorage_CreateStorage( stg2, streamW, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READ, 0, 0, &stg3 );
2276 ok(hr == STG_E_FILEALREADYEXISTS, "should fail, res=%x\n", hr);
2277 if (SUCCEEDED(hr))
2278 IStorage_Release(stg3);
2279
2280 /* CreateStorage on read-only storage, name does not exist */
2281 hr = IStorage_CreateStorage( stg2, storageW, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READ, 0, 0, &stg3 );
2282 ok(hr == STG_E_ACCESSDENIED, "should fail, res=%x\n", hr);
2283 if (SUCCEEDED(hr))
2284 IStorage_Release(stg3);
2285
2286 /* DestroyElement on read-only storage, name exists */
2287 hr = IStorage_DestroyElement( stg2, streamW );
2288 ok(hr == STG_E_ACCESSDENIED, "should fail, res=%x\n", hr);
2289
2290 /* DestroyElement on read-only storage, name does not exist */
2291 hr = IStorage_DestroyElement( stg2, storageW );
2292 ok(hr == STG_E_ACCESSDENIED, "should fail, res=%x\n", hr);
2293
2294 IStorage_Release(stg2);
2295 }
2296
2297 IStorage_Release(stg);
2298 }
2299
2300 DeleteFileA("winetest");
2301 }
2302
2303 static void test_simple(void)
2304 {
2305 /* Tests for STGM_SIMPLE mode */
2306
2307 IStorage *stg, *stg2;
2308 HRESULT r;
2309 IStream *stm;
2310 static const WCHAR stgname[] = { 'S','t','g',0 };
2311 static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
2312 static const WCHAR stmname2[] = { 'S','m','a','l','l',0 };
2313 LARGE_INTEGER pos;
2314 ULARGE_INTEGER upos;
2315 DWORD count;
2316 STATSTG stat;
2317
2318 DeleteFileA(filenameA);
2319
2320 r = StgCreateDocfile( filename, STGM_SIMPLE | STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &stg);
2321 ok(r == S_OK, "got %08x\n", r);
2322
2323 r = IStorage_CreateStorage(stg, stgname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stg2);
2324 ok(r == STG_E_INVALIDFUNCTION, "got %08x\n", r);
2325 if (SUCCEEDED(r)) IStorage_Release(stg2);
2326
2327 r = IStorage_CreateStream(stg, stmname, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm);
2328 ok(r == STG_E_INVALIDFLAG, "got %08x\n", r);
2329 r = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm);
2330 ok(r == S_OK, "got %08x\n", r);
2331
2332 upos.QuadPart = 6000;
2333 r = IStream_SetSize(stm, upos);
2334 ok(r == S_OK, "got %08x\n", r);
2335
2336 r = IStream_Write(stm, "foo", 3, &count);
2337 ok(r == S_OK, "got %08x\n", r);
2338 ok(count == 3, "got %d\n", count);
2339
2340 pos.QuadPart = 0;
2341 r = IStream_Seek(stm, pos, STREAM_SEEK_CUR, &upos);
2342 ok(r == S_OK, "got %08x\n", r);
2343 ok(upos.QuadPart == 3, "got %d\n", upos.u.LowPart);
2344
2345 r = IStream_Stat(stm, &stat, STATFLAG_NONAME);
2346 ok(r == S_OK ||
2347 broken(r == STG_E_INVALIDFUNCTION), /* NT4 and below */
2348 "got %08x\n", r);
2349 if (r == S_OK)
2350 ok(stat.cbSize.QuadPart == 3, "got %d\n", stat.cbSize.u.LowPart);
2351
2352 pos.QuadPart = 1;
2353 r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &upos);
2354 ok(r == S_OK, "got %08x\n", r);
2355 ok(upos.QuadPart == 1, "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 == 1, "got %d\n", stat.cbSize.u.LowPart);
2363
2364 IStream_Release(stm);
2365
2366 r = IStorage_CreateStream(stg, stmname2, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm);
2367 ok(r == S_OK, "got %08x\n", r);
2368
2369 upos.QuadPart = 100;
2370 r = IStream_SetSize(stm, upos);
2371 ok(r == S_OK, "got %08x\n", r);
2372
2373 r = IStream_Write(stm, "foo", 3, &count);
2374 ok(r == S_OK, "got %08x\n", r);
2375 ok(count == 3, "got %d\n", count);
2376
2377 IStream_Release(stm);
2378
2379 IStorage_Commit(stg, STGC_DEFAULT);
2380 IStorage_Release(stg);
2381
2382 r = StgOpenStorage( filename, NULL, STGM_SIMPLE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &stg);
2383 if (r == STG_E_INVALIDFLAG)
2384 {
2385 win_skip("Flag combination is not supported on NT4 and below\n");
2386 DeleteFileA(filenameA);
2387 return;
2388 }
2389 ok(r == S_OK, "got %08x\n", r);
2390
2391 r = IStorage_OpenStorage(stg, stgname, NULL, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &stg2);
2392 ok(r == STG_E_INVALIDFUNCTION, "got %08x\n", r);
2393 if (SUCCEEDED(r)) IStorage_Release(stg2);
2394
2395 r = IStorage_OpenStream(stg, stmname, NULL, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &stm);
2396 ok(r == S_OK, "got %08x\n", r);
2397
2398 r = IStream_Stat(stm, &stat, STATFLAG_NONAME);
2399 ok(r == S_OK, "got %08x\n", r);
2400 ok(stat.cbSize.QuadPart == 6000, "got %d\n", stat.cbSize.u.LowPart);
2401
2402 IStream_Release(stm);
2403
2404 r = IStorage_OpenStream(stg, stmname2, NULL, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &stm);
2405 ok(r == S_OK, "got %08x\n", r);
2406
2407 r = IStream_Stat(stm, &stat, STATFLAG_NONAME);
2408 ok(r == S_OK, "got %08x\n", r);
2409 ok(stat.cbSize.QuadPart == 4096, "got %d\n", stat.cbSize.u.LowPart);
2410
2411 IStream_Release(stm);
2412
2413
2414 IStorage_Release(stg);
2415
2416 DeleteFileA(filenameA);
2417 }
2418
2419 static void test_fmtusertypestg(void)
2420 {
2421 IStorage *stg;
2422 IEnumSTATSTG *stat;
2423 HRESULT hr;
2424 static const char fileA[] = {'f','m','t','t','e','s','t',0};
2425 static const WCHAR fileW[] = {'f','m','t','t','e','s','t',0};
2426 static WCHAR userTypeW[] = {'S','t','g','U','s','r','T','y','p','e',0};
2427 static const WCHAR strmNameW[] = {1,'C','o','m','p','O','b','j',0};
2428 static const STATSTG statstg_null;
2429
2430 hr = StgCreateDocfile( fileW, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &stg);
2431 ok(hr == S_OK, "should succeed, res=%x\n", hr);
2432
2433 if (SUCCEEDED(hr))
2434 {
2435 /* try to write the stream */
2436 hr = WriteFmtUserTypeStg(stg, 0, userTypeW);
2437 ok(hr == S_OK, "should succeed, res=%x\n", hr);
2438
2439 /* check that the stream was created */
2440 hr = IStorage_EnumElements(stg, 0, NULL, 0, &stat);
2441 ok(hr == S_OK, "should succeed, res=%x\n", hr);
2442 if (SUCCEEDED(hr))
2443 {
2444 BOOL found = FALSE;
2445 STATSTG statstg;
2446 DWORD got;
2447 memset(&statstg, 0xad, sizeof(statstg));
2448 while ((hr = IEnumSTATSTG_Next(stat, 1, &statstg, &got)) == S_OK && got == 1)
2449 {
2450 if (strcmp_ww(statstg.pwcsName, strmNameW) == 0)
2451 found = TRUE;
2452 else
2453 ok(0, "found unexpected stream or storage\n");
2454 CoTaskMemFree(statstg.pwcsName);
2455 }
2456 ok(memcmp(&statstg, &statstg_null, sizeof(statstg)) == 0, "statstg is not zeroed\n");
2457 ok(found == TRUE, "expected storage to contain stream \\0001CompObj\n");
2458 IEnumSTATSTG_Release(stat);
2459 }
2460
2461 /* re-write the stream */
2462 hr = WriteFmtUserTypeStg(stg, 0, userTypeW);
2463 ok(hr == S_OK, "should succeed, res=%x\n", hr);
2464
2465 /* check that the stream is still there */
2466 hr = IStorage_EnumElements(stg, 0, NULL, 0, &stat);
2467 ok(hr == S_OK, "should succeed, res=%x\n", hr);
2468 if (SUCCEEDED(hr))
2469 {
2470 BOOL found = FALSE;
2471 STATSTG statstg;
2472 DWORD got;
2473 memset(&statstg, 0xad, sizeof(statstg));
2474 while ((hr = IEnumSTATSTG_Next(stat, 1, &statstg, &got)) == S_OK && got == 1)
2475 {
2476 if (strcmp_ww(statstg.pwcsName, strmNameW) == 0)
2477 found = TRUE;
2478 else
2479 ok(0, "found unexpected stream or storage\n");
2480 CoTaskMemFree(statstg.pwcsName);
2481 }
2482 ok(memcmp(&statstg, &statstg_null, sizeof(statstg)) == 0, "statstg is not zeroed\n");
2483 ok(found == TRUE, "expected storage to contain stream \\0001CompObj\n");
2484 IEnumSTATSTG_Release(stat);
2485 }
2486
2487 IStorage_Release(stg);
2488 DeleteFileA( fileA );
2489 }
2490 }
2491
2492 static void test_references(void)
2493 {
2494 IStorage *stg,*stg2;
2495 HRESULT hr;
2496 unsigned c1,c2;
2497 static const WCHAR StorName[] = { 'D','a','t','a','S','p','a','c','e','I','n','f','o',0 };
2498
2499 DeleteFileA(filenameA);
2500
2501 hr = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
2502 ok(hr==S_OK, "StgCreateDocfile failed\n");
2503
2504 if (SUCCEEDED(hr))
2505 {
2506 IStorage_Release(stg);
2507
2508 hr = StgOpenStorage( filename, NULL, STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &stg);
2509 ok(hr==S_OK, "StgOpenStorage failed (result=%x)\n",hr);
2510
2511 if (SUCCEEDED(hr))
2512 {
2513 hr = IStorage_CreateStorage(stg,StorName,STGM_READWRITE | STGM_SHARE_EXCLUSIVE,0,0,&stg2);
2514 ok(hr == S_OK, "IStorage_CreateStorage failed (result=%x)\n",hr);
2515
2516 if (SUCCEEDED(hr))
2517 {
2518 c1 = IStorage_AddRef(stg);
2519 ok(c1 == 2, "creating internal storage added references to ancestor\n");
2520 c1 = IStorage_AddRef(stg);
2521 IStorage_Release(stg2);
2522 c2 = IStorage_AddRef(stg) - 1;
2523 ok(c1 == c2, "releasing internal storage removed references to ancestor\n");
2524 }
2525 c1 = IStorage_Release(stg);
2526 while ( c1 ) c1 = IStorage_Release(stg);
2527 }
2528 }
2529
2530 DeleteFileA(filenameA);
2531 }
2532
2533 /* dest
2534 * |-StorageA
2535 * | `StreamA: "StreamA"
2536 * |-StorageB
2537 * | `StreamB: "StreamB"
2538 * `StreamC: "StreamC"
2539 */
2540 static HRESULT create_test_file(IStorage *dest)
2541 {
2542 IStorage *stgA = NULL, *stgB = NULL;
2543 IStream *strmA = NULL, *strmB = NULL, *strmC = NULL;
2544 const ULONG strmA_name_size = lstrlenW(strmA_name) * sizeof(WCHAR);
2545 const ULONG strmB_name_size = lstrlenW(strmB_name) * sizeof(WCHAR);
2546 const ULONG strmC_name_size = lstrlenW(strmC_name) * sizeof(WCHAR);
2547 ULONG bytes;
2548 HRESULT hr;
2549
2550 hr = IStorage_CreateStorage(dest, stgA_name, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stgA);
2551 ok(hr == S_OK, "IStorage_CreateStorage failed: 0x%08x\n", hr);
2552 if(FAILED(hr))
2553 goto cleanup;
2554
2555 hr = IStorage_CreateStream(stgA, strmA_name, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &strmA);
2556 ok(hr == S_OK, "IStorage_CreateStream failed: 0x%08x\n", hr);
2557 if(FAILED(hr))
2558 goto cleanup;
2559
2560 hr = IStream_Write(strmA, strmA_name, strmA_name_size, &bytes);
2561 ok(hr == S_OK && bytes == strmA_name_size, "IStream_Write failed: 0x%08x, %d of %d bytes written\n", hr, bytes, strmA_name_size);
2562
2563 hr = IStorage_CreateStorage(dest, stgB_name, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stgB);
2564 ok(hr == S_OK, "IStorage_CreateStorage failed: 0x%08x\n", hr);
2565 if(FAILED(hr))
2566 goto cleanup;
2567
2568 hr = IStorage_CreateStream(stgB, strmB_name, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &strmB);
2569 ok(hr == S_OK, "IStorage_CreateStream failed: 0x%08x\n", hr);
2570 if(FAILED(hr))
2571 goto cleanup;
2572
2573 hr = IStream_Write(strmB, strmB_name, strmB_name_size, &bytes);
2574 ok(hr == S_OK && bytes == strmB_name_size, "IStream_Write failed: 0x%08x, %d of %d bytes written\n", hr, bytes, strmB_name_size);
2575
2576 hr = IStorage_CreateStream(dest, strmC_name, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &strmC);
2577 ok(hr == S_OK, "IStorage_CreateStream failed: 0x%08x\n", hr);
2578 if(FAILED(hr))
2579 goto cleanup;
2580
2581 hr = IStream_Write(strmC, strmC_name, strmC_name_size, &bytes);
2582 ok(hr == S_OK && bytes == strmC_name_size, "IStream_Write failed: 0x%08x, %d of %d bytes written\n", hr, bytes, strmC_name_size);
2583
2584 cleanup:
2585 if(strmC)
2586 IStream_Release(strmC);
2587 if(strmB)
2588 IStream_Release(strmB);
2589 if(stgB)
2590 IStorage_Release(stgB);
2591 if(strmA)
2592 IStream_Release(strmA);
2593 if(stgA)
2594 IStorage_Release(stgA);
2595
2596 return hr;
2597 }
2598
2599 static void test_copyto(void)
2600 {
2601 IStorage *file1 = NULL, *file2 = NULL, *stg_tmp;
2602 IStream *strm_tmp;
2603 WCHAR buf[64];
2604 HRESULT hr;
2605
2606 /* create & populate file1 */
2607 hr = StgCreateDocfile(file1_name, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &file1);
2608 ok(hr == S_OK, "StgCreateDocfile failed: 0x%08x\n", hr);
2609 if(FAILED(hr))
2610 goto cleanup;
2611
2612 hr = create_test_file(file1);
2613 if(FAILED(hr))
2614 goto cleanup;
2615
2616 /* create file2 */
2617 hr = StgCreateDocfile(file2_name, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &file2);
2618 ok(hr == S_OK, "StgCreateDocfile failed: 0x%08x\n", hr);
2619 if(FAILED(hr))
2620 goto cleanup;
2621
2622 /* copy file1 into file2 */
2623 hr = IStorage_CopyTo(file1, 0, NULL, NULL, NULL);
2624 ok(hr == STG_E_INVALIDPOINTER, "CopyTo should give STG_E_INVALIDPONITER, gave: 0x%08x\n", hr);
2625
2626 hr = IStorage_CopyTo(file1, 0, NULL, NULL, file2);
2627 ok(hr == S_OK, "CopyTo failed: 0x%08x\n", hr);
2628 if(FAILED(hr))
2629 goto cleanup;
2630
2631 /* verify that all of file1 was copied */
2632 hr = IStorage_OpenStorage(file2, stgA_name, NULL,
2633 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg_tmp);
2634 ok(hr == S_OK, "OpenStorage failed: 0x%08x\n", hr);
2635
2636 if(SUCCEEDED(hr)){
2637 hr = IStorage_OpenStream(stg_tmp, strmA_name, NULL,
2638 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
2639 ok(hr == S_OK, "OpenStream failed: 0x%08x\n", hr);
2640
2641 if(SUCCEEDED(hr)){
2642 memset(buf, 0, sizeof(buf));
2643 hr = IStream_Read(strm_tmp, buf, sizeof(buf), NULL);
2644 ok(hr == S_OK, "Read failed: 0x%08x\n", hr);
2645 if(SUCCEEDED(hr))
2646 ok(strcmp_ww(buf, strmA_name) == 0,
2647 "Expected %s to be read, got %s\n", wine_dbgstr_w(strmA_name), wine_dbgstr_w(buf));
2648
2649 IStream_Release(strm_tmp);
2650 }
2651
2652 IStorage_Release(stg_tmp);
2653 }
2654
2655 hr = IStorage_OpenStorage(file2, stgB_name, NULL,
2656 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg_tmp);
2657 ok(hr == S_OK, "OpenStorage failed: 0x%08x\n", hr);
2658
2659 if(SUCCEEDED(hr)){
2660 hr = IStorage_OpenStream(stg_tmp, strmB_name, NULL,
2661 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
2662 ok(hr == S_OK, "OpenStream failed: 0x%08x\n", hr);
2663
2664 if(SUCCEEDED(hr)){
2665 memset(buf, 0, sizeof(buf));
2666 hr = IStream_Read(strm_tmp, buf, sizeof(buf), NULL);
2667 ok(hr == S_OK, "Read failed: 0x%08x\n", hr);
2668 if(SUCCEEDED(hr))
2669 ok(strcmp_ww(buf, strmB_name) == 0,
2670 "Expected %s to be read, got %s\n", wine_dbgstr_w(strmB_name), wine_dbgstr_w(buf));
2671
2672 IStream_Release(strm_tmp);
2673 }
2674
2675 IStorage_Release(stg_tmp);
2676 }
2677
2678 hr = IStorage_OpenStream(file2, strmC_name, NULL,
2679 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
2680 ok(hr == S_OK, "OpenStream failed: 0x%08x\n", hr);
2681
2682 if(SUCCEEDED(hr)){
2683 memset(buf, 0, sizeof(buf));
2684 hr = IStream_Read(strm_tmp, buf, sizeof(buf), NULL);
2685 ok(hr == S_OK, "Read failed: 0x%08x\n", hr);
2686 if(SUCCEEDED(hr))
2687 ok(strcmp_ww(buf, strmC_name) == 0,
2688 "Expected %s to be read, got %s\n", wine_dbgstr_w(strmC_name), wine_dbgstr_w(buf));
2689
2690 IStream_Release(strm_tmp);
2691 }
2692
2693 cleanup:
2694 if(file1)
2695 IStorage_Release(file1);
2696 if(file2)
2697 IStorage_Release(file2);
2698
2699 DeleteFileA(file1_nameA);
2700 DeleteFileA(file2_nameA);
2701 }
2702
2703 static void test_copyto_snbexclusions(void)
2704 {
2705 static const WCHAR *snb_exclude[] = {stgA_name, strmB_name, strmC_name, 0};
2706
2707 IStorage *file1 = NULL, *file2 = NULL, *stg_tmp;
2708 IStream *strm_tmp;
2709 WCHAR buf[64];
2710 HRESULT hr;
2711
2712 /* create & populate file1 */
2713 hr = StgCreateDocfile(file1_name, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &file1);
2714 ok(hr == S_OK, "StgCreateDocfile failed: 0x%08x\n", hr);
2715 if(FAILED(hr))
2716 goto cleanup;
2717
2718 hr = create_test_file(file1);
2719 if(FAILED(hr))
2720 goto cleanup;
2721
2722 /* create file2 */
2723 hr = StgCreateDocfile(file2_name, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &file2);
2724 ok(hr == S_OK, "StgCreateDocfile failed: 0x%08x\n", hr);
2725 if(FAILED(hr))
2726 goto cleanup;
2727
2728 /* copy file1 to file2 with name exclusions */
2729 hr = IStorage_CopyTo(file1, 0, NULL, (SNB)snb_exclude, file2);
2730 ok(hr == S_OK, "CopyTo failed: 0x%08x\n", hr);
2731 if(FAILED(hr))
2732 goto cleanup;
2733
2734 /* verify that file1 copied over, respecting exclusions */
2735 hr = IStorage_OpenStorage(file2, stgA_name, NULL,
2736 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg_tmp);
2737 ok(hr == STG_E_FILENOTFOUND, "OpenStorage should give STG_E_FILENOTFOUND, gave: 0x%08x\n", hr);
2738 if(SUCCEEDED(hr))
2739 IStorage_Release(stg_tmp);
2740
2741 hr = IStorage_OpenStream(file2, strmA_name, NULL,
2742 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
2743 ok(hr == STG_E_FILENOTFOUND, "OpenStream should give STG_E_FILENOTFOUND, gave: 0x%08x\n", hr);
2744 if(SUCCEEDED(hr))
2745 IStream_Release(strm_tmp);
2746
2747 hr = IStorage_OpenStorage(file2, stgB_name, NULL,
2748 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg_tmp);
2749 ok(hr == S_OK, "OpenStorage failed: 0x%08x\n", hr);
2750
2751 if(SUCCEEDED(hr)){
2752 hr = IStorage_OpenStream(stg_tmp, strmB_name, NULL,
2753 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
2754 ok(hr == S_OK, "OpenStream failed: 0x%08x\n", hr);
2755
2756 if(SUCCEEDED(hr)){
2757 memset(buf, 0, sizeof(buf));
2758 hr = IStream_Read(strm_tmp, buf, sizeof(buf), NULL);
2759 ok(hr == S_OK, "Read failed: 0x%08x\n", hr);
2760 if(SUCCEEDED(hr))
2761 ok(strcmp_ww(buf, strmB_name) == 0,
2762 "Expected %s to be read, got %s\n", wine_dbgstr_w(strmB_name), wine_dbgstr_w(buf));
2763
2764 IStream_Release(strm_tmp);
2765 }
2766
2767 IStorage_Release(stg_tmp);
2768 }
2769
2770 hr = IStorage_OpenStream(file2, strmC_name, NULL,
2771 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
2772 ok(hr == STG_E_FILENOTFOUND, "OpenStream should give STG_E_FILENOTFOUND, gave: 0x%08x\n", hr);
2773 if(SUCCEEDED(hr))
2774 IStream_Release(strm_tmp);
2775
2776 cleanup:
2777 if(file1)
2778 IStorage_Release(file1);
2779 if(file2)
2780 IStorage_Release(file2);
2781
2782 DeleteFileA(file1_nameA);
2783 DeleteFileA(file2_nameA);
2784 }
2785
2786 static void test_copyto_iidexclusions_storage(void)
2787 {
2788 IStorage *file1 = NULL, *file2 = NULL, *stg_tmp;
2789 IStream *strm_tmp;
2790 WCHAR buf[64];
2791 HRESULT hr;
2792
2793 /* create & populate file1 */
2794 hr = StgCreateDocfile(file1_name, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &file1);
2795 ok(hr == S_OK, "StgCreateDocfile failed: 0x%08x\n", hr);
2796 if(FAILED(hr))
2797 goto cleanup;
2798
2799 hr = create_test_file(file1);
2800 if(FAILED(hr))
2801 goto cleanup;
2802
2803 /* create file2 */
2804 hr = StgCreateDocfile(file2_name, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &file2);
2805 ok(hr == S_OK, "StgCreateDocfile failed: 0x%08x\n", hr);
2806 if(FAILED(hr))
2807 goto cleanup;
2808
2809 /* copy file1 to file2 with iid exclusions */
2810 hr = IStorage_CopyTo(file1, 1, &IID_IStorage, NULL, file2);
2811 ok(hr == S_OK, "CopyTo failed: 0x%08x\n", hr);
2812 if(FAILED(hr))
2813 goto cleanup;
2814
2815 /* verify that file1 copied over, respecting exclusions */
2816 hr = IStorage_OpenStorage(file2, stgA_name, NULL,
2817 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg_tmp);
2818 ok(hr == STG_E_FILENOTFOUND, "OpenStorage should give STG_E_FILENOTFOUND, gave: 0x%08x\n", hr);
2819 if(SUCCEEDED(hr))
2820 IStorage_Release(stg_tmp);
2821
2822 hr = IStorage_OpenStream(file2, strmA_name, NULL,
2823 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
2824 ok(hr == STG_E_FILENOTFOUND, "OpenStream should give STG_E_FILENOTFOUND, gave: 0x%08x\n", hr);
2825 if(SUCCEEDED(hr))
2826 IStream_Release(strm_tmp);
2827
2828 hr = IStorage_OpenStorage(file2, stgB_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, strmB_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_OpenStream(file2, strmC_name, NULL,
2841 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
2842 ok(hr == S_OK, "OpenStream failed: 0x%08x\n", hr);
2843
2844 if(SUCCEEDED(hr)){
2845 memset(buf, 0, sizeof(buf));
2846 hr = IStream_Read(strm_tmp, buf, sizeof(buf), NULL);
2847 ok(hr == S_OK, "Read failed: 0x%08x\n", hr);
2848 if(SUCCEEDED(hr))
2849 ok(strcmp_ww(buf, strmC_name) == 0,
2850 "Expected %s to be read, got %s\n", wine_dbgstr_w(strmC_name), wine_dbgstr_w(buf));
2851
2852 IStream_Release(strm_tmp);
2853 }
2854
2855 cleanup:
2856 if(file1)
2857 IStorage_Release(file1);
2858 if(file2)
2859 IStorage_Release(file2);
2860
2861 DeleteFileA(file1_nameA);
2862 DeleteFileA(file2_nameA);
2863 }
2864
2865 static void test_copyto_iidexclusions_stream(void)
2866 {
2867 IStorage *file1 = NULL, *file2 = NULL, *stg_tmp;
2868 IStream *strm_tmp;
2869 HRESULT hr;
2870
2871 /* create & populate file1 */
2872 hr = StgCreateDocfile(file1_name, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &file1);
2873 ok(hr == S_OK, "StgCreateDocfile failed: 0x%08x\n", hr);
2874 if(FAILED(hr))
2875 goto cleanup;
2876
2877 hr = create_test_file(file1);
2878 if(FAILED(hr))
2879 goto cleanup;
2880
2881 /* create file2 */
2882 hr = StgCreateDocfile(file2_name, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &file2);
2883 ok(hr == S_OK, "StgCreateDocfile failed: 0x%08x\n", hr);
2884 if(FAILED(hr))
2885 goto cleanup;
2886
2887 /* copy file1 to file2 with iid exclusions */
2888 hr = IStorage_CopyTo(file1, 1, &IID_IStream, NULL, file2);
2889 ok(hr == S_OK, "CopyTo failed: 0x%08x\n", hr);
2890 if(FAILED(hr))
2891 goto cleanup;
2892
2893 /* verify that file1 copied over, respecting exclusions */
2894 hr = IStorage_OpenStorage(file2, stgA_name, NULL,
2895 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg_tmp);
2896 ok(hr == S_OK, "OpenStorage failed: 0x%08x\n", hr);
2897
2898 if(SUCCEEDED(hr)){
2899 hr = IStorage_OpenStream(stg_tmp, strmA_name, NULL,
2900 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
2901 ok(hr == STG_E_FILENOTFOUND, "OpenStream should give STG_E_FILENOTFOUND, gave: 0x%08x\n", hr);
2902 if(SUCCEEDED(hr))
2903 IStream_Release(strm_tmp);
2904
2905 IStorage_Release(stg_tmp);
2906 }
2907
2908 hr = IStorage_OpenStorage(file2, stgB_name, NULL,
2909 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg_tmp);
2910 ok(hr == S_OK, "OpenStorage failed: 0x%08x\n", hr);
2911
2912 if(SUCCEEDED(hr)){
2913 hr = IStorage_OpenStream(stg_tmp, strmB_name, NULL,
2914 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
2915 ok(hr == STG_E_FILENOTFOUND, "OpenStream should give STG_E_FILENOTFOUND, gave: 0x%08x\n", hr);
2916 if(SUCCEEDED(hr))
2917 IStream_Release(strm_tmp);
2918
2919 IStorage_Release(stg_tmp);
2920 }
2921
2922 hr = IStorage_OpenStream(file2, strmC_name, NULL,
2923 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
2924 ok(hr == STG_E_FILENOTFOUND, "OpenStream should give STG_E_FILENOTFOUND, gave: 0x%08x\n", hr);
2925 if(SUCCEEDED(hr))
2926 IStream_Release(strm_tmp);
2927
2928 cleanup:
2929 if(file1)
2930 IStorage_Release(file1);
2931 if(file2)
2932 IStorage_Release(file2);
2933
2934 DeleteFileA(file1_nameA);
2935 DeleteFileA(file2_nameA);
2936 }
2937
2938 static void test_rename(void)
2939 {
2940 IStorage *stg, *stg2;
2941 IStream *stm;
2942 HRESULT r;
2943 static const WCHAR stgname[] = { 'P','E','R','M','S','T','G',0 };
2944 static const WCHAR stgname2[] = { 'S','T','G',0 };
2945 static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
2946 static const WCHAR stmname2[] = { 'E','N','T','S',0 };
2947 BOOL ret;
2948
2949 DeleteFileA(filenameA);
2950
2951 /* create the file */
2952 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
2953 STGM_READWRITE, 0, &stg);
2954 ok(r==S_OK, "StgCreateDocfile failed\n");
2955
2956 /* create a substorage */
2957 r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
2958 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
2959
2960 /* create a stream in the substorage */
2961 r = IStorage_CreateStream(stg2, stmname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm);
2962 ok(r==S_OK, "IStorage->CreateStream failed, hr=%08x\n", r);
2963 IStream_Release(stm);
2964
2965 /* rename the stream */
2966 r = IStorage_RenameElement(stg2, stmname, stmname2);
2967 ok(r==S_OK, "IStorage->RenameElement failed, hr=%08x\n", r);
2968
2969 /* cannot open stream with old name */
2970 r = IStorage_OpenStream(stg2, stmname, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &stm);
2971 ok(r==STG_E_FILENOTFOUND, "IStorage_OpenStream should fail, hr=%08x\n", r);
2972 if (SUCCEEDED(r)) IStream_Release(stm);
2973
2974 /* can open stream with new name */
2975 r = IStorage_OpenStream(stg2, stmname2, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &stm);
2976 ok(r==S_OK, "IStorage_OpenStream failed, hr=%08x\n", r);
2977 if (SUCCEEDED(r)) IStream_Release(stm);
2978
2979 IStorage_Release(stg2);
2980
2981 /* rename the storage */
2982 IStorage_RenameElement(stg, stgname, stgname2);
2983
2984 /* cannot open storage with old name */
2985 r = IStorage_OpenStorage(stg, stgname, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg2);
2986 ok(r==STG_E_FILENOTFOUND, "IStorage_OpenStream should fail, hr=%08x\n", r);
2987 if (SUCCEEDED(r)) IStorage_Release(stg2);
2988
2989 /* can open storage with new name */
2990 r = IStorage_OpenStorage(stg, stgname2, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg2);
2991 ok(r==S_OK, "IStorage_OpenStream should fail, hr=%08x\n", r);
2992 if (SUCCEEDED(r))
2993 {
2994 /* opened storage still has the stream */
2995 r = IStorage_OpenStream(stg2, stmname2, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &stm);
2996 ok(r==S_OK, "IStorage_OpenStream failed, hr=%08x\n", r);
2997 if (SUCCEEDED(r)) IStream_Release(stm);
2998
2999 IStorage_Release(stg2);
3000 }
3001
3002 IStorage_Release(stg);
3003
3004 ret = DeleteFileA(filenameA);
3005 ok(ret, "deleted file\n");
3006 }
3007
3008 static void test_toplevel_stat(void)
3009 {
3010 IStorage *stg = NULL;
3011 HRESULT r;
3012 STATSTG stat;
3013 char prev_dir[MAX_PATH];
3014 char temp[MAX_PATH];
3015 char full_path[MAX_PATH];
3016 LPSTR rel_pathA;
3017 WCHAR rel_path[MAX_PATH];
3018
3019 DeleteFileA(filenameA);
3020
3021 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
3022 STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
3023 ok(r==S_OK, "StgCreateDocfile failed\n");
3024
3025 r = IStorage_Stat( stg, &stat, STATFLAG_DEFAULT );
3026 ok(r==S_OK, "Storage_Stat failed with error 0x%08x\n", r);
3027 ok(!strcmp_ww(stat.pwcsName, filename), "expected %s, got %s\n",
3028 wine_dbgstr_w(filename), wine_dbgstr_w(stat.pwcsName));
3029 CoTaskMemFree(stat.pwcsName);
3030
3031 IStorage_Release( stg );
3032
3033 r = StgOpenStorage( filename, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg);
3034 ok(r==S_OK, "StgOpenStorage failed with error 0x%08x\n", r);
3035
3036 r = IStorage_Stat( stg, &stat, STATFLAG_DEFAULT );
3037 ok(r==S_OK, "Storage_Stat failed with error 0x%08x\n", r);
3038 ok(!strcmp_ww(stat.pwcsName, filename), "expected %s, got %s\n",
3039 wine_dbgstr_w(filename), wine_dbgstr_w(stat.pwcsName));
3040 CoTaskMemFree(stat.pwcsName);
3041
3042 IStorage_Release( stg );
3043
3044 DeleteFileA(filenameA);
3045
3046 /* Stat always returns the full path, even for files opened with a relative path. */
3047 GetCurrentDirectoryA(MAX_PATH, prev_dir);
3048
3049 GetTempPathA(MAX_PATH, temp);
3050
3051 SetCurrentDirectoryA(temp);
3052
3053 GetFullPathNameA(filenameA, MAX_PATH, full_path, &rel_pathA);
3054 MultiByteToWideChar(CP_ACP, 0, rel_pathA, -1, rel_path, MAX_PATH);
3055
3056 r = StgCreateDocfile( rel_path, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
3057 STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
3058 ok(r==S_OK, "StgCreateDocfile failed\n");
3059
3060 r = IStorage_Stat( stg, &stat, STATFLAG_DEFAULT );
3061 ok(r==S_OK, "Storage_Stat failed with error 0x%08x\n", r);
3062 ok(!strcmp_ww(stat.pwcsName, filename), "expected %s, got %s\n",
3063 wine_dbgstr_w(filename), wine_dbgstr_w(stat.pwcsName));
3064 CoTaskMemFree(stat.pwcsName);
3065
3066 IStorage_Release( stg );
3067
3068 r = StgOpenStorage( rel_path, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg);
3069 ok(r==S_OK, "StgOpenStorage failed with error 0x%08x\n", r);
3070
3071 r = IStorage_Stat( stg, &stat, STATFLAG_DEFAULT );
3072 ok(r==S_OK, "Storage_Stat failed with error 0x%08x\n", r);
3073 ok(!strcmp_ww(stat.pwcsName, filename), "expected %s, got %s\n",
3074 wine_dbgstr_w(filename), wine_dbgstr_w(stat.pwcsName));
3075 CoTaskMemFree(stat.pwcsName);
3076
3077 IStorage_Release( stg );
3078
3079 SetCurrentDirectoryA(prev_dir);
3080
3081 DeleteFileA(filenameA);
3082 }
3083
3084 static void test_substorage_enum(void)
3085 {
3086 IStorage *stg, *stg2;
3087 IEnumSTATSTG *ee;
3088 HRESULT r;
3089 ULONG ref;
3090 static const WCHAR stgname[] = { 'P','E','R','M','S','T','G',0 };
3091 BOOL ret;
3092
3093 DeleteFileA(filenameA);
3094
3095 /* create the file */
3096 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
3097 STGM_READWRITE, 0, &stg);
3098 ok(r==S_OK, "StgCreateDocfile failed\n");
3099
3100 /* create a substorage */
3101 r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
3102 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
3103
3104 /* create an enumelements */
3105 r = IStorage_EnumElements(stg2, 0, NULL, 0, &ee);
3106 ok(r==S_OK, "IStorage->EnumElements failed, hr=%08x\n", r);
3107
3108 /* release the substorage */
3109 ref = IStorage_Release(stg2);
3110 todo_wine ok(ref==0, "storage not released\n");
3111
3112 /* reopening fails, because the substorage is really still open */
3113 r = IStorage_OpenStorage(stg, stgname, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
3114 ok(r==STG_E_ACCESSDENIED, "IStorage->OpenStorage failed, hr=%08x\n", r);
3115
3116 /* destroying the storage invalidates the enumerator */
3117 r = IStorage_DestroyElement(stg, stgname);
3118 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
3119
3120 r = IEnumSTATSTG_Reset(ee);
3121 ok(r==STG_E_REVERTED, "IEnumSTATSTG->Reset failed, hr=%08x\n", r);
3122
3123 IEnumSTATSTG_Release(ee);
3124
3125 IStorage_Release(stg);
3126
3127 ret = DeleteFileA(filenameA);
3128 ok(ret, "deleted file\n");
3129 }
3130
3131 static void test_copyto_locking(void)
3132 {
3133 IStorage *stg, *stg2, *stg3, *stg4;
3134 IStream *stm;
3135 HRESULT r;
3136 static const WCHAR stgname[] = { 'S','T','G','1',0 };
3137 static const WCHAR stgname2[] = { 'S','T','G','2',0 };
3138 static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
3139 BOOL ret;
3140
3141 DeleteFileA(filenameA);
3142
3143 /* create the file */
3144 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
3145 STGM_READWRITE, 0, &stg);
3146 ok(r==S_OK, "StgCreateDocfile failed\n");
3147
3148 /* create a substorage */
3149 r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
3150 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
3151
3152 /* create another substorage */
3153 r = IStorage_CreateStorage(stg, stgname2, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg3);
3154 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
3155
3156 /* add a stream, and leave it open */
3157 r = IStorage_CreateStream(stg2, stmname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm);
3158 ok(r==S_OK, "IStorage->CreateStream failed, hr=%08x\n", r);
3159
3160 /* Try to copy the storage while the stream is open */
3161 r = IStorage_CopyTo(stg2, 0, NULL, NULL, stg3);
3162 ok(r==S_OK, "IStorage->CopyTo failed, hr=%08x\n", r);
3163
3164 IStream_Release(stm);
3165
3166 /* create a substorage */
3167 r = IStorage_CreateStorage(stg2, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg4);
3168 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
3169
3170 /* Try to copy the storage while the substorage is open */
3171 r = IStorage_CopyTo(stg2, 0, NULL, NULL, stg3);
3172 ok(r==S_OK, "IStorage->CopyTo failed, hr=%08x\n", r);
3173
3174 IStorage_Release(stg4);
3175 IStorage_Release(stg3);
3176 IStorage_Release(stg2);
3177 IStorage_Release(stg);
3178
3179 ret = DeleteFileA(filenameA);
3180 ok(ret, "deleted file\n");
3181 }
3182
3183 static void test_copyto_recursive(void)
3184 {
3185 IStorage *stg, *stg2, *stg3, *stg4;
3186 HRESULT r;
3187 static const WCHAR stgname[] = { 'S','T','G','1',0 };
3188 static const WCHAR stgname2[] = { 'S','T','G','2',0 };
3189 BOOL ret;
3190
3191 DeleteFileA(filenameA);
3192
3193 /* create the file */
3194 r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
3195 STGM_READWRITE, 0, &stg);
3196 ok(r==S_OK, "StgCreateDocfile failed\n");
3197
3198 /* create a substorage */
3199 r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
3200 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
3201
3202 /* copy the parent to the child */
3203 r = IStorage_CopyTo(stg, 0, NULL, NULL, stg2);
3204 ok(r==STG_E_ACCESSDENIED, "IStorage->CopyTo failed, hr=%08x\n", r);
3205
3206 /* create a transacted substorage */
3207 r = IStorage_CreateStorage(stg, stgname2, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_TRANSACTED, 0, 0, &stg3);
3208 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
3209
3210 /* copy the parent to the transacted child */
3211 r = IStorage_CopyTo(stg, 0, NULL, NULL, stg2);
3212 ok(r==STG_E_ACCESSDENIED, "IStorage->CopyTo failed, hr=%08x\n", r);
3213
3214 /* create a transacted subsubstorage */
3215 r = IStorage_CreateStorage(stg3, stgname2, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_TRANSACTED, 0, 0, &stg4);
3216 ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
3217
3218 /* copy the parent to the transacted child of the transacted child */
3219 r = IStorage_CopyTo(stg, 0, NULL, NULL, stg4);
3220 ok(r==STG_E_ACCESSDENIED, "IStorage->CopyTo failed, hr=%08x\n", r);
3221
3222 /* copy the parent but exclude storage objects */
3223 r = IStorage_CopyTo(stg, 1, &IID_IStorage, NULL, stg4);
3224 ok(r==S_OK, "IStorage->CopyTo failed, hr=%08x\n", r);
3225
3226 IStorage_Release(stg4);
3227 IStorage_Release(stg3);
3228 IStorage_Release(stg2);
3229 IStorage_Release(stg);
3230
3231 ret = DeleteFileA(filenameA);
3232 ok(ret, "deleted file\n");
3233 }
3234
3235 static void test_hglobal_storage_creation(void)
3236 {
3237 ILockBytes *ilb = NULL;
3238 IStorage *stg = NULL;
3239 HRESULT r;
3240 STATSTG stat;
3241 char junk[512];
3242 ULARGE_INTEGER offset;
3243
3244 r = CreateILockBytesOnHGlobal(NULL, TRUE, &ilb);
3245 ok(r == S_OK, "CreateILockBytesOnHGlobal failed, hr=%x\n", r);
3246
3247 offset.QuadPart = 0;
3248 memset(junk, 0xaa, 512);
3249 r = ILockBytes_WriteAt(ilb, offset, junk, 512, NULL);
3250 ok(r == S_OK, "ILockBytes_WriteAt failed, hr=%x\n", r);
3251
3252 offset.QuadPart = 2000;
3253 r = ILockBytes_WriteAt(ilb, offset, junk, 512, NULL);
3254 ok(r == S_OK, "ILockBytes_WriteAt failed, hr=%x\n", r);
3255
3256 r = StgCreateDocfileOnILockBytes(ilb, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stg);
3257 ok(r == S_OK, "StgCreateDocfileOnILockBytes failed, hr=%x\n", r);
3258
3259 IStorage_Release(stg);
3260
3261 r = StgOpenStorageOnILockBytes(ilb, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE,
3262 NULL, 0, &stg);
3263 ok(r == S_OK, "StgOpenStorageOnILockBytes failed, hr=%x\n", r);
3264
3265 if (SUCCEEDED(r))
3266 {
3267 r = IStorage_Stat(stg, &stat, STATFLAG_NONAME);
3268 ok(r == S_OK, "StgOpenStorageOnILockBytes failed, hr=%x\n", r);
3269 ok(IsEqualCLSID(&stat.clsid, &GUID_NULL), "unexpected CLSID value\n");
3270
3271 IStorage_Release(stg);
3272 }
3273
3274 r = ILockBytes_Stat(ilb, &stat, STATFLAG_NONAME);
3275 ok(r == S_OK, "ILockBytes_Stat failed, hr=%x\n", r);
3276 ok(stat.cbSize.u.LowPart < 2512, "expected truncated size, got %d\n", stat.cbSize.u.LowPart);
3277
3278 ILockBytes_Release(ilb);
3279 }
3280
3281 static void test_convert(void)
3282 {
3283 static const WCHAR filename[] = {'s','t','o','r','a','g','e','.','s','t','g',0};
3284 IStorage *stg;
3285 HRESULT hr;
3286
3287 hr = GetConvertStg(NULL);
3288 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3289
3290 hr = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &stg);
3291 ok(hr == S_OK, "StgCreateDocfile failed\n");
3292 hr = GetConvertStg(stg);
3293 ok(hr == STG_E_FILENOTFOUND, "got 0x%08x\n", hr);
3294 hr = SetConvertStg(stg, TRUE);
3295 ok(hr == S_OK, "got 0x%08x\n", hr);
3296 hr = SetConvertStg(stg, TRUE);
3297 ok(hr == S_OK, "got 0x%08x\n", hr);
3298 hr = GetConvertStg(stg);
3299 ok(hr == S_OK, "got 0x%08x\n", hr);
3300 hr = SetConvertStg(stg, FALSE);
3301 ok(hr == S_OK, "got 0x%08x\n", hr);
3302 hr = GetConvertStg(stg);
3303 ok(hr == S_FALSE, "got 0x%08x\n", hr);
3304
3305 IStorage_Release(stg);
3306
3307 DeleteFileW(filename);
3308 }
3309
3310 static void test_direct_swmr(void)
3311 {
3312 static const WCHAR fileW[] = {'w','i','n','e','t','e','s','t',0};
3313 IDirectWriterLock *dwlock;
3314 ULONG ref, ref2;
3315 IStorage *stg;
3316 HRESULT hr;
3317
3318 /* it's possible to create in writer mode */
3319 hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE | STGM_SHARE_DENY_WRITE | STGM_DIRECT_SWMR, 0, &stg);
3320 todo_wine
3321 ok(hr == S_OK, "got %08x\n", hr);
3322 if (hr == S_OK) {
3323 IStorage_Release(stg);
3324 DeleteFileW(fileW);
3325 }
3326
3327 hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE | STGM_SHARE_DENY_WRITE | STGM_TRANSACTED, 0, &stg);
3328 ok(hr == S_OK, "got %08x\n", hr);
3329 IStorage_Release(stg);
3330
3331 /* reader mode */
3332 hr = StgOpenStorage(fileW, NULL, STGM_DIRECT_SWMR | STGM_READ | STGM_SHARE_DENY_NONE, NULL, 0, &stg);
3333 ok(hr == S_OK || broken(hr == STG_E_INVALIDFLAG), "got %08x\n", hr);
3334 if(hr == S_OK)
3335 {
3336 hr = IStorage_QueryInterface(stg, &IID_IDirectWriterLock, (void**)&dwlock);
3337 ok(hr == E_NOINTERFACE, "got %08x\n", hr);
3338 IStorage_Release(stg);
3339 }
3340
3341 /* writer mode */
3342 hr = StgOpenStorage(fileW, NULL, STGM_DIRECT_SWMR | STGM_READWRITE | STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
3343 ok(hr == S_OK, "got %08x\n", hr);
3344 if(hr == S_OK)
3345 {
3346 ref = IStorage_AddRef(stg);
3347 IStorage_Release(stg);
3348
3349 hr = IStorage_QueryInterface(stg, &IID_IDirectWriterLock, (void**)&dwlock);
3350 ok(hr == S_OK, "got %08x\n", hr);
3351
3352 ref2 = IStorage_AddRef(stg);
3353 IStorage_Release(stg);
3354 ok(ref2 == ref + 1, "got %u\n", ref2);
3355
3356 IDirectWriterLock_Release(dwlock);
3357 IStorage_Release(stg);
3358 }
3359
3360 DeleteFileW(fileW);
3361 }
3362
3363 struct lock_test
3364 {
3365 DWORD stg_mode;
3366 BOOL create;
3367 DWORD access;
3368 DWORD sharing;
3369 const int *locked_bytes;
3370 const int *fail_ranges;
3371 BOOL todo;
3372 };
3373
3374 static const int priority_locked_bytes[] = { 0x158, 0x181, 0x193, -1 };
3375 static const int rwex_locked_bytes[] = { 0x193, 0x1a7, 0x1bb, 0x1cf, -1 };
3376 static const int rw_locked_bytes[] = { 0x193, 0x1a7, -1 };
3377 static const int nosn_locked_bytes[] = { 0x16c, 0x193, 0x1a7, 0x1cf, -1 };
3378 static const int rwdw_locked_bytes[] = { 0x193, 0x1a7, 0x1cf, -1 };
3379 static const int wodw_locked_bytes[] = { 0x1a7, 0x1cf, -1 };
3380 static const int tr_locked_bytes[] = { 0x193, -1 };
3381 static const int no_locked_bytes[] = { -1 };
3382 static const int roex_locked_bytes[] = { 0x193, 0x1bb, 0x1cf, -1 };
3383
3384 static const int rwex_fail_ranges[] = { 0x193,0x1e3, -1 };
3385 static const int rw_fail_ranges[] = { 0x1bb,0x1e3, -1 };
3386 static const int rwdw_fail_ranges[] = { 0x1a7,0x1e3, -1 };
3387 static const int dw_fail_ranges[] = { 0x1a7,0x1cf, -1 };
3388 static const int tr_fail_ranges[] = { 0x1bb,0x1cf, -1 };
3389 static const int pr_fail_ranges[] = { 0x180,0x181, 0x1bb,0x1cf, -1 };
3390 static const int roex_fail_ranges[] = { 0x0,-1 };
3391
3392 static const struct lock_test lock_tests[] = {
3393 { STGM_PRIORITY, FALSE, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, priority_locked_bytes, pr_fail_ranges, FALSE },
3394 { STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, TRUE, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, rwex_locked_bytes, 0, FALSE },
3395 { STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE|STGM_TRANSACTED, TRUE, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, rwex_locked_bytes, 0, FALSE },
3396 { STGM_CREATE|STGM_READWRITE|STGM_TRANSACTED, TRUE, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, rw_locked_bytes, 0, FALSE },
3397 { STGM_CREATE|STGM_READWRITE|STGM_SHARE_DENY_WRITE|STGM_TRANSACTED, TRUE, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, rwdw_locked_bytes, 0, FALSE },
3398 { STGM_CREATE|STGM_WRITE|STGM_SHARE_DENY_WRITE|STGM_TRANSACTED, TRUE, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, wodw_locked_bytes, 0, FALSE },
3399 { STGM_SHARE_EXCLUSIVE|STGM_READWRITE, FALSE, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, rwex_locked_bytes, rwex_fail_ranges, FALSE },
3400 { STGM_SHARE_EXCLUSIVE|STGM_READWRITE|STGM_TRANSACTED, FALSE, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, rwex_locked_bytes, rwex_fail_ranges, FALSE },
3401 { STGM_READWRITE|STGM_TRANSACTED, FALSE, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, rw_locked_bytes, rw_fail_ranges, FALSE },
3402 { STGM_READWRITE|STGM_TRANSACTED|STGM_NOSNAPSHOT, FALSE, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, nosn_locked_bytes, rwdw_fail_ranges, FALSE },
3403 { STGM_READWRITE|STGM_TRANSACTED|STGM_SHARE_DENY_WRITE, FALSE, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, rwdw_locked_bytes, rwdw_fail_ranges, FALSE },
3404 { STGM_READ|STGM_SHARE_DENY_WRITE, FALSE, GENERIC_READ, FILE_SHARE_READ, no_locked_bytes, dw_fail_ranges, TRUE },
3405 { STGM_READ|STGM_TRANSACTED, FALSE, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, tr_locked_bytes, tr_fail_ranges, FALSE },
3406 { STGM_READ|STGM_SHARE_EXCLUSIVE, FALSE, GENERIC_READ, FILE_SHARE_READ, roex_locked_bytes, roex_fail_ranges, FALSE },
3407 { STGM_READ|STGM_SHARE_EXCLUSIVE|STGM_TRANSACTED, FALSE, GENERIC_READ, FILE_SHARE_READ, roex_locked_bytes, roex_fail_ranges, FALSE },
3408 };
3409
3410 static BOOL can_open(LPCWSTR filename, DWORD access, DWORD sharing)
3411 {
3412 HANDLE hfile;
3413
3414 hfile = CreateFileW(filename, access, sharing, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3415
3416 if (hfile == INVALID_HANDLE_VALUE)
3417 return FALSE;
3418
3419 CloseHandle(hfile);
3420 return TRUE;
3421 }
3422
3423 static void check_sharing(LPCWSTR filename, const struct lock_test *current,
3424 DWORD access, DWORD sharing, const char *desc, DWORD *open_mode, BOOL *any_failure)
3425 {
3426 if (can_open(filename, access, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE))
3427 {
3428 *open_mode = access;
3429 if (!current->todo || (current->sharing & sharing))
3430 ok(current->sharing & sharing ||
3431 broken(!(current->sharing & sharing) && access == GENERIC_WRITE && (current->stg_mode & 0xf) != STGM_READ) /* win2k */,
3432 "file with mode %x should not be openable with %s permission\n", current->stg_mode, desc);
3433 else
3434 {
3435 todo_wine ok(current->sharing & sharing ||
3436 broken(!(current->sharing & sharing) && access == GENERIC_WRITE && (current->stg_mode & 0xf) != STGM_READ) /* win2k */,
3437 "file with mode %x should not be openable with %s permission\n", current->stg_mode, desc);
3438 *any_failure = TRUE;
3439 }
3440 }
3441 else
3442 {
3443 if (!current->todo || !(current->sharing & sharing))
3444 ok(!(current->sharing & sharing), "file with mode %x should be openable with %s permission\n", current->stg_mode, desc);
3445 else
3446 {
3447 todo_wine ok(!(current->sharing & sharing), "file with mode %x should be openable with %s permission\n", current->stg_mode, desc);
3448 *any_failure = TRUE;
3449 }
3450 }
3451 }
3452
3453 static void check_access(LPCWSTR filename, const struct lock_test *current,
3454 DWORD access, DWORD sharing, const char *desc, DWORD open_mode, BOOL *any_failure)
3455 {
3456 if (can_open(filename, open_mode, (FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE) & ~sharing))
3457 {
3458 if (!current->todo || !(current->access & access))
3459 ok(!(current->access & access), "file with mode %x should not be openable without %s sharing\n", current->stg_mode, desc);
3460 else
3461 {
3462 todo_wine ok(!(current->access & access), "file with mode %x should not be openable without %s sharing\n", current->stg_mode, desc);
3463 *any_failure = TRUE;
3464 }
3465 }
3466 else
3467 {
3468 if (!current->todo || (current->access & access))
3469 ok(current->access & access, "file with mode %x should be openable without %s sharing\n", current->stg_mode, desc);
3470 else
3471 {
3472 todo_wine ok(current->access & access, "file with mode %x should be openable without %s sharing\n", current->stg_mode, desc);
3473 *any_failure = TRUE;
3474 }
3475 }
3476 }
3477
3478 static void test_locking(void)
3479 {
3480 static const WCHAR filename[] = {'w','i','n','e','t','e','s','t',0};
3481 int i;
3482 IStorage *stg;
3483 HRESULT hr;
3484
3485 for (i=0; i<sizeof(lock_tests)/sizeof(lock_tests[0]); i++)
3486 {
3487 const struct lock_test *current = &lock_tests[i];
3488 BOOL any_failure = FALSE;
3489 DWORD open_mode = 0;
3490
3491 if (current->create)
3492 {
3493 hr = StgCreateDocfile(filename, current->stg_mode, 0, &stg);
3494 ok(SUCCEEDED(hr), "StgCreateDocfile with mode %x failed with hr %x\n", current->stg_mode, hr);
3495 if (FAILED(hr)) continue;
3496 }
3497 else
3498 {
3499 hr = StgCreateDocfile(filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &stg);
3500 ok(SUCCEEDED(hr), "StgCreateDocfile failed with hr %x\n", hr);
3501 if (FAILED(hr)) continue;
3502 IStorage_Release(stg);
3503
3504 hr = StgOpenStorage(filename, NULL, current->stg_mode, NULL, 0, &stg);
3505 ok(SUCCEEDED(hr), "StgOpenStorage with mode %x failed with hr %x\n", current->stg_mode, hr);
3506 if (FAILED(hr))
3507 {
3508 DeleteFileW(filename);
3509 continue;
3510 }
3511 }
3512
3513 check_sharing(filename, current, GENERIC_READ, FILE_SHARE_READ, "READ", &open_mode, &any_failure);
3514 check_sharing(filename, current, GENERIC_WRITE, FILE_SHARE_WRITE, "WRITE", &open_mode, &any_failure);
3515 check_sharing(filename, current, DELETE, FILE_SHARE_DELETE, "DELETE", &open_mode, &any_failure);
3516
3517 if (open_mode != 0)
3518 {
3519 HANDLE hfile;
3520 BOOL locked, expect_locked;
3521 OVERLAPPED ol;
3522 const int* next_lock = current->locked_bytes;
3523
3524 check_access(filename, current, GENERIC_READ, FILE_SHARE_READ, "READ", open_mode, &any_failure);
3525 check_access(filename, current, GENERIC_WRITE, FILE_SHARE_WRITE, "WRITE", open_mode, &any_failure);
3526 check_access(filename, current, DELETE, FILE_SHARE_DELETE, "DELETE", open_mode, &any_failure);
3527
3528 hfile = CreateFileW(filename, open_mode, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3529 ok(hfile != INVALID_HANDLE_VALUE, "couldn't open file with mode %x\n", current->stg_mode);
3530
3531 ol.u.s.OffsetHigh = 0;
3532 ol.hEvent = NULL;
3533
3534 for (ol.u.s.Offset = 0x7ffffe00; ol.u.s.Offset != 0x80000000; ol.u.s.Offset++)
3535 {
3536 if (LockFileEx(hfile, LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY, 0, 1, 0, &ol))
3537 locked = FALSE;
3538 else
3539 {
3540 ok(!LockFileEx(hfile, LOCKFILE_FAIL_IMMEDIATELY, 0, 1, 0, &ol), "shared locks should not be used\n");
3541 locked = TRUE;
3542 }
3543
3544 UnlockFileEx(hfile, 0, 1, 0, &ol);
3545
3546 if ((ol.u.s.Offset&0x1ff) == *next_lock)
3547 {
3548 expect_locked = TRUE;
3549 next_lock++;
3550 }
3551 else
3552 expect_locked = FALSE;
3553
3554 if (!current->todo || locked == expect_locked)
3555 ok(locked == expect_locked, "byte %x of file with mode %x is %slocked but should %sbe\n",
3556 ol.u.s.Offset, current->stg_mode, locked?"":"not ", expect_locked?"":"not ");
3557 else
3558 {
3559 any_failure = TRUE;
3560 todo_wine ok(locked == expect_locked, "byte %x of file with mode %x is %slocked but should %sbe\n",
3561 ol.u.s.Offset, current->stg_mode, locked?"":"not ", expect_locked?"":"not ");
3562 }
3563 }
3564
3565 CloseHandle(hfile);
3566 }
3567
3568 IStorage_Release( stg );
3569
3570 if (!current->create)
3571 {
3572 HANDLE hfile;
3573 BOOL failed, expect_failed=FALSE;
3574 OVERLAPPED ol;
3575 const int* next_range = current->fail_ranges;
3576
3577 hfile = CreateFileW(filename, open_mode, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3578 ok(hfile != INVALID_HANDLE_VALUE, "couldn't open file with mode %x\n", current->stg_mode);
3579
3580 ol.u.s.OffsetHigh = 0;
3581 ol.hEvent = NULL;
3582
3583 for (ol.u.s.Offset = 0x7ffffe00; ol.u.s.Offset != 0x80000000; ol.u.s.Offset++)
3584 {
3585 if (ol.u.s.Offset == 0x7fffff92 ||
3586 (ol.u.s.Offset == 0x7fffff80 && current->stg_mode == (STGM_TRANSACTED|STGM_READWRITE)) ||
3587 (ol.u.s.Offset == 0x7fffff80 && current->stg_mode == (STGM_TRANSACTED|STGM_READ)))
3588 continue; /* This makes opens hang */
3589
3590 if (ol.u.s.Offset < 0x7fffff00)
3591 LockFileEx(hfile, 0, 0, 1, 0, &ol);
3592 else
3593 LockFileEx(hfile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &ol);
3594
3595 hr = StgOpenStorage(filename, NULL, current->stg_mode, NULL, 0, &stg);
3596 ok(hr == S_OK || hr == STG_E_LOCKVIOLATION || hr == STG_E_SHAREVIOLATION, "failed with unexpected hr %x\n", hr);
3597 if (SUCCEEDED(hr)) IStorage_Release(stg);
3598
3599 UnlockFileEx(hfile, 0, 1, 0, &ol);
3600
3601 failed = FAILED(hr);
3602
3603 if (!expect_failed && (ol.u.s.Offset&0x1ff) == next_range[0])
3604 {
3605 expect_failed = TRUE;
3606 }
3607 else if (expect_failed && (ol.u.s.Offset&0x1ff) == next_range[1])
3608 {
3609 expect_failed = FALSE;
3610 next_range += 2;
3611 }
3612
3613 if (!current->todo || failed == expect_failed)
3614 ok(failed == expect_failed, "open with byte %x locked, mode %x %s but should %s\n",
3615 ol.u.s.Offset, current->stg_mode, failed?"failed":"succeeded", expect_failed?"fail":"succeed");
3616 else
3617 {
3618 any_failure = TRUE;
3619 todo_wine ok(failed == expect_failed, "open with byte %x locked, mode %x %s but should %s\n",
3620 ol.u.s.Offset, current->stg_mode, failed?"failed":"succeeded", expect_failed?"fail":"succeed");
3621 }
3622 }
3623
3624 CloseHandle(hfile);
3625 }
3626
3627 DeleteFileW(filename);
3628
3629 if (current->todo && !any_failure)
3630 todo_wine ok(1, "tests succeeded for mode %x\n", current->stg_mode);
3631 }
3632 }
3633
3634 static void test_transacted_shared(void)
3635 {
3636 IStorage *stg = NULL;
3637 IStorage *stgrw = NULL;
3638 HRESULT r;
3639 IStream *stm = NULL;
3640 static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
3641 LARGE_INTEGER pos;
3642 ULARGE_INTEGER upos;
3643 char buffer[10];
3644 ULONG bytesread;
3645
3646 DeleteFileA(filenameA);
3647
3648 /* create a new transacted storage with a stream */
3649 r = StgCreateDocfile(filename, STGM_CREATE |
3650 STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
3651 ok(r==S_OK, "StgCreateDocfile failed %x\n", r);
3652
3653 r = WriteClassStg(stg, &test_stg_cls);
3654 ok(r == S_OK, "WriteClassStg failed %x\n", r);
3655
3656 r = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm);
3657 ok(r==S_OK, "IStorage->CreateStream failed %x\n", r);
3658
3659 pos.QuadPart = 0;
3660 r = IStream_Seek(stm, pos, 0, &upos);
3661 ok(r==S_OK, "IStream->Seek failed %x\n", r);
3662
3663 r = IStream_Write(stm, "aaa", 3, NULL);
3664 ok(r==S_OK, "IStream->Write failed %x\n", r);
3665
3666 r = IStorage_Commit(stg, STGC_ONLYIFCURRENT);
3667 ok(r==S_OK, "IStorage->Commit failed %x\n", r);
3668
3669 /* open a second transacted read/write storage */
3670 r = StgOpenStorage(filename, NULL, STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_DENY_NONE, NULL, 0, &stgrw);
3671 ok(r==S_OK, "StgOpenStorage failed %x\n", r);
3672
3673 /* update stream on the first storage and commit */
3674 pos.QuadPart = 0;
3675 r = IStream_Seek(stm, pos, 0, &upos);
3676 ok(r==S_OK, "IStream->Seek failed %x\n", r);
3677
3678 r = IStream_Write(stm, "ccc", 3, NULL);
3679 ok(r==S_OK, "IStream->Write failed %x\n", r);
3680
3681 r = IStorage_Commit(stg, STGC_ONLYIFCURRENT);
3682 ok(r==S_OK, "IStorage->Commit failed %x\n", r);
3683
3684 /* update again without committing */
3685 pos.QuadPart = 0;
3686 r = IStream_Seek(stm, pos, 0, &upos);
3687 ok(r==S_OK, "IStream->Seek failed %x\n", r);
3688
3689 r = IStream_Write(stm, "ddd", 3, NULL);
3690 ok(r==S_OK, "IStream->Write failed %x\n", r);
3691
3692 IStream_Release(stm);
3693
3694 /* we can still read the old content from the second storage */
3695 r = IStorage_OpenStream(stgrw, stmname, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &stm);
3696 ok(r==S_OK, "IStorage->OpenStream failed %x\n", r);
3697
3698 pos.QuadPart = 0;
3699 r = IStream_Seek(stm, pos, 0, &upos);
3700 ok(r==S_OK, "IStream->Seek failed %x\n", r);
3701
3702 r = IStream_Read(stm, buffer, sizeof(buffer), &bytesread);
3703 ok(r==S_OK, "IStream->Read failed %x\n", r);
3704 ok(bytesread == 3, "read wrong number of bytes %i\n", bytesread);
3705 ok(memcmp(buffer, "aaa", 3) == 0, "wrong data\n");
3706
3707 /* and overwrite the data */
3708 pos.QuadPart = 0;
3709 r = IStream_Seek(stm, pos, 0, &upos);
3710 ok(r==S_OK, "IStream->Seek failed %x\n", r);
3711
3712 r = IStream_Write(stm, "bbb", 3, NULL);
3713 ok(r==S_OK, "IStream->Write failed %x\n", r);
3714
3715 IStream_Release(stm);
3716
3717 /* commit fails because we're out of date */
3718 r = IStorage_Commit(stgrw, STGC_ONLYIFCURRENT);
3719 ok(r==STG_E_NOTCURRENT, "IStorage->Commit failed %x\n", r);
3720
3721 /* unless we force it */
3722 r = IStorage_Commit(stgrw, STGC_DEFAULT);
3723 ok(r==S_OK, "IStorage->Commit failed %x\n", r);
3724
3725 /* reverting gets us back to the last commit from the same storage */
3726 r = IStorage_Revert(stg);
3727 ok(r==S_OK, "IStorage->Revert failed %x\n", r);
3728
3729 r = IStorage_OpenStream(stg, stmname, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &stm);
3730 ok(r==S_OK, "IStorage->CreateStream failed %x\n", r);
3731
3732 pos.QuadPart = 0;
3733 r = IStream_Seek(stm, pos, 0, &upos);
3734 ok(r==S_OK, "IStream->Seek failed %x\n", r);
3735
3736 r = IStream_Read(stm, buffer, sizeof(buffer), &bytesread);
3737 ok(r==S_OK, "IStream->Read failed %x\n", r);
3738 ok(bytesread == 3, "read wrong number of bytes %i\n", bytesread);
3739 ok(memcmp(buffer, "ccc", 3) == 0, "wrong data\n");
3740
3741 /* and committing fails forever */
3742 r = IStorage_Commit(stg, STGC_ONLYIFCURRENT);
3743 ok(r==STG_E_NOTCURRENT, "IStorage->Commit failed %x\n", r);
3744
3745 IStream_Release(stm);
3746
3747 IStorage_Release(stg);
3748 IStorage_Release(stgrw);
3749
3750 DeleteFileA(filenameA);
3751 }
3752
3753 static void test_overwrite(void)
3754 {
3755 IStorage *stg = NULL;
3756 HRESULT r;
3757 IStream *stm = NULL;
3758 static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
3759 static const WCHAR stmname2[] = { 'C','O','N','T','E','N','T','2',0 };
3760 LARGE_INTEGER pos;
3761 ULARGE_INTEGER upos;
3762 char buffer[4096];
3763 DWORD orig_size, new_size;
3764 ULONG bytesread;
3765 HANDLE hfile;
3766 int i;
3767
3768 DeleteFileA(filenameA);
3769
3770 r = StgCreateDocfile(filename, STGM_CREATE | STGM_READWRITE | STGM_TRANSACTED, 0, &stg);
3771 ok(r==S_OK, "StgCreateDocfile failed %x\n", r);
3772
3773 r = WriteClassStg(stg, &test_stg_cls);
3774 ok(r == S_OK, "WriteClassStg failed %x\n", r);
3775
3776 r = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm);
3777 ok(r==S_OK, "IStorage->CreateStream failed %x\n", r);
3778
3779 pos.QuadPart = 0;
3780 r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &upos);
3781 ok(r==S_OK, "IStream->Seek failed %x\n", r);
3782
3783 memset(buffer, 'a', sizeof(buffer));
3784 for (i=0; i<4; i++)
3785 {
3786 /* Write enough bytes to pass the minimum storage file size */
3787 r = IStream_Write(stm, buffer, sizeof(buffer), NULL);
3788 ok(r==S_OK, "IStream->Write failed %x\n", r);
3789 }
3790
3791 r = IStorage_Commit(stg, STGC_DEFAULT);
3792 ok(r==S_OK, "IStorage->Commit failed %x\n", r);
3793
3794 hfile = CreateFileA(filenameA, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
3795 NULL, OPEN_EXISTING, 0, NULL);
3796 ok(hfile != NULL, "couldn't open file %d\n", GetLastError());
3797
3798 orig_size = GetFileSize(hfile, NULL);
3799
3800 pos.QuadPart = 0;
3801 r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &upos);
3802 ok(r==S_OK, "IStream->Seek failed %x\n", r);
3803
3804 r = IStream_Write(stm, "b", 1, NULL);
3805 ok(r==S_OK, "IStream->Write failed %x\n", r);
3806
3807 r = IStorage_Commit(stg, STGC_OVERWRITE);
3808 ok(r==S_OK, "IStorage->Commit failed %x\n", r);
3809
3810 new_size = GetFileSize(hfile, NULL);
3811
3812 todo_wine ok(new_size == orig_size, "file grew from %d bytes to %d\n", orig_size, new_size);
3813
3814 IStream_Release(stm);
3815
3816 IStorage_RenameElement(stg, stmname, stmname2);
3817
3818 r = IStorage_Commit(stg, STGC_OVERWRITE);
3819 ok(r==S_OK, "IStorage->Commit failed %x\n", r);
3820
3821 new_size = GetFileSize(hfile, NULL);
3822
3823 todo_wine ok(new_size == orig_size, "file grew from %d bytes to %d\n", orig_size, new_size);
3824
3825 IStorage_Release(stg);
3826
3827 r = StgOpenStorage(filename, NULL, STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg);
3828 ok(r==S_OK, "StgOpenStorage failed %x\n", r);
3829
3830 r = IStorage_OpenStream(stg, stmname2, NULL, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &stm);
3831 ok(r==S_OK, "IStorage->CreateStream failed %x\n", r);
3832
3833 r = IStream_Read(stm, buffer, sizeof(buffer), &bytesread);
3834 ok(r==S_OK, "IStream->Write failed %x\n", r);
3835 ok(bytesread == sizeof(buffer), "only read %d bytes\n", bytesread);
3836 ok(buffer[0] == 'b', "unexpected data at byte 0\n");
3837
3838 for (i=1; i<sizeof(buffer); i++)
3839 if (buffer[i] != 'a')
3840 break;
3841 ok(i == sizeof(buffer), "unexpected data at byte %i\n", i);
3842
3843 pos.QuadPart = 0;
3844 r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &upos);
3845 ok(r==S_OK, "IStream->Seek failed %x\n", r);
3846
3847 r = IStream_Write(stm, "c", 1, NULL);
3848 ok(r==S_OK, "IStream->Write failed %x\n", r);
3849
3850 r = IStorage_Commit(stg, STGC_OVERWRITE);
3851 ok(r==S_OK, "IStorage->Commit failed %x\n", r);
3852
3853 new_size = GetFileSize(hfile, NULL);
3854
3855 todo_wine ok(new_size == orig_size, "file grew from %d bytes to %d\n", orig_size, new_size);
3856
3857 IStream_Release(stm);
3858
3859 IStorage_Release(stg);
3860
3861 CloseHandle(hfile);
3862
3863 DeleteFileA(filenameA);
3864 }
3865
3866 static void test_custom_lockbytes(void)
3867 {
3868 static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
3869 TestLockBytes* lockbytes;
3870 HRESULT hr;
3871 IStorage* stg;
3872 IStream* stm;
3873
3874 CreateTestLockBytes(&lockbytes);
3875
3876 hr = StgCreateDocfileOnILockBytes(&lockbytes->ILockBytes_iface, STGM_CREATE|STGM_READWRITE|STGM_TRANSACTED, 0, &stg);
3877 ok(hr==S_OK, "StgCreateDocfileOnILockBytes failed %x\n", hr);
3878
3879 hr = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &stm);
3880 ok(hr==S_OK, "IStorage_CreateStream failed %x\n", hr);
3881
3882 IStream_Release(stm);
3883
3884 hr = IStorage_Commit(stg, 0);
3885
3886 IStorage_Release(stg);
3887
3888 ok(!lockbytes->lock_called, "unexpected call to LockRegion\n");
3889
3890 lockbytes->locks_supported = LOCK_WRITE|LOCK_EXCLUSIVE|LOCK_ONLYONCE;
3891
3892 hr = StgCreateDocfileOnILockBytes(&lockbytes->ILockBytes_iface, STGM_CREATE|STGM_READWRITE|STGM_TRANSACTED, 0, &stg);
3893 ok(hr==S_OK, "StgCreateDocfileOnILockBytes failed %x\n", hr);
3894
3895 hr = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &stm);
3896 ok(hr==S_OK, "IStorage_CreateStream failed %x\n", hr);
3897
3898 IStream_Release(stm);
3899
3900 hr = IStorage_Commit(stg, 0);
3901
3902 IStorage_Release(stg);
3903
3904 ok(lockbytes->lock_called, "expected LockRegion to be called\n");
3905
3906 lockbytes->lock_hr = STG_E_INVALIDFUNCTION;
3907
3908 hr = StgCreateDocfileOnILockBytes(&lockbytes->ILockBytes_iface, STGM_CREATE|STGM_READWRITE|STGM_TRANSACTED, 0, &stg);
3909 ok(hr==STG_E_INVALIDFUNCTION, "StgCreateDocfileOnILockBytes failed %x\n", hr);
3910
3911 DeleteTestLockBytes(lockbytes);
3912 }
3913
3914 START_TEST(storage32)
3915 {
3916 CHAR temp[MAX_PATH];
3917
3918 GetTempPathA(MAX_PATH, temp);
3919 if(!GetTempFileNameA(temp, "stg", 0, filenameA))
3920 {
3921 win_skip("Could not create temp file, %u\n", GetLastError());
3922 return;
3923 }
3924 MultiByteToWideChar(CP_ACP, 0, filenameA, -1, filename, MAX_PATH);
3925 DeleteFileA(filenameA);
3926
3927 test_hglobal_storage_stat();
3928 test_create_storage_modes();
3929 test_stgcreatestorageex();
3930 test_storage_stream();
3931 test_open_storage();
3932 test_storage_suminfo();
3933 test_storage_refcount();
3934 test_streamenum();
3935 test_transact();
3936 test_substorage_share();
3937 test_revert();
3938 test_parent_free();
3939 test_nonroot_transacted();
3940 test_ReadClassStm();
3941 test_access();
3942 test_writeclassstg();
3943 test_readonly();
3944 test_simple();
3945 test_fmtusertypestg();
3946 test_references();
3947 test_copyto();
3948 test_copyto_snbexclusions();
3949 test_copyto_iidexclusions_storage();
3950 test_copyto_iidexclusions_stream();
3951 test_rename();
3952 test_toplevel_stat();
3953 test_substorage_enum();
3954 test_copyto_locking();
3955 test_copyto_recursive();
3956 test_hglobal_storage_creation();
3957 test_convert();
3958 test_direct_swmr();
3959 test_locking();
3960 test_transacted_shared();
3961 test_overwrite();
3962 test_custom_lockbytes();
3963 }