xref: /reactos/dll/win32/ole32/storage32.h (revision da5f10af)
1 /*
2  * Compound Storage (32 bit version)
3  *
4  * Implemented using the documentation of the LAOLA project at
5  * <URL:http://wwwwbs.cs.tu-berlin.de/~schwartz/pmh/index.html>
6  * (Thanks to Martin Schwartz <schwartz@cs.tu-berlin.de>)
7  *
8  * This include file contains definitions of types and function
9  * prototypes that are used in the many files implementing the
10  * storage functionality
11  *
12  * Copyright 1998,1999 Francis Beaudet
13  * Copyright 1998,1999 Thuy Nguyen
14  * Copyright 2010 Vincent Povirk for CodeWeavers
15  *
16  * This library is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU Lesser General Public
18  * License as published by the Free Software Foundation; either
19  * version 2.1 of the License, or (at your option) any later version.
20  *
21  * This library is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * Lesser General Public License for more details.
25  *
26  * You should have received a copy of the GNU Lesser General Public
27  * License along with this library; if not, write to the Free Software
28  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29  */
30 
31 #ifndef __STORAGE32_H__
32 #define __STORAGE32_H__
33 
34 /*
35  * Definitions for the file format offsets.
36  */
37 static const ULONG OFFSET_MINORVERSION       = 0x00000018;
38 static const ULONG OFFSET_MAJORVERSION       = 0x0000001a;
39 static const ULONG OFFSET_BYTEORDERMARKER    = 0x0000001c;
40 static const ULONG OFFSET_BIGBLOCKSIZEBITS   = 0x0000001e;
41 static const ULONG OFFSET_SMALLBLOCKSIZEBITS = 0x00000020;
42 static const ULONG OFFSET_DIRSECTORCOUNT     = 0x00000028;
43 static const ULONG OFFSET_BBDEPOTCOUNT	     = 0x0000002C;
44 static const ULONG OFFSET_ROOTSTARTBLOCK     = 0x00000030;
45 static const ULONG OFFSET_TRANSACTIONSIG     = 0x00000034;
46 static const ULONG OFFSET_SMALLBLOCKLIMIT    = 0x00000038;
47 static const ULONG OFFSET_SBDEPOTSTART	     = 0x0000003C;
48 static const ULONG OFFSET_SBDEPOTCOUNT       = 0x00000040;
49 static const ULONG OFFSET_EXTBBDEPOTSTART    = 0x00000044;
50 static const ULONG OFFSET_EXTBBDEPOTCOUNT    = 0x00000048;
51 static const ULONG OFFSET_BBDEPOTSTART	     = 0x0000004C;
52 static const ULONG OFFSET_PS_NAME            = 0x00000000;
53 static const ULONG OFFSET_PS_NAMELENGTH	     = 0x00000040;
54 static const ULONG OFFSET_PS_STGTYPE         = 0x00000042;
55 static const ULONG OFFSET_PS_LEFTCHILD       = 0x00000044;
56 static const ULONG OFFSET_PS_RIGHTCHILD      = 0x00000048;
57 static const ULONG OFFSET_PS_DIRROOT	     = 0x0000004C;
58 static const ULONG OFFSET_PS_GUID            = 0x00000050;
59 static const ULONG OFFSET_PS_CTIMELOW        = 0x00000064;
60 static const ULONG OFFSET_PS_CTIMEHIGH       = 0x00000068;
61 static const ULONG OFFSET_PS_MTIMELOW        = 0x0000006C;
62 static const ULONG OFFSET_PS_MTIMEHIGH       = 0x00000070;
63 static const ULONG OFFSET_PS_STARTBLOCK	     = 0x00000074;
64 static const ULONG OFFSET_PS_SIZE	     = 0x00000078;
65 static const ULONG OFFSET_PS_SIZE_HIGH	     = 0x0000007C;
66 static const WORD  DEF_BIG_BLOCK_SIZE_BITS   = 0x0009;
67 static const WORD  MIN_BIG_BLOCK_SIZE_BITS   = 0x0009;
68 static const WORD  MAX_BIG_BLOCK_SIZE_BITS   = 0x000c;
69 static const WORD  DEF_SMALL_BLOCK_SIZE_BITS = 0x0006;
70 static const WORD  DEF_BIG_BLOCK_SIZE        = 0x0200;
71 static const WORD  DEF_SMALL_BLOCK_SIZE      = 0x0040;
72 static const ULONG BLOCK_FIRST_SPECIAL       = 0xFFFFFFFB;
73 static const ULONG BLOCK_EXTBBDEPOT          = 0xFFFFFFFC;
74 static const ULONG BLOCK_SPECIAL             = 0xFFFFFFFD;
75 static const ULONG BLOCK_END_OF_CHAIN        = 0xFFFFFFFE;
76 static const ULONG BLOCK_UNUSED              = 0xFFFFFFFF;
77 static const ULONG DIRENTRY_NULL             = 0xFFFFFFFF;
78 
79 #define DIRENTRY_NAME_MAX_LEN    0x20
80 #define DIRENTRY_NAME_BUFFER_LEN 0x40
81 
82 #define RAW_DIRENTRY_SIZE 0x00000080
83 
84 #define HEADER_SIZE 512
85 
86 #define MIN_BIG_BLOCK_SIZE 0x200
87 #define MAX_BIG_BLOCK_SIZE 0x1000
88 
89 /*
90  * Type of child entry link
91  */
92 #define DIRENTRY_RELATION_PREVIOUS 0
93 #define DIRENTRY_RELATION_NEXT     1
94 #define DIRENTRY_RELATION_DIR      2
95 
96 /*
97  * type constant used in files for the root storage
98  */
99 #define STGTY_ROOT 0x05
100 
101 #define COUNT_BBDEPOTINHEADER    109
102 
103 /* FIXME: This value is stored in the header, but we hard-code it to 0x1000. */
104 #define LIMIT_TO_USE_SMALL_BLOCK 0x1000
105 
106 #define STGM_ACCESS_MODE(stgm)   ((stgm)&0x0000f)
107 #define STGM_SHARE_MODE(stgm)    ((stgm)&0x000f0)
108 #define STGM_CREATE_MODE(stgm)   ((stgm)&0x0f000)
109 
110 #define STGM_KNOWN_FLAGS (0xf0ff | \
111      STGM_TRANSACTED | STGM_CONVERT | STGM_PRIORITY | STGM_NOSCRATCH | \
112      STGM_NOSNAPSHOT | STGM_DIRECT_SWMR | STGM_DELETEONRELEASE | STGM_SIMPLE)
113 
114 /*
115  * Forward declarations of all the structures used by the storage
116  * module.
117  */
118 typedef struct StorageBaseImpl     StorageBaseImpl;
119 typedef struct StorageBaseImplVtbl StorageBaseImplVtbl;
120 typedef struct StorageImpl         StorageImpl;
121 typedef struct BlockChainStream      BlockChainStream;
122 typedef struct SmallBlockChainStream SmallBlockChainStream;
123 typedef struct IEnumSTATSTGImpl      IEnumSTATSTGImpl;
124 typedef struct DirEntry              DirEntry;
125 typedef struct StgStreamImpl         StgStreamImpl;
126 
127 /*
128  * A reference to a directory entry in the file or a transacted cache.
129  */
130 typedef ULONG DirRef;
131 
132 /*
133  * This utility structure is used to read/write the information in a directory
134  * entry.
135  */
136 struct DirEntry
137 {
138   WCHAR	         name[DIRENTRY_NAME_MAX_LEN];
139   WORD	         sizeOfNameString;
140   BYTE	         stgType;
141   DirRef         leftChild;
142   DirRef         rightChild;
143   DirRef         dirRootEntry;
144   GUID           clsid;
145   FILETIME       ctime;
146   FILETIME       mtime;
147   ULONG          startingBlock;
148   ULARGE_INTEGER size;
149 };
150 
151 HRESULT FileLockBytesImpl_Construct(HANDLE hFile, DWORD openFlags, LPCWSTR pwcsName, ILockBytes **pLockBytes) DECLSPEC_HIDDEN;
152 
153 /*************************************************************************
154  * Ole Convert support
155  */
156 
157 HRESULT STORAGE_CreateOleStream(IStorage*, DWORD) DECLSPEC_HIDDEN;
158 HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName) DECLSPEC_HIDDEN;
159 
160 enum swmr_mode
161 {
162   SWMR_None,
163   SWMR_Writer,
164   SWMR_Reader
165 };
166 
167 /****************************************************************************
168  * StorageBaseImpl definitions.
169  *
170  * This structure defines the base information contained in all implementations
171  * of IStorage contained in this file storage implementation.
172  *
173  * In OOP terms, this is the base class for all the IStorage implementations
174  * contained in this file.
175  */
176 struct StorageBaseImpl
177 {
178   IStorage IStorage_iface;
179   IPropertySetStorage IPropertySetStorage_iface; /* interface for adding a properties stream */
180   IDirectWriterLock IDirectWriterLock_iface;
181   LONG ref;
182 
183   /*
184    * Stream tracking list
185    */
186 
187   struct list strmHead;
188 
189   /*
190    * Storage tracking list
191    */
192   struct list storageHead;
193 
194   /*
195    * TRUE if this object has been invalidated
196    */
197   BOOL reverted;
198 
199   /*
200    * Index of the directory entry of this storage
201    */
202   DirRef storageDirEntry;
203 
204   /*
205    * virtual methods.
206    */
207   const StorageBaseImplVtbl *baseVtbl;
208 
209   /*
210    * flags that this storage was opened or created with
211    */
212   DWORD openFlags;
213 
214   /*
215    * State bits appear to only be preserved while running. No in the stream
216    */
217   DWORD stateBits;
218 
219   BOOL  create;     /* Was the storage created or opened.
220                        The behaviour of STGM_SIMPLE depends on this */
221   /*
222    * If this storage was opened in transacted mode, the object that implements
223    * the transacted snapshot or cache.
224    */
225   StorageBaseImpl *transactedChild;
226   enum swmr_mode lockingrole;
227 };
228 
229 /* virtual methods for StorageBaseImpl objects */
230 struct StorageBaseImplVtbl {
231   void (*Destroy)(StorageBaseImpl*);
232   void (*Invalidate)(StorageBaseImpl*);
233   HRESULT (*Flush)(StorageBaseImpl*);
234   HRESULT (*GetFilename)(StorageBaseImpl*,LPWSTR*);
235   HRESULT (*CreateDirEntry)(StorageBaseImpl*,const DirEntry*,DirRef*);
236   HRESULT (*WriteDirEntry)(StorageBaseImpl*,DirRef,const DirEntry*);
237   HRESULT (*ReadDirEntry)(StorageBaseImpl*,DirRef,DirEntry*);
238   HRESULT (*DestroyDirEntry)(StorageBaseImpl*,DirRef);
239   HRESULT (*StreamReadAt)(StorageBaseImpl*,DirRef,ULARGE_INTEGER,ULONG,void*,ULONG*);
240   HRESULT (*StreamWriteAt)(StorageBaseImpl*,DirRef,ULARGE_INTEGER,ULONG,const void*,ULONG*);
241   HRESULT (*StreamSetSize)(StorageBaseImpl*,DirRef,ULARGE_INTEGER);
242   HRESULT (*StreamLink)(StorageBaseImpl*,DirRef,DirRef);
243   HRESULT (*GetTransactionSig)(StorageBaseImpl*,ULONG*,BOOL);
244   HRESULT (*SetTransactionSig)(StorageBaseImpl*,ULONG);
245   HRESULT (*LockTransaction)(StorageBaseImpl*,BOOL);
246   HRESULT (*UnlockTransaction)(StorageBaseImpl*,BOOL);
247 };
248 
249 static inline void StorageBaseImpl_Destroy(StorageBaseImpl *This)
250 {
251   This->baseVtbl->Destroy(This);
252 }
253 
254 static inline void StorageBaseImpl_Invalidate(StorageBaseImpl *This)
255 {
256   This->baseVtbl->Invalidate(This);
257 }
258 
259 static inline HRESULT StorageBaseImpl_Flush(StorageBaseImpl *This)
260 {
261   return This->baseVtbl->Flush(This);
262 }
263 
264 static inline HRESULT StorageBaseImpl_GetFilename(StorageBaseImpl *This, LPWSTR *result)
265 {
266   return This->baseVtbl->GetFilename(This, result);
267 }
268 
269 static inline HRESULT StorageBaseImpl_CreateDirEntry(StorageBaseImpl *This,
270   const DirEntry *newData, DirRef *index)
271 {
272   return This->baseVtbl->CreateDirEntry(This, newData, index);
273 }
274 
275 static inline HRESULT StorageBaseImpl_WriteDirEntry(StorageBaseImpl *This,
276   DirRef index, const DirEntry *data)
277 {
278   return This->baseVtbl->WriteDirEntry(This, index, data);
279 }
280 
281 static inline HRESULT StorageBaseImpl_ReadDirEntry(StorageBaseImpl *This,
282   DirRef index, DirEntry *data)
283 {
284   return This->baseVtbl->ReadDirEntry(This, index, data);
285 }
286 
287 static inline HRESULT StorageBaseImpl_DestroyDirEntry(StorageBaseImpl *This,
288   DirRef index)
289 {
290   return This->baseVtbl->DestroyDirEntry(This, index);
291 }
292 
293 /* Read up to size bytes from this directory entry's stream at the given offset. */
294 static inline HRESULT StorageBaseImpl_StreamReadAt(StorageBaseImpl *This,
295   DirRef index, ULARGE_INTEGER offset, ULONG size, void *buffer, ULONG *bytesRead)
296 {
297   return This->baseVtbl->StreamReadAt(This, index, offset, size, buffer, bytesRead);
298 }
299 
300 /* Write size bytes to this directory entry's stream at the given offset,
301  * growing the stream if necessary. */
302 static inline HRESULT StorageBaseImpl_StreamWriteAt(StorageBaseImpl *This,
303   DirRef index, ULARGE_INTEGER offset, ULONG size, const void *buffer, ULONG *bytesWritten)
304 {
305   return This->baseVtbl->StreamWriteAt(This, index, offset, size, buffer, bytesWritten);
306 }
307 
308 static inline HRESULT StorageBaseImpl_StreamSetSize(StorageBaseImpl *This,
309   DirRef index, ULARGE_INTEGER newsize)
310 {
311   return This->baseVtbl->StreamSetSize(This, index, newsize);
312 }
313 
314 /* Make dst point to the same stream that src points to. Other stream operations
315  * will not work properly for entries that point to the same stream, so this
316  * must be a very temporary state, and only one entry pointing to a given stream
317  * may be reachable at any given time. */
318 static inline HRESULT StorageBaseImpl_StreamLink(StorageBaseImpl *This,
319   DirRef dst, DirRef src)
320 {
321   return This->baseVtbl->StreamLink(This, dst, src);
322 }
323 
324 static inline HRESULT StorageBaseImpl_GetTransactionSig(StorageBaseImpl *This,
325   ULONG* result, BOOL refresh)
326 {
327   return This->baseVtbl->GetTransactionSig(This, result, refresh);
328 }
329 
330 static inline HRESULT StorageBaseImpl_SetTransactionSig(StorageBaseImpl *This,
331   ULONG value)
332 {
333   return This->baseVtbl->SetTransactionSig(This, value);
334 }
335 
336 static inline HRESULT StorageBaseImpl_LockTransaction(StorageBaseImpl *This, BOOL write)
337 {
338   return This->baseVtbl->LockTransaction(This, write);
339 }
340 
341 static inline HRESULT StorageBaseImpl_UnlockTransaction(StorageBaseImpl *This, BOOL write)
342 {
343   return This->baseVtbl->UnlockTransaction(This, write);
344 }
345 
346 /****************************************************************************
347  * StorageBaseImpl stream list handlers
348  */
349 
350 void StorageBaseImpl_AddStream(StorageBaseImpl * stg, StgStreamImpl * strm) DECLSPEC_HIDDEN;
351 void StorageBaseImpl_RemoveStream(StorageBaseImpl * stg, StgStreamImpl * strm) DECLSPEC_HIDDEN;
352 
353 /* Number of BlockChainStream objects to cache in a StorageImpl */
354 #define BLOCKCHAIN_CACHE_SIZE 4
355 
356 /****************************************************************************
357  * StorageImpl definitions.
358  *
359  * This implementation of the IStorage interface represents a root
360  * storage. Basically, a document file.
361  */
362 struct StorageImpl
363 {
364   struct StorageBaseImpl base;
365 
366   /*
367    * File header
368    */
369   WORD  bigBlockSizeBits;
370   WORD  smallBlockSizeBits;
371   ULONG bigBlockSize;
372   ULONG smallBlockSize;
373   ULONG bigBlockDepotCount;
374   ULONG rootStartBlock;
375   ULONG smallBlockLimit;
376   ULONG smallBlockDepotStart;
377   ULONG extBigBlockDepotStart;
378   ULONG *extBigBlockDepotLocations;
379   ULONG extBigBlockDepotLocationsSize;
380   ULONG extBigBlockDepotCount;
381   ULONG bigBlockDepotStart[COUNT_BBDEPOTINHEADER];
382   ULONG transactionSig;
383 
384   ULONG extBlockDepotCached[MAX_BIG_BLOCK_SIZE / 4];
385   ULONG indexExtBlockDepotCached;
386 
387   ULONG blockDepotCached[MAX_BIG_BLOCK_SIZE / 4];
388   ULONG indexBlockDepotCached;
389   ULONG prevFreeBlock;
390 
391   /* All small blocks before this one are known to be in use. */
392   ULONG firstFreeSmallBlock;
393 
394   /*
395    * Abstraction of the big block chains for the chains of the header.
396    */
397   BlockChainStream* rootBlockChain;
398   BlockChainStream* smallBlockDepotChain;
399   BlockChainStream* smallBlockRootChain;
400 
401   /* Cache of block chain streams objects for directory entries */
402   BlockChainStream* blockChainCache[BLOCKCHAIN_CACHE_SIZE];
403   UINT blockChainToEvict;
404 
405   ULONG locks_supported;
406 
407   ILockBytes* lockBytes;
408 
409   ULONG locked_bytes[8];
410 };
411 
412 /****************************************************************************
413  * StgStreamImpl definitions.
414  *
415  * This class implements the IStream interface and represents a stream
416  * located inside a storage object.
417  */
418 struct StgStreamImpl
419 {
420   IStream IStream_iface;
421   LONG ref;
422 
423   /*
424    * We are an entry in the storage object's stream handler list
425    */
426   struct list StrmListEntry;
427 
428   /*
429    * Storage that is the parent(owner) of the stream
430    */
431   StorageBaseImpl* parentStorage;
432 
433   /*
434    * Access mode of this stream.
435    */
436   DWORD grfMode;
437 
438   /*
439    * Index of the directory entry that owns (points to) this stream.
440    */
441   DirRef             dirEntry;
442 
443   /*
444    * This is the current position of the cursor in the stream
445    */
446   ULARGE_INTEGER     currentPosition;
447 };
448 
449 static inline StgStreamImpl *impl_from_IStream( IStream *iface )
450 {
451     return CONTAINING_RECORD(iface, StgStreamImpl, IStream_iface);
452 }
453 
454 /*
455  * Method definition for the StgStreamImpl class.
456  */
457 StgStreamImpl* StgStreamImpl_Construct(
458 		StorageBaseImpl* parentStorage,
459     DWORD            grfMode,
460     DirRef           dirEntry) DECLSPEC_HIDDEN;
461 
462 
463 /* Range lock constants.
464  *
465  * The storage format reserves the region from 0x7fffff00-0x7fffffff for
466  * locking and synchronization. Because it reserves the entire block containing
467  * that range, and the minimum block size is 512 bytes, 0x7ffffe00-0x7ffffeff
468  * also cannot be used for any other purpose.
469  * Unfortunately, the spec doesn't say which bytes
470  * within that range are used, and for what. These are guesses based on testing.
471  * In particular, ends of ranges may be wrong.
472 
473  0x0 through 0x57: Unknown. Causes read-only exclusive opens to fail.
474  0x58 through 0x6b: Priority mode.
475  0x6c through 0x7f: No snapshot mode.
476  0x80: Commit lock.
477  0x81 through 0x91: Priority mode, again. Not sure why it uses two regions.
478  0x92: Lock-checking lock. Held while opening so ranges can be tested without
479   causing spurious failures if others try to grab or test those ranges at the
480   same time.
481  0x93 through 0xa6: Read mode.
482  0xa7 through 0xba: Write mode.
483  0xbb through 0xce: Deny read.
484  0xcf through 0xe2: Deny write.
485  0xe2 through 0xff: Unknown. Causes read-only exclusive opens to fail.
486 */
487 
488 #define RANGELOCK_UNK1_FIRST            0x7ffffe00
489 #define RANGELOCK_UNK1_LAST             0x7fffff57
490 #define RANGELOCK_PRIORITY1_FIRST       0x7fffff58
491 #define RANGELOCK_PRIORITY1_LAST        0x7fffff6b
492 #define RANGELOCK_NOSNAPSHOT_FIRST      0x7fffff6c
493 #define RANGELOCK_NOSNAPSHOT_LAST       0x7fffff7f
494 #define RANGELOCK_COMMIT                0x7fffff80
495 #define RANGELOCK_PRIORITY2_FIRST       0x7fffff81
496 #define RANGELOCK_PRIORITY2_LAST        0x7fffff91
497 #define RANGELOCK_CHECKLOCKS            0x7fffff92
498 #define RANGELOCK_READ_FIRST            0x7fffff93
499 #define RANGELOCK_READ_LAST             0x7fffffa6
500 #define RANGELOCK_WRITE_FIRST           0x7fffffa7
501 #define RANGELOCK_WRITE_LAST            0x7fffffba
502 #define RANGELOCK_DENY_READ_FIRST       0x7fffffbb
503 #define RANGELOCK_DENY_READ_LAST        0x7fffffce
504 #define RANGELOCK_DENY_WRITE_FIRST      0x7fffffcf
505 #define RANGELOCK_DENY_WRITE_LAST       0x7fffffe2
506 #define RANGELOCK_UNK2_FIRST            0x7fffffe3
507 #define RANGELOCK_UNK2_LAST             0x7fffffff
508 #define RANGELOCK_TRANSACTION_FIRST     RANGELOCK_COMMIT
509 #define RANGELOCK_TRANSACTION_LAST      RANGELOCK_CHECKLOCKS
510 #define RANGELOCK_FIRST                 RANGELOCK_UNK1_FIRST
511 #define RANGELOCK_LAST                  RANGELOCK_UNK2_LAST
512 
513 /* internal value for LockRegion/UnlockRegion */
514 #define WINE_LOCK_READ                  0x80000000
515 
516 
517 /******************************************************************************
518  * Endian conversion macros
519  */
520 #ifdef WORDS_BIGENDIAN
521 
522 #ifndef htole32
523 #define htole32(x) RtlUlongByteSwap(x)
524 #endif
525 #ifndef htole16
526 #define htole16(x) RtlUshortByteSwap(x)
527 #endif
528 #define lendian32toh(x) RtlUlongByteSwap(x)
529 #define lendian16toh(x) RtlUshortByteSwap(x)
530 
531 #else
532 
533 #ifndef htole32
534 #define htole32(x) (x)
535 #endif
536 #ifndef htole16
537 #define htole16(x) (x)
538 #endif
539 #define lendian32toh(x) (x)
540 #define lendian16toh(x) (x)
541 
542 #endif
543 
544 /******************************************************************************
545  * The StorageUtl_ functions are miscellaneous utility functions. Most of which
546  * are abstractions used to read values from file buffers without having to
547  * worry about bit order
548  */
549 void StorageUtl_ReadWord(const BYTE* buffer, ULONG offset, WORD* value) DECLSPEC_HIDDEN;
550 void StorageUtl_WriteWord(BYTE* buffer, ULONG offset, WORD value) DECLSPEC_HIDDEN;
551 void StorageUtl_ReadDWord(const BYTE* buffer, ULONG offset, DWORD* value) DECLSPEC_HIDDEN;
552 void StorageUtl_WriteDWord(BYTE* buffer, ULONG offset, DWORD value) DECLSPEC_HIDDEN;
553 void StorageUtl_ReadULargeInteger(const BYTE* buffer, ULONG offset,
554  ULARGE_INTEGER* value) DECLSPEC_HIDDEN;
555 void StorageUtl_WriteULargeInteger(BYTE* buffer, ULONG offset,
556  const ULARGE_INTEGER *value) DECLSPEC_HIDDEN;
557 void StorageUtl_ReadGUID(const BYTE* buffer, ULONG offset, GUID* value) DECLSPEC_HIDDEN;
558 void StorageUtl_WriteGUID(BYTE* buffer, ULONG offset, const GUID* value) DECLSPEC_HIDDEN;
559 void StorageUtl_CopyDirEntryToSTATSTG(StorageBaseImpl *storage,STATSTG* destination,
560  const DirEntry* source, int statFlags) DECLSPEC_HIDDEN;
561 
562 
563 #endif /* __STORAGE32_H__ */
564