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