Silence a noisy FIXME.
[wine/multimedia.git] / dlls / itss / storage.c
blob221cc832bbaf635d49440af1f798e23424e0d353
1 /*
2 * ITSS Storage implementation
4 * Copyright 2004 Mike McCormack
6 * see http://bonedaddy.net/pabs3/hhm/#chmspec
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "config.h"
25 #include <stdarg.h>
26 #include <stdio.h>
28 #define COBJMACROS
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winuser.h"
33 #include "winnls.h"
34 #include "winreg.h"
35 #include "ole2.h"
37 #include "uuids.h"
39 #include "itss.h"
40 #include "chm_lib.h"
41 #include "itsstor.h"
43 #include "wine/unicode.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(itss);
48 extern ULONG dll_count;
50 /************************************************************************/
52 typedef struct _ITSS_IStorageImpl
54 IStorageVtbl *vtbl_IStorage;
55 DWORD ref;
56 struct chmFile *chmfile;
57 WCHAR dir[1];
58 } ITSS_IStorageImpl;
60 struct enum_info
62 struct enum_info *next, *prev;
63 struct chmUnitInfo ui;
66 typedef struct _IEnumSTATSTG_Impl
68 IEnumSTATSTGVtbl *vtbl_IEnumSTATSTG;
69 DWORD ref;
70 struct enum_info *first, *last, *current;
71 } IEnumSTATSTG_Impl;
73 typedef struct _IStream_Impl
75 IStreamVtbl *vtbl_IStream;
76 DWORD ref;
77 ITSS_IStorageImpl *stg;
78 ULONGLONG addr;
79 struct chmUnitInfo ui;
80 } IStream_Impl;
82 static HRESULT ITSS_create_chm_storage(
83 struct chmFile *chmfile, const WCHAR *dir, IStorage** ppstgOpen );
84 static IStream_Impl* ITSS_create_stream(
85 ITSS_IStorageImpl *stg, struct chmUnitInfo *ui );
87 /************************************************************************/
89 static HRESULT WINAPI ITSS_IEnumSTATSTG_QueryInterface(
90 IEnumSTATSTG* iface,
91 REFIID riid,
92 void** ppvObject)
94 IEnumSTATSTG_Impl *This = (IEnumSTATSTG_Impl *)iface;
96 if (IsEqualGUID(riid, &IID_IUnknown)
97 || IsEqualGUID(riid, &IID_IEnumSTATSTG))
99 IEnumSTATSTG_AddRef(iface);
100 *ppvObject = This;
101 return S_OK;
104 WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
105 return E_NOINTERFACE;
108 static ULONG WINAPI ITSS_IEnumSTATSTG_AddRef(
109 IEnumSTATSTG* iface)
111 IEnumSTATSTG_Impl *This = (IEnumSTATSTG_Impl *)iface;
112 return InterlockedIncrement(&This->ref);
115 static ULONG WINAPI ITSS_IEnumSTATSTG_Release(
116 IEnumSTATSTG* iface)
118 IEnumSTATSTG_Impl *This = (IEnumSTATSTG_Impl *)iface;
120 ULONG ref = InterlockedDecrement(&This->ref);
122 if (ref == 0)
124 while( This->first )
126 struct enum_info *t = This->first->next;
127 HeapFree( GetProcessHeap(), 0, This->first );
128 This->first = t;
130 HeapFree(GetProcessHeap(), 0, This);
131 InterlockedDecrement(&dll_count);
134 return ref;
137 static HRESULT WINAPI ITSS_IEnumSTATSTG_Next(
138 IEnumSTATSTG* iface,
139 ULONG celt,
140 STATSTG* rgelt,
141 ULONG* pceltFetched)
143 IEnumSTATSTG_Impl *This = (IEnumSTATSTG_Impl *)iface;
144 DWORD len, n;
145 struct enum_info *cur;
147 TRACE("%p %lu %p %p\n", This, celt, rgelt, pceltFetched );
149 cur = This->current;
150 n = 0;
151 while( (n<celt) && cur)
153 WCHAR *str;
155 memset( rgelt, 0, sizeof *rgelt );
157 /* copy the name */
158 str = cur->ui.path;
159 if( *str == '/' )
160 str++;
161 len = strlenW( str ) + 1;
162 rgelt->pwcsName = CoTaskMemAlloc( len*sizeof(WCHAR) );
163 strcpyW( rgelt->pwcsName, str );
165 /* determine the type */
166 if( rgelt->pwcsName[len-2] == '/' )
168 rgelt->pwcsName[len-2] = 0;
169 rgelt->type = STGTY_STORAGE;
171 else
172 rgelt->type = STGTY_STREAM;
174 /* copy the size */
175 rgelt->cbSize.QuadPart = cur->ui.length;
177 /* advance to the next item if it exists */
178 n++;
179 cur = cur->next;
182 This->current = cur;
183 *pceltFetched = n;
185 if( n < celt )
186 return S_FALSE;
188 return S_OK;
191 static HRESULT WINAPI ITSS_IEnumSTATSTG_Skip(
192 IEnumSTATSTG* iface,
193 ULONG celt)
195 IEnumSTATSTG_Impl *This = (IEnumSTATSTG_Impl *)iface;
196 DWORD n;
197 struct enum_info *cur;
199 TRACE("%p %lu\n", This, celt );
201 cur = This->current;
202 n = 0;
203 while( (n<celt) && cur)
205 n++;
206 cur = cur->next;
208 This->current = cur;
210 if( n < celt )
211 return S_FALSE;
213 return S_OK;
216 static HRESULT WINAPI ITSS_IEnumSTATSTG_Reset(
217 IEnumSTATSTG* iface)
219 IEnumSTATSTG_Impl *This = (IEnumSTATSTG_Impl *)iface;
221 TRACE("%p\n", This );
223 This->current = This->first;
225 return S_OK;
228 static HRESULT WINAPI ITSS_IEnumSTATSTG_Clone(
229 IEnumSTATSTG* iface,
230 IEnumSTATSTG** ppenum)
232 FIXME("\n");
233 return E_NOTIMPL;
236 struct IEnumSTATSTGVtbl IEnumSTATSTG_vtbl =
238 ITSS_IEnumSTATSTG_QueryInterface,
239 ITSS_IEnumSTATSTG_AddRef,
240 ITSS_IEnumSTATSTG_Release,
241 ITSS_IEnumSTATSTG_Next,
242 ITSS_IEnumSTATSTG_Skip,
243 ITSS_IEnumSTATSTG_Reset,
244 ITSS_IEnumSTATSTG_Clone
247 static IEnumSTATSTG_Impl *ITSS_create_enum( void )
249 IEnumSTATSTG_Impl *stgenum;
251 stgenum = HeapAlloc( GetProcessHeap(), 0, sizeof (IEnumSTATSTG_Impl) );
252 stgenum->vtbl_IEnumSTATSTG = &IEnumSTATSTG_vtbl;
253 stgenum->ref = 1;
254 stgenum->first = NULL;
255 stgenum->last = NULL;
256 stgenum->current = NULL;
257 InterlockedIncrement(&dll_count);
259 TRACE(" -> %p\n", stgenum );
261 return stgenum;
264 /************************************************************************/
266 HRESULT WINAPI ITSS_IStorageImpl_QueryInterface(
267 IStorage* iface,
268 REFIID riid,
269 void** ppvObject)
271 ITSS_IStorageImpl *This = (ITSS_IStorageImpl *)iface;
273 if (IsEqualGUID(riid, &IID_IUnknown)
274 || IsEqualGUID(riid, &IID_IStorage))
276 IStorage_AddRef(iface);
277 *ppvObject = This;
278 return S_OK;
281 WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
282 return E_NOINTERFACE;
285 ULONG WINAPI ITSS_IStorageImpl_AddRef(
286 IStorage* iface)
288 ITSS_IStorageImpl *This = (ITSS_IStorageImpl *)iface;
289 return InterlockedIncrement(&This->ref);
292 ULONG WINAPI ITSS_IStorageImpl_Release(
293 IStorage* iface)
295 ITSS_IStorageImpl *This = (ITSS_IStorageImpl *)iface;
297 ULONG ref = InterlockedDecrement(&This->ref);
299 if (ref == 0)
301 HeapFree(GetProcessHeap(), 0, This);
302 InterlockedDecrement(&dll_count);
305 return ref;
308 HRESULT WINAPI ITSS_IStorageImpl_CreateStream(
309 IStorage* iface,
310 LPCOLESTR pwcsName,
311 DWORD grfMode,
312 DWORD reserved1,
313 DWORD reserved2,
314 IStream** ppstm)
316 FIXME("\n");
317 return E_NOTIMPL;
320 HRESULT WINAPI ITSS_IStorageImpl_OpenStream(
321 IStorage* iface,
322 LPCOLESTR pwcsName,
323 void* reserved1,
324 DWORD grfMode,
325 DWORD reserved2,
326 IStream** ppstm)
328 ITSS_IStorageImpl *This = (ITSS_IStorageImpl *)iface;
329 IStream_Impl *stm;
330 DWORD len;
331 struct chmUnitInfo ui;
332 int r;
333 WCHAR *path;
335 TRACE("%p %s %p %lu %lu %p\n", This, debugstr_w(pwcsName),
336 reserved1, grfMode, reserved2, ppstm );
338 len = strlenW( This->dir ) + strlenW( pwcsName ) + 1;
339 path = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
340 strcpyW( path, This->dir );
341 if( pwcsName[0] == '/' )
343 WCHAR *p = &path[strlenW( path ) - 1];
344 while( ( path <= p ) && ( *p == '/' ) )
345 *p-- = 0;
347 strcatW( path, pwcsName );
349 TRACE("Resolving %s\n", debugstr_w(path));
351 r = chm_resolve_object(This->chmfile, path, &ui);
352 HeapFree( GetProcessHeap(), 0, path );
354 if( r != CHM_RESOLVE_SUCCESS )
355 return STG_E_FILENOTFOUND;
357 stm = ITSS_create_stream( This, &ui );
358 if( !stm )
359 return E_FAIL;
361 *ppstm = (IStream*) stm;
363 return S_OK;
366 HRESULT WINAPI ITSS_IStorageImpl_CreateStorage(
367 IStorage* iface,
368 LPCOLESTR pwcsName,
369 DWORD grfMode,
370 DWORD dwStgFmt,
371 DWORD reserved2,
372 IStorage** ppstg)
374 FIXME("\n");
375 return E_NOTIMPL;
378 HRESULT WINAPI ITSS_IStorageImpl_OpenStorage(
379 IStorage* iface,
380 LPCOLESTR pwcsName,
381 IStorage* pstgPriority,
382 DWORD grfMode,
383 SNB snbExclude,
384 DWORD reserved,
385 IStorage** ppstg)
387 ITSS_IStorageImpl *This = (ITSS_IStorageImpl *)iface;
389 FIXME("%p %s %p %lu %p %lu %p\n", This, debugstr_w(pwcsName),
390 pstgPriority, grfMode, snbExclude, reserved, ppstg);
391 return E_NOTIMPL;
394 HRESULT WINAPI ITSS_IStorageImpl_CopyTo(
395 IStorage* iface,
396 DWORD ciidExclude,
397 const IID* rgiidExclude,
398 SNB snbExclude,
399 IStorage* pstgDest)
401 FIXME("\n");
402 return E_NOTIMPL;
405 HRESULT WINAPI ITSS_IStorageImpl_MoveElementTo(
406 IStorage* iface,
407 LPCOLESTR pwcsName,
408 IStorage* pstgDest,
409 LPCOLESTR pwcsNewName,
410 DWORD grfFlags)
412 FIXME("\n");
413 return E_NOTIMPL;
416 HRESULT WINAPI ITSS_IStorageImpl_Commit(
417 IStorage* iface,
418 DWORD grfCommitFlags)
420 FIXME("\n");
421 return E_NOTIMPL;
424 HRESULT WINAPI ITSS_IStorageImpl_Revert(
425 IStorage* iface)
427 FIXME("\n");
428 return E_NOTIMPL;
431 static int ITSS_chm_enumerator(
432 struct chmFile *h,
433 struct chmUnitInfo *ui,
434 void *context)
436 struct enum_info *info;
437 IEnumSTATSTG_Impl* stgenum = context;
439 TRACE("adding %s to enumeration\n", debugstr_w(ui->path) );
441 info = HeapAlloc( GetProcessHeap(), 0, sizeof (struct enum_info) );
442 memcpy( &info->ui, ui, sizeof info->ui );
444 info->next = NULL;
445 info->prev = stgenum->last;
446 if( stgenum->last )
447 stgenum->last->next = info;
448 else
449 stgenum->first = info;
450 stgenum->last = info;
452 return CHM_ENUMERATOR_CONTINUE;
455 HRESULT WINAPI ITSS_IStorageImpl_EnumElements(
456 IStorage* iface,
457 DWORD reserved1,
458 void* reserved2,
459 DWORD reserved3,
460 IEnumSTATSTG** ppenum)
462 ITSS_IStorageImpl *This = (ITSS_IStorageImpl *)iface;
463 IEnumSTATSTG_Impl* stgenum;
465 TRACE("%p %ld %p %ld %p\n", This, reserved1, reserved2, reserved3, ppenum );
467 stgenum = ITSS_create_enum();
468 if( !stgenum )
469 return E_FAIL;
471 chm_enumerate_dir(This->chmfile,
472 This->dir,
473 CHM_ENUMERATE_ALL,
474 ITSS_chm_enumerator,
475 stgenum );
477 stgenum->current = stgenum->first;
479 *ppenum = (IEnumSTATSTG*) stgenum;
481 return S_OK;
484 HRESULT WINAPI ITSS_IStorageImpl_DestroyElement(
485 IStorage* iface,
486 LPCOLESTR pwcsName)
488 FIXME("\n");
489 return E_NOTIMPL;
492 HRESULT WINAPI ITSS_IStorageImpl_RenameElement(
493 IStorage* iface,
494 LPCOLESTR pwcsOldName,
495 LPCOLESTR pwcsNewName)
497 FIXME("\n");
498 return E_NOTIMPL;
501 HRESULT WINAPI ITSS_IStorageImpl_SetElementTimes(
502 IStorage* iface,
503 LPCOLESTR pwcsName,
504 const FILETIME* pctime,
505 const FILETIME* patime,
506 const FILETIME* pmtime)
508 FIXME("\n");
509 return E_NOTIMPL;
512 HRESULT WINAPI ITSS_IStorageImpl_SetClass(
513 IStorage* iface,
514 REFCLSID clsid)
516 FIXME("\n");
517 return E_NOTIMPL;
520 HRESULT WINAPI ITSS_IStorageImpl_SetStateBits(
521 IStorage* iface,
522 DWORD grfStateBits,
523 DWORD grfMask)
525 FIXME("\n");
526 return E_NOTIMPL;
529 HRESULT WINAPI ITSS_IStorageImpl_Stat(
530 IStorage* iface,
531 STATSTG* pstatstg,
532 DWORD grfStatFlag)
534 FIXME("\n");
535 return E_NOTIMPL;
538 static IStorageVtbl ITSS_IStorageImpl_Vtbl =
540 ITSS_IStorageImpl_QueryInterface,
541 ITSS_IStorageImpl_AddRef,
542 ITSS_IStorageImpl_Release,
543 ITSS_IStorageImpl_CreateStream,
544 ITSS_IStorageImpl_OpenStream,
545 ITSS_IStorageImpl_CreateStorage,
546 ITSS_IStorageImpl_OpenStorage,
547 ITSS_IStorageImpl_CopyTo,
548 ITSS_IStorageImpl_MoveElementTo,
549 ITSS_IStorageImpl_Commit,
550 ITSS_IStorageImpl_Revert,
551 ITSS_IStorageImpl_EnumElements,
552 ITSS_IStorageImpl_DestroyElement,
553 ITSS_IStorageImpl_RenameElement,
554 ITSS_IStorageImpl_SetElementTimes,
555 ITSS_IStorageImpl_SetClass,
556 ITSS_IStorageImpl_SetStateBits,
557 ITSS_IStorageImpl_Stat,
560 static HRESULT ITSS_create_chm_storage(
561 struct chmFile *chmfile, const WCHAR *dir, IStorage** ppstgOpen )
563 ITSS_IStorageImpl *stg;
564 DWORD len;
566 TRACE("%p %s\n", chmfile, debugstr_w( dir ) );
568 len = strlenW( dir ) + 1;
569 stg = HeapAlloc( GetProcessHeap(), 0,
570 sizeof (ITSS_IStorageImpl) + len*sizeof(WCHAR) );
571 stg->vtbl_IStorage = &ITSS_IStorageImpl_Vtbl;
572 stg->ref = 1;
573 stg->chmfile = chmfile;
574 strcpyW( stg->dir, dir );
576 *ppstgOpen = (IStorage*) stg;
577 InterlockedIncrement(&dll_count);
579 return S_OK;
582 HRESULT ITSS_StgOpenStorage(
583 const WCHAR* pwcsName,
584 IStorage* pstgPriority,
585 DWORD grfMode,
586 SNB snbExclude,
587 DWORD reserved,
588 IStorage** ppstgOpen)
590 struct chmFile *chmfile;
591 static const WCHAR szRoot[] = { '/', 0 };
593 TRACE("%s\n", debugstr_w(pwcsName) );
595 chmfile = chm_openW( pwcsName );
596 if( !chmfile )
597 return E_FAIL;
599 return ITSS_create_chm_storage( chmfile, szRoot, ppstgOpen );
602 /************************************************************************/
604 static HRESULT WINAPI ITSS_IStream_QueryInterface(
605 IStream* iface,
606 REFIID riid,
607 void** ppvObject)
609 IStream_Impl *This = (IStream_Impl *)iface;
611 if (IsEqualGUID(riid, &IID_IUnknown)
612 || IsEqualGUID(riid, &IID_ISequentialStream)
613 || IsEqualGUID(riid, &IID_IStream))
615 IStream_AddRef(iface);
616 *ppvObject = This;
617 return S_OK;
620 WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
621 return E_NOINTERFACE;
624 static ULONG WINAPI ITSS_IStream_AddRef(
625 IStream* iface)
627 IStream_Impl *This = (IStream_Impl *)iface;
628 return InterlockedIncrement(&This->ref);
631 static ULONG WINAPI ITSS_IStream_Release(
632 IStream* iface)
634 IStream_Impl *This = (IStream_Impl *)iface;
636 ULONG ref = InterlockedDecrement(&This->ref);
638 if (ref == 0)
640 IStorage_Release( (IStorage*) This->stg );
641 HeapFree(GetProcessHeap(), 0, This);
642 InterlockedDecrement(&dll_count);
645 return ref;
648 static HRESULT WINAPI ITSS_IStream_Read(
649 IStream* iface,
650 void* pv,
651 ULONG cb,
652 ULONG* pcbRead)
654 IStream_Impl *This = (IStream_Impl *)iface;
655 ULONG count;
657 TRACE("%p %p %lu %p\n", This, pv, cb, pcbRead);
659 count = chm_retrieve_object(This->stg->chmfile,
660 &This->ui, pv, This->addr, cb);
661 This->addr += count;
662 if( pcbRead )
663 *pcbRead = count;
665 return S_OK;
668 static HRESULT WINAPI ITSS_IStream_Write(
669 IStream* iface,
670 const void* pv,
671 ULONG cb,
672 ULONG* pcbWritten)
674 FIXME("\n");
675 return E_NOTIMPL;
678 static HRESULT WINAPI ITSS_IStream_Seek(
679 IStream* iface,
680 LARGE_INTEGER dlibMove,
681 DWORD dwOrigin,
682 ULARGE_INTEGER* plibNewPosition)
684 IStream_Impl *This = (IStream_Impl *)iface;
685 LONGLONG newpos;
687 TRACE("%p %s %lu %p\n", This,
688 wine_dbgstr_longlong( dlibMove.QuadPart ), dwOrigin, plibNewPosition );
690 newpos = This->addr;
691 switch( dwOrigin )
693 case STREAM_SEEK_CUR:
694 newpos = This->addr + dlibMove.QuadPart;
695 break;
696 case STREAM_SEEK_SET:
697 newpos = dlibMove.QuadPart;
698 break;
699 case STREAM_SEEK_END:
700 newpos = This->ui.length + dlibMove.QuadPart;
701 break;
704 if( ( newpos < 0 ) || ( newpos > This->ui.length ) )
705 return STG_E_INVALIDPOINTER;
707 This->addr = newpos;
708 if( plibNewPosition )
709 plibNewPosition->QuadPart = This->addr;
711 return S_OK;
714 static HRESULT WINAPI ITSS_IStream_SetSize(
715 IStream* iface,
716 ULARGE_INTEGER libNewSize)
718 FIXME("\n");
719 return E_NOTIMPL;
722 static HRESULT WINAPI ITSS_IStream_CopyTo(
723 IStream* iface,
724 IStream* pstm,
725 ULARGE_INTEGER cb,
726 ULARGE_INTEGER* pcbRead,
727 ULARGE_INTEGER* pcbWritten)
729 FIXME("\n");
730 return E_NOTIMPL;
733 static HRESULT WINAPI ITSS_IStream_Commit(
734 IStream* iface,
735 DWORD grfCommitFlags)
737 FIXME("\n");
738 return E_NOTIMPL;
741 static HRESULT WINAPI ITSS_IStream_Revert(
742 IStream* iface)
744 FIXME("\n");
745 return E_NOTIMPL;
748 static HRESULT WINAPI ITSS_IStream_LockRegion(
749 IStream* iface,
750 ULARGE_INTEGER libOffset,
751 ULARGE_INTEGER cb,
752 DWORD dwLockType)
754 FIXME("\n");
755 return E_NOTIMPL;
758 static HRESULT WINAPI ITSS_IStream_UnlockRegion(
759 IStream* iface,
760 ULARGE_INTEGER libOffset,
761 ULARGE_INTEGER cb,
762 DWORD dwLockType)
764 FIXME("\n");
765 return E_NOTIMPL;
768 static HRESULT WINAPI ITSS_IStream_Stat(
769 IStream* iface,
770 STATSTG* pstatstg,
771 DWORD grfStatFlag)
773 IStream_Impl *This = (IStream_Impl *)iface;
775 TRACE("%p %p %ld\n", This, pstatstg, grfStatFlag);
777 memset( pstatstg, 0, sizeof *pstatstg );
778 if( !( grfStatFlag & STATFLAG_NONAME ) )
780 FIXME("copy the name\n");
782 pstatstg->type = STGTY_STREAM;
783 pstatstg->cbSize.QuadPart = This->ui.length;
784 pstatstg->grfMode = STGM_READ;
785 memcpy( &pstatstg->clsid, &CLSID_ITStorage, sizeof (CLSID) );
787 return S_OK;
790 static HRESULT WINAPI ITSS_IStream_Clone(
791 IStream* iface,
792 IStream** ppstm)
794 FIXME("\n");
795 return E_NOTIMPL;
798 struct IStreamVtbl ITSS_IStream_vtbl =
800 ITSS_IStream_QueryInterface,
801 ITSS_IStream_AddRef,
802 ITSS_IStream_Release,
803 ITSS_IStream_Read,
804 ITSS_IStream_Write,
805 ITSS_IStream_Seek,
806 ITSS_IStream_SetSize,
807 ITSS_IStream_CopyTo,
808 ITSS_IStream_Commit,
809 ITSS_IStream_Revert,
810 ITSS_IStream_LockRegion,
811 ITSS_IStream_UnlockRegion,
812 ITSS_IStream_Stat,
813 ITSS_IStream_Clone,
816 static IStream_Impl *ITSS_create_stream(
817 ITSS_IStorageImpl *stg, struct chmUnitInfo *ui )
819 IStream_Impl *stm;
821 stm = HeapAlloc( GetProcessHeap(), 0, sizeof (IStream_Impl) );
822 stm->vtbl_IStream = &ITSS_IStream_vtbl;
823 stm->ref = 1;
824 stm->addr = 0;
825 memcpy( &stm->ui, ui, sizeof stm->ui );
826 stm->stg = stg;
827 IStorage_AddRef( (IStorage*) stg );
828 InterlockedIncrement(&dll_count);
830 TRACE(" -> %p\n", stm );
832 return stm;