3 * Implemented using the documentation of the LAOLA project at
4 * <URL:http://wwwwbs.cs.tu-berlin.de/~schwartz/pmh/index.html>
5 * (Thanks to Martin Schwartz <schwartz@cs.tu-berlin.de>)
7 * Copyright 1998 Marcus Meissner
16 #include <ddk/ntddk.h>
17 #include <ole32/ole32.h>
19 #include <storage32.h>
23 struct storage_header
{
24 BYTE magic
[8]; /* 00: magic */
25 BYTE unknown1
[36]; /* 08: unknown */
26 DWORD num_of_bbd_blocks
;/* 2C: length of big datablocks */
27 DWORD root_startblock
;/* 30: root storage first big block */
28 DWORD unknown2
[2]; /* 34: unknown */
29 DWORD sbd_startblock
; /* 3C: small block depot first big block */
30 DWORD unknown3
[3]; /* 40: unknown */
31 DWORD bbd_list
[109]; /* 4C: big data block list (up to end of sector)*/
33 struct storage_pps_entry
{
34 WCHAR pps_rawname
[32];/* 00: \0 terminated widechar name */
35 WORD pps_sizeofname
; /* 40: namelength in bytes */
36 BYTE pps_type
; /* 42: flags, 1 storage/dir, 2 stream, 5 root */
37 BYTE pps_unknown0
; /* 43: unknown */
38 DWORD pps_prev
; /* 44: previous pps */
39 DWORD pps_next
; /* 48: next pps */
40 DWORD pps_dir
; /* 4C: directory pps */
41 GUID pps_guid
; /* 50: class ID */
42 DWORD pps_unknown1
; /* 60: unknown */
43 FILETIME pps_ft1
; /* 64: filetime1 */
44 FILETIME pps_ft2
; /* 70: filetime2 */
45 DWORD pps_sb
; /* 74: data startblock */
46 DWORD pps_size
; /* 78: datalength. (<0x1000)?small:big blocks*/
47 DWORD pps_unknown2
; /* 7C: unknown */
50 #define STORAGE_CHAINENTRY_FAT 0xfffffffd
51 #define STORAGE_CHAINENTRY_ENDOFCHAIN 0xfffffffe
52 #define STORAGE_CHAINENTRY_FREE 0xffffffff
55 //static const BYTE STORAGE_magic[8] ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};
56 //static const BYTE STORAGE_notmagic[8]={0x0e,0x11,0xfc,0x0d,0xd0,0xcf,0x11,0xe0};
57 //static const BYTE STORAGE_oldmagic[8]={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d};
62 #define SMALLBLOCKS_PER_BIGBLOCK (BIGSIZE/SMALLSIZE)
64 #define READ_HEADER assert(STORAGE_get_big_block(hf,-1,(LPBYTE)&sth));assert(!memcmp(STORAGE_magic,sth.magic,sizeof(STORAGE_magic)));
65 static ICOM_VTABLE(IStorage16
) stvt16
;
66 static ICOM_VTABLE(IStorage16
) *segstvt16
= NULL
;
67 static ICOM_VTABLE(IStream16
) strvt16
;
68 static ICOM_VTABLE(IStream16
) *segstrvt16
= NULL
;
70 /*ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this);*/
71 static void _create_istorage16(LPSTORAGE16
*stg
);
72 static void _create_istream16(LPSTREAM16
*str
);
77 /******************************************************************************
78 * STORAGE_get_big_block [Internal]
80 * Reading OLE compound storage
83 STORAGE_get_big_block(HFILE hf
,int n
,BYTE
*block
) {
85 if (-1==_llseek(hf
,(n
+1)*BIGSIZE
,SEEK_SET
)) {
86 Print(MID_TRACE
, (" seek failed (%ld)\n",GetLastError()));
89 assert((n
+1)*BIGSIZE
==_llseek(hf
,0,SEEK_CUR
));
90 if (BIGSIZE
!=_lread(hf
,block
,BIGSIZE
)) {
91 Print(MID_TRACE
, ("(block size %d): read didn't read (%ld)\n",n
,GetLastError()));
98 /******************************************************************************
99 * STORAGE_put_big_block [INTERNAL]
102 STORAGE_put_big_block(HFILE hf
,int n
,BYTE
*block
) {
104 if (-1==_llseek(hf
,(n
+1)*BIGSIZE
,SEEK_SET
)) {
105 Print(MID_TRACE
, (" seek failed (%ld)\n",GetLastError()));
108 assert((n
+1)*BIGSIZE
==_llseek(hf
,0,SEEK_CUR
));
109 if (BIGSIZE
!=_lwrite(hf
,block
,BIGSIZE
)) {
110 Print(MID_TRACE
, (" write failed (%ld)\n",GetLastError()));
116 /******************************************************************************
117 * STORAGE_get_next_big_blocknr [INTERNAL]
120 STORAGE_get_next_big_blocknr(HFILE hf
,int blocknr
) {
121 INT bbs
[BIGSIZE
/sizeof(INT
)];
122 struct storage_header sth
;
126 assert(blocknr
>>7<sth
.num_of_bbd_blocks
);
127 if (sth
.bbd_list
[blocknr
>>7]==0xffffffff)
129 if (!STORAGE_get_big_block(hf
,sth
.bbd_list
[blocknr
>>7],(LPBYTE
)bbs
))
131 assert(bbs
[blocknr
&0x7f]!=STORAGE_CHAINENTRY_FREE
);
132 return bbs
[blocknr
&0x7f];
135 /******************************************************************************
136 * STORAGE_get_nth_next_big_blocknr [INTERNAL]
139 STORAGE_get_nth_next_big_blocknr(HFILE hf
,int blocknr
,int nr
) {
140 INT bbs
[BIGSIZE
/sizeof(INT
)];
142 struct storage_header sth
;
148 assert((blocknr
>>7)<sth
.num_of_bbd_blocks
);
149 assert(sth
.bbd_list
[blocknr
>>7]!=0xffffffff);
151 /* simple caching... */
152 if (lastblock
!=sth
.bbd_list
[blocknr
>>7]) {
153 assert(STORAGE_get_big_block(hf
,sth
.bbd_list
[blocknr
>>7],(LPBYTE
)bbs
));
154 lastblock
= sth
.bbd_list
[blocknr
>>7];
156 blocknr
= bbs
[blocknr
&0x7f];
161 /******************************************************************************
162 * STORAGE_get_root_pps_entry [Internal]
165 STORAGE_get_root_pps_entry(HFILE hf
,struct storage_pps_entry
*pstde
) {
168 struct storage_pps_entry
*stde
=(struct storage_pps_entry
*)block
;
169 struct storage_header sth
;
172 blocknr
= sth
.root_startblock
;
174 assert(STORAGE_get_big_block(hf
,blocknr
,block
));
176 if (!stde
[i
].pps_sizeofname
)
178 if (stde
[i
].pps_type
==5) {
183 blocknr
=STORAGE_get_next_big_blocknr(hf
,blocknr
);
188 /******************************************************************************
189 * STORAGE_get_small_block [INTERNAL]
192 STORAGE_get_small_block(HFILE hf
,int blocknr
,BYTE
*sblock
) {
195 struct storage_pps_entry root
;
198 assert(STORAGE_get_root_pps_entry(hf
,&root
));
199 bigblocknr
= STORAGE_get_nth_next_big_blocknr(hf
,root
.pps_sb
,blocknr
/SMALLBLOCKS_PER_BIGBLOCK
);
200 assert(bigblocknr
>=0);
201 assert(STORAGE_get_big_block(hf
,bigblocknr
,block
));
203 memcpy(sblock
,((LPBYTE
)block
)+SMALLSIZE
*(blocknr
&(SMALLBLOCKS_PER_BIGBLOCK
-1)),SMALLSIZE
);
207 /******************************************************************************
208 * STORAGE_put_small_block [INTERNAL]
211 STORAGE_put_small_block(HFILE hf
,int blocknr
,BYTE
*sblock
) {
214 struct storage_pps_entry root
;
218 assert(STORAGE_get_root_pps_entry(hf
,&root
));
219 bigblocknr
= STORAGE_get_nth_next_big_blocknr(hf
,root
.pps_sb
,blocknr
/SMALLBLOCKS_PER_BIGBLOCK
);
220 assert(bigblocknr
>=0);
221 assert(STORAGE_get_big_block(hf
,bigblocknr
,block
));
223 memcpy(((LPBYTE
)block
)+SMALLSIZE
*(blocknr
&(SMALLBLOCKS_PER_BIGBLOCK
-1)),sblock
,SMALLSIZE
);
224 assert(STORAGE_put_big_block(hf
,bigblocknr
,block
));
228 /******************************************************************************
229 * STORAGE_get_next_small_blocknr [INTERNAL]
232 STORAGE_get_next_small_blocknr(HFILE hf
,int blocknr
) {
234 LPINT sbd
= (LPINT
)block
;
236 struct storage_header sth
;
240 bigblocknr
= STORAGE_get_nth_next_big_blocknr(hf
,sth
.sbd_startblock
,blocknr
/128);
241 assert(bigblocknr
>=0);
242 assert(STORAGE_get_big_block(hf
,bigblocknr
,block
));
243 assert(sbd
[blocknr
& 127]!=STORAGE_CHAINENTRY_FREE
);
244 return sbd
[blocknr
& (128-1)];
247 /******************************************************************************
248 * STORAGE_get_nth_next_small_blocknr [INTERNAL]
251 STORAGE_get_nth_next_small_blocknr(HFILE hf
,int blocknr
,int nr
) {
254 LPINT sbd
= (LPINT
)block
;
255 struct storage_header sth
;
260 while ((nr
--) && (blocknr
>=0)) {
261 if (lastblocknr
/128!=blocknr
/128) {
263 bigblocknr
= STORAGE_get_nth_next_big_blocknr(hf
,sth
.sbd_startblock
,blocknr
/128);
264 assert(bigblocknr
>=0);
265 assert(STORAGE_get_big_block(hf
,bigblocknr
,block
));
266 lastblocknr
= blocknr
;
268 assert(lastblocknr
>=0);
270 blocknr
=sbd
[blocknr
& (128-1)];
271 assert(blocknr
!=STORAGE_CHAINENTRY_FREE
);
276 /******************************************************************************
277 * STORAGE_get_pps_entry [INTERNAL]
280 STORAGE_get_pps_entry(HFILE hf
,int n
,struct storage_pps_entry
*pstde
) {
283 struct storage_pps_entry
*stde
= (struct storage_pps_entry
*)(((LPBYTE
)block
)+128*(n
&3));
284 struct storage_header sth
;
287 /* we have 4 pps entries per big block */
288 blocknr
= STORAGE_get_nth_next_big_blocknr(hf
,sth
.root_startblock
,n
/4);
290 assert(STORAGE_get_big_block(hf
,blocknr
,block
));
296 /******************************************************************************
297 * STORAGE_put_pps_entry [Internal]
300 STORAGE_put_pps_entry(HFILE hf
,int n
,struct storage_pps_entry
*pstde
) {
303 struct storage_pps_entry
*stde
= (struct storage_pps_entry
*)(((LPBYTE
)block
)+128*(n
&3));
304 struct storage_header sth
;
308 /* we have 4 pps entries per big block */
309 blocknr
= STORAGE_get_nth_next_big_blocknr(hf
,sth
.root_startblock
,n
/4);
311 assert(STORAGE_get_big_block(hf
,blocknr
,block
));
313 assert(STORAGE_put_big_block(hf
,blocknr
,block
));
317 /******************************************************************************
318 * STORAGE_look_for_named_pps [Internal]
321 STORAGE_look_for_named_pps(HFILE hf
,int n
,LPOLESTR name
) {
322 struct storage_pps_entry stde
;
327 if (1!=STORAGE_get_pps_entry(hf
,n
,&stde
))
330 if (!lstrcmpW(name
,stde
.pps_rawname
))
332 if (stde
.pps_prev
!= -1) {
333 ret
=STORAGE_look_for_named_pps(hf
,stde
.pps_prev
,name
);
337 if (stde
.pps_next
!= -1) {
338 ret
=STORAGE_look_for_named_pps(hf
,stde
.pps_next
,name
);
345 /******************************************************************************
346 * STORAGE_dump_pps_entry [Internal]
352 STORAGE_dump_pps_entry(struct storage_pps_entry
*stde
) {
356 WideCharToMultiByte( CP_ACP
, 0, stde
->pps_rawname
, -1, name
, sizeof(name
), NULL
, NULL
);
357 if (!stde
->pps_sizeofname
)
359 Print(MAX_TRACE
, ("name: %s\n",name
));
360 Print(MAX_TRACE
, ("type: %d\n",stde
->pps_type
));
361 Print(MAX_TRACE
, ("prev pps: %ld\n",stde
->pps_prev
));
362 Print(MAX_TRACE
, ("next pps: %ld\n",stde
->pps_next
));
363 Print(MAX_TRACE
, ("dir pps: %ld\n",stde
->pps_dir
));
364 Print(MAX_TRACE
, ("guid: %s\n",PRINT_GUID(&(stde
->pps_guid
))));
365 if (stde
->pps_type
!=2) {
368 RtlTimeToSecondsSince1970(&(stde
->pps_ft1
),&dw
);
370 Print(MAX_TRACE
, ("ts1: %s\n",ctime(&t
)));
371 RtlTimeToSecondsSince1970(&(stde
->pps_ft2
),&dw
);
373 Print(MAX_TRACE
, ("ts2: %s\n",ctime(&t
)));
375 Print(MAX_TRACE
, ("startblock: %ld\n",stde
->pps_sb
));
376 Print(MAX_TRACE
, ("size: %ld\n",stde
->pps_size
));
380 /******************************************************************************
381 * STORAGE_init_storage [INTERNAL]
384 STORAGE_init_storage(HFILE hf
) {
387 struct storage_header
*sth
;
388 struct storage_pps_entry
*stde
;
390 assert(-1!=_llseek(hf
,0,SEEK_SET
));
391 /* block -1 is the storage header */
392 sth
= (struct storage_header
*)block
;
393 memcpy(sth
->magic
,STORAGE_magic
,8);
394 memset(sth
->unknown1
,0,sizeof(sth
->unknown1
));
395 memset(sth
->unknown2
,0,sizeof(sth
->unknown2
));
396 memset(sth
->unknown3
,0,sizeof(sth
->unknown3
));
397 sth
->num_of_bbd_blocks
= 1;
398 sth
->root_startblock
= 1;
399 sth
->sbd_startblock
= 0xffffffff;
400 memset(sth
->bbd_list
,0xff,sizeof(sth
->bbd_list
));
401 sth
->bbd_list
[0] = 0;
402 assert(BIGSIZE
==_lwrite(hf
,block
,BIGSIZE
));
403 /* block 0 is the big block directory */
405 memset(block
,0xff,sizeof(block
)); /* mark all blocks as free */
406 bbs
[0]=STORAGE_CHAINENTRY_ENDOFCHAIN
; /* for this block */
407 bbs
[1]=STORAGE_CHAINENTRY_ENDOFCHAIN
; /* for directory entry */
408 assert(BIGSIZE
==_lwrite(hf
,block
,BIGSIZE
));
409 /* block 1 is the root directory entry */
410 memset(block
,0x00,sizeof(block
));
411 stde
= (struct storage_pps_entry
*)block
;
412 MultiByteToWideChar( CP_ACP
, 0, "RootEntry", -1, stde
->pps_rawname
,
413 sizeof(stde
->pps_rawname
)/sizeof(WCHAR
));
414 stde
->pps_sizeofname
= (lstrlenW(stde
->pps_rawname
)+1) * sizeof(WCHAR
);
419 stde
->pps_sb
= 0xffffffff;
421 assert(BIGSIZE
==_lwrite(hf
,block
,BIGSIZE
));
425 /******************************************************************************
426 * STORAGE_set_big_chain [Internal]
429 STORAGE_set_big_chain(HFILE hf
,int blocknr
,INT type
) {
431 LPINT bbd
= (LPINT
)block
;
432 int nextblocknr
,bigblocknr
;
433 struct storage_header sth
;
436 assert(blocknr
!=type
);
438 bigblocknr
= sth
.bbd_list
[blocknr
/128];
439 assert(bigblocknr
>=0);
440 assert(STORAGE_get_big_block(hf
,bigblocknr
,block
));
442 nextblocknr
= bbd
[blocknr
&(128-1)];
443 bbd
[blocknr
&(128-1)] = type
;
446 assert(STORAGE_put_big_block(hf
,bigblocknr
,block
));
447 type
= STORAGE_CHAINENTRY_FREE
;
448 blocknr
= nextblocknr
;
453 /******************************************************************************
454 * STORAGE_set_small_chain [Internal]
457 STORAGE_set_small_chain(HFILE hf
,int blocknr
,INT type
) {
459 LPINT sbd
= (LPINT
)block
;
460 int lastblocknr
,nextsmallblocknr
,bigblocknr
;
461 struct storage_header sth
;
465 assert(blocknr
!=type
);
466 lastblocknr
=-129;bigblocknr
=-2;
468 /* cache block ... */
469 if (lastblocknr
/128!=blocknr
/128) {
470 bigblocknr
= STORAGE_get_nth_next_big_blocknr(hf
,sth
.sbd_startblock
,blocknr
/128);
471 assert(bigblocknr
>=0);
472 assert(STORAGE_get_big_block(hf
,bigblocknr
,block
));
474 lastblocknr
= blocknr
;
475 nextsmallblocknr
= sbd
[blocknr
&(128-1)];
476 sbd
[blocknr
&(128-1)] = type
;
477 assert(STORAGE_put_big_block(hf
,bigblocknr
,block
));
480 type
= STORAGE_CHAINENTRY_FREE
;
481 blocknr
= nextsmallblocknr
;
486 /******************************************************************************
487 * STORAGE_get_free_big_blocknr [Internal]
490 STORAGE_get_free_big_blocknr(HFILE hf
) {
492 LPINT sbd
= (LPINT
)block
;
493 int lastbigblocknr
,i
,curblock
,bigblocknr
;
494 struct storage_header sth
;
499 bigblocknr
= sth
.bbd_list
[curblock
];
500 while (curblock
<sth
.num_of_bbd_blocks
) {
501 assert(bigblocknr
>=0);
502 assert(STORAGE_get_big_block(hf
,bigblocknr
,block
));
504 if (sbd
[i
]==STORAGE_CHAINENTRY_FREE
) {
505 sbd
[i
] = STORAGE_CHAINENTRY_ENDOFCHAIN
;
506 assert(STORAGE_put_big_block(hf
,bigblocknr
,block
));
507 memset(block
,0x42,sizeof(block
));
508 assert(STORAGE_put_big_block(hf
,i
+curblock
*128,block
));
509 return i
+curblock
*128;
511 lastbigblocknr
= bigblocknr
;
512 bigblocknr
= sth
.bbd_list
[++curblock
];
514 bigblocknr
= curblock
*128;
515 /* since we have marked all blocks from 0 up to curblock*128-1
516 * the next free one is curblock*128, where we happily put our
517 * next large block depot.
519 memset(block
,0xff,sizeof(block
));
520 /* mark the block allocated and returned by this function */
521 sbd
[1] = STORAGE_CHAINENTRY_ENDOFCHAIN
;
522 assert(STORAGE_put_big_block(hf
,bigblocknr
,block
));
524 /* if we had a bbd block already (mostlikely) we need
525 * to link the new one into the chain
527 if (lastbigblocknr
!=-1)
528 assert(STORAGE_set_big_chain(hf
,lastbigblocknr
,bigblocknr
));
529 sth
.bbd_list
[curblock
]=bigblocknr
;
530 sth
.num_of_bbd_blocks
++;
531 assert(sth
.num_of_bbd_blocks
==curblock
+1);
532 assert(STORAGE_put_big_block(hf
,-1,(LPBYTE
)&sth
));
534 /* Set the end of the chain for the bigblockdepots */
535 assert(STORAGE_set_big_chain(hf
,bigblocknr
,STORAGE_CHAINENTRY_ENDOFCHAIN
));
536 /* add 1, for the first entry is used for the additional big block
537 * depot. (means we already used bigblocknr) */
538 memset(block
,0x42,sizeof(block
));
539 /* allocate this block (filled with 0x42) */
540 assert(STORAGE_put_big_block(hf
,bigblocknr
+1,block
));
545 /******************************************************************************
546 * STORAGE_get_free_small_blocknr [Internal]
549 STORAGE_get_free_small_blocknr(HFILE hf
) {
551 LPINT sbd
= (LPINT
)block
;
552 int lastbigblocknr
,newblocknr
,i
,curblock
,bigblocknr
;
553 struct storage_pps_entry root
;
554 struct storage_header sth
;
557 bigblocknr
= sth
.sbd_startblock
;
561 while (bigblocknr
>=0) {
562 if (!STORAGE_get_big_block(hf
,bigblocknr
,block
))
565 if (sbd
[i
]==STORAGE_CHAINENTRY_FREE
) {
566 sbd
[i
]=STORAGE_CHAINENTRY_ENDOFCHAIN
;
567 newblocknr
= i
+curblock
*128;
572 lastbigblocknr
= bigblocknr
;
573 bigblocknr
= STORAGE_get_next_big_blocknr(hf
,bigblocknr
);
576 if (newblocknr
==-1) {
577 bigblocknr
= STORAGE_get_free_big_blocknr(hf
);
581 memset(block
,0xff,sizeof(block
));
582 sbd
[0]=STORAGE_CHAINENTRY_ENDOFCHAIN
;
583 if (!STORAGE_put_big_block(hf
,bigblocknr
,block
))
585 if (lastbigblocknr
==-1) {
586 sth
.sbd_startblock
= bigblocknr
;
587 if (!STORAGE_put_big_block(hf
,-1,(LPBYTE
)&sth
)) /* need to write it */
590 if (!STORAGE_set_big_chain(hf
,lastbigblocknr
,bigblocknr
))
593 if (!STORAGE_set_big_chain(hf
,bigblocknr
,STORAGE_CHAINENTRY_ENDOFCHAIN
))
595 newblocknr
= curblock
*128;
597 /* allocate enough big blocks for storing the allocated small block */
598 if (!STORAGE_get_root_pps_entry(hf
,&root
))
603 lastbigblocknr
= STORAGE_get_nth_next_big_blocknr(hf
,root
.pps_sb
,(root
.pps_size
-1)/BIGSIZE
);
604 while (root
.pps_size
< (newblocknr
*SMALLSIZE
+SMALLSIZE
-1)) {
605 /* we need to allocate more stuff */
606 bigblocknr
= STORAGE_get_free_big_blocknr(hf
);
610 if (root
.pps_sb
==-1) {
611 root
.pps_sb
= bigblocknr
;
612 root
.pps_size
+= BIGSIZE
;
614 if (!STORAGE_set_big_chain(hf
,lastbigblocknr
,bigblocknr
))
616 root
.pps_size
+= BIGSIZE
;
618 lastbigblocknr
= bigblocknr
;
620 if (!STORAGE_set_big_chain(hf
,lastbigblocknr
,STORAGE_CHAINENTRY_ENDOFCHAIN
))
622 if (!STORAGE_put_pps_entry(hf
,0,&root
))
627 /******************************************************************************
628 * STORAGE_get_free_pps_entry [Internal]
631 STORAGE_get_free_pps_entry(HFILE hf
) {
632 int blocknr
,i
,curblock
,lastblocknr
;
634 struct storage_pps_entry
*stde
= (struct storage_pps_entry
*)block
;
635 struct storage_header sth
;
638 blocknr
= sth
.root_startblock
;
642 if (!STORAGE_get_big_block(hf
,blocknr
,block
))
645 if (stde
[i
].pps_sizeofname
==0) /* free */
647 lastblocknr
= blocknr
;
648 blocknr
= STORAGE_get_next_big_blocknr(hf
,blocknr
);
651 assert(blocknr
==STORAGE_CHAINENTRY_ENDOFCHAIN
);
652 blocknr
= STORAGE_get_free_big_blocknr(hf
);
653 /* sth invalidated */
657 if (!STORAGE_set_big_chain(hf
,lastblocknr
,blocknr
))
659 if (!STORAGE_set_big_chain(hf
,blocknr
,STORAGE_CHAINENTRY_ENDOFCHAIN
))
661 memset(block
,0,sizeof(block
));
662 STORAGE_put_big_block(hf
,blocknr
,block
);
666 /* --- IStream32 implementation */
670 /* IUnknown fields */
671 ICOM_VFIELD(IStream
);
673 /* IStream32 fields */
674 struct storage_pps_entry stde
;
677 ULARGE_INTEGER offset
;
680 /*****************************************************************************
681 * IStream32_QueryInterface [VTABLE]
683 HRESULT WINAPI
IStream_fnQueryInterface(
684 IStream
* iface
,REFIID refiid
,LPVOID
*obj
686 ICOM_THIS(IStream32Impl
,iface
);
688 Print(MAX_TRACE
, ("(%p)->(%s,%p)\n",This
,debugstr_guid(refiid
),obj
));
689 if (!memcmp(&IID_IUnknown
,refiid
,sizeof(IID_IUnknown
))) {
693 return OLE_E_ENUM_NOMORE
;
697 /******************************************************************************
698 * IStream32_AddRef [VTABLE]
700 ULONG WINAPI
IStream_fnAddRef(IStream
* iface
) {
701 ICOM_THIS(IStream32Impl
,iface
);
702 return ++(This
->ref
);
705 /******************************************************************************
706 * IStream32_Release [VTABLE]
708 ULONG WINAPI
IStream_fnRelease(IStream
* iface
) {
710 ICOM_THIS(IStream32Impl
,iface
);
711 FlushFileBuffers(This
->hf
);
714 CloseHandle(This
->hf
);
726 /******************************************************************************
727 * Storage API functions
730 /******************************************************************************
731 * StgCreateDocFile16 [STORAGE.1]
733 HRESULT WINAPI
StgCreateDocFile16(
734 LPCOLESTR16 pwcsName
,DWORD grfMode
,DWORD reserved
,IStorage16
**ppstgOpen
740 /******************************************************************************
741 * StgIsStorageFile16 [STORAGE.5]
743 HRESULT WINAPI
StgIsStorageFile16(LPCOLESTR16 fn
) {
748 /******************************************************************************
749 * StgIsStorageFile [OLE32.146]
752 StgIsStorageFile(LPCOLESTR fn
)
755 LPOLESTR16 xfn
= HEAP_strdupWtoA(GetProcessHeap(),0,fn
);
756 HRESULT ret
= StgIsStorageFile16(xfn
);
758 HeapFree(GetProcessHeap(),0,xfn
);
767 /******************************************************************************
768 * StgOpenStorage16 [STORAGE.3]
770 HRESULT WINAPI
StgOpenStorage16(
771 LPCOLESTR16 pwcsName
,IStorage16
*pstgPriority
,DWORD grfMode
,
772 SNB16 snbExclude
,DWORD reserved
, IStorage16
**ppstgOpen