Windows的复合文件技术

本文介绍复合文件的基本概念、结构及特点,并提供了一个使用VC6环境下复合文件操作的示例代码,帮助读者理解复合文件的存储原理及其在Microsoft Office文档中的应用。
      今天初步学习了复合文件的一些知识,对于该知识点,由于涉及COM的一些原理,暂时还不理解,这个文档就是将暂时了解的一些内容,组织成一篇学习笔记,供以后参考.

      在Microsoft的Word,Excel等应用程序中,保存文件的格式是用复合结构来保存的.复合结构不像一般的文件存储方式(根目录、子目录、文件形式的结构),而是采用根存储(IStorage类型),子存储(IStorage类型),流(IStream)结构的形式来存储文件.

      复合文件中的流,是保存数据的空间,存储单位是512字节.

      不同进程,不同线程可以访问复合文件的不同部分而不受干扰.这在不同于普通文件的特点之处.

      复合文件提供了增量访问的能力,在一个文件中插入某些字节不需要对整个文件进行访问.

      在VC6中有一工具提供了查看复合文件的功能,是Doc File View工具.可以用它来查看复合文件的结构内容.

      操作复合文件的函数,分为三种类型,WinAPI函数,存储IStorage接口函数,流IStream接口函数.

WINAPI函数:
    StgCreateDocFile()  建立复合文件,得到根存储对象
    StgOpenStorage()    打开复合文件,得到根存储对象
    StgIsStorageFile()  判断文件是否复合文件

IStorage函数
    CreateStorage() 在当前存储中建立新存储,得到子存储对象
    CreateStream()  在当前存储中建立流,得到流对象
    OpenStorage()   打开子存储,得到子存储对象
    OpenStream()    打开流,得到流对象
    CopyTo()  MoveElementTo()  DestoryElement()  RenameElement()  EnumElements()  SetElementTimes() SetClass() Stat() Release() 等等


    IStream函数
    Read()  Write()  Seek() SetSize()  CopyTo()  Stat()  Clone()  Release()

    关于这些函数有很好的教程: http://www.vckbase.com/document/viewdoc/?id=1483


MSDN文章上面有一代码,描述了如何具体的创建和设置Storage File的方法,很好的一个例子,值得学习.


例子如下:

  1 ExpandedBlockStart.gif ContractedBlock.gif /**/ /*The EnumAll.cpp sample program dumps all the properties in all property sets of a storage file.*/
  2 None.gif
  3 None.gif // +============================================================================
  4 None.gif //
  5 None.gif //  To Build:   cl /GX enumall.cpp
  6 None.gif //
  7 None.gif //  This sample is a program which dumps all the properties in all property
  8 None.gif //  sets of a storage file.
  9 None.gif //
 10 None.gif // +============================================================================
 11 None.gif
 12 None.gif
 13 None.gif #define  UNICODE
 14 None.gif #define  _UNICODE
 15 None.gif
 16 None.gif#include  < stdio.h >
 17 None.gif#include  < windows.h >
 18 None.gif
 19 None.gif#pragma comment( lib,  " ole32.lib "  )
 20 None.gif
 21 None.gif // +----------------------------------------------------------------------------
 22 None.gif //
 23 None.gif //   ConvertVarTypeToString
 24 None.gif //   
 25 None.gif //   Generate a string for a given PROPVARIANT variable type (VT). 
 26 None.gif //   For the given vt, write the string to pwszType, which is a buffer of
 27 None.gif //   size cchType characters.
 28 None.gif //
 29 None.gif // +----------------------------------------------------------------------------
 30 None.gif
 31 None.gif void
 32 None.gifConvertVarTypeToString( VARTYPE vt, WCHAR  * pwszType, ULONG cchType )
 33 ExpandedBlockStart.gifContractedBlock.gif dot.gif {
 34InBlock.gif    const WCHAR *pwszModifier;
 35InBlock.gif
 36InBlock.gif    // Make sure the output string will be terminated
 37InBlock.gif    // (wcsncpy doesn't guarantee termination)
 38InBlock.gif
 39InBlock.gif    pwszType[ cchType-1 ] = L'\0';
 40InBlock.gif    --cchType;
 41InBlock.gif
 42InBlock.gif    // Stringize the basic type
 43InBlock.gif
 44InBlock.gif    switch( vt & VT_TYPEMASK )
 45ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
 46InBlock.gif    case VT_EMPTY:
 47InBlock.gif        wcsncpy( pwszType, L"VT_EMPTY", cchType );
 48InBlock.gif        break;
 49InBlock.gif    case VT_NULL:
 50InBlock.gif        wcsncpy( pwszType, L"VT_NULL", cchType );
 51InBlock.gif        break;
 52InBlock.gif    case VT_I2:
 53InBlock.gif        wcsncpy( pwszType, L"VT_I2", cchType );
 54InBlock.gif        break;
 55InBlock.gif    case VT_I4:
 56InBlock.gif        wcsncpy( pwszType, L"VT_I4", cchType );
 57InBlock.gif        break;
 58InBlock.gif    case VT_I8:
 59InBlock.gif        wcsncpy( pwszType, L"VT_I8", cchType );
 60InBlock.gif        break;
 61InBlock.gif    case VT_UI2:
 62InBlock.gif        wcsncpy( pwszType, L"VT_UI2", cchType );
 63InBlock.gif        break;
 64InBlock.gif    case VT_UI4:
 65InBlock.gif        wcsncpy( pwszType, L"VT_UI4", cchType );
 66InBlock.gif        break;
 67InBlock.gif    case VT_UI8:
 68InBlock.gif        wcsncpy( pwszType, L"VT_UI8", cchType );
 69InBlock.gif        break;
 70InBlock.gif    case VT_R4:
 71InBlock.gif        wcsncpy( pwszType, L"VT_R4", cchType );
 72InBlock.gif        break;
 73InBlock.gif    case VT_R8:
 74InBlock.gif        wcsncpy( pwszType, L"VT_R8", cchType );
 75InBlock.gif        break;
 76InBlock.gif    case VT_CY:
 77InBlock.gif        wcsncpy( pwszType, L"VT_CY", cchType );
 78InBlock.gif        break;
 79InBlock.gif    case VT_DATE:
 80InBlock.gif        wcsncpy( pwszType, L"VT_DATE", cchType );
 81InBlock.gif        break;
 82InBlock.gif    case VT_BSTR:
 83InBlock.gif        wcsncpy( pwszType, L"VT_BSTR", cchType );
 84InBlock.gif        break;
 85InBlock.gif    case VT_ERROR:
 86InBlock.gif        wcsncpy( pwszType, L"VT_ERROR", cchType );
 87InBlock.gif        break;
 88InBlock.gif    case VT_BOOL:
 89InBlock.gif        wcsncpy( pwszType, L"VT_BOOL", cchType );
 90InBlock.gif        break;
 91InBlock.gif    case VT_VARIANT:
 92InBlock.gif        wcsncpy( pwszType, L"VT_VARIANT", cchType );
 93InBlock.gif        break;
 94InBlock.gif    case VT_DECIMAL:
 95InBlock.gif        wcsncpy( pwszType, L"VT_DECIMAL", cchType );
 96InBlock.gif        break;
 97InBlock.gif    case VT_I1:
 98InBlock.gif        wcsncpy( pwszType, L"VT_I1", cchType );
 99InBlock.gif        break;
100InBlock.gif    case VT_UI1:
101InBlock.gif        wcsncpy( pwszType, L"VT_UI1", cchType );
102InBlock.gif        break;
103InBlock.gif    case VT_INT:
104InBlock.gif        wcsncpy( pwszType, L"VT_INT", cchType );
105InBlock.gif        break;
106InBlock.gif    case VT_UINT:
107InBlock.gif        wcsncpy( pwszType, L"VT_UINT", cchType );
108InBlock.gif        break;
109InBlock.gif    case VT_VOID:
110InBlock.gif        wcsncpy( pwszType, L"VT_VOID", cchType );
111InBlock.gif        break;
112InBlock.gif    case VT_SAFEARRAY:
113InBlock.gif        wcsncpy( pwszType, L"VT_SAFEARRAY", cchType );
114InBlock.gif        break;
115InBlock.gif    case VT_USERDEFINED:
116InBlock.gif        wcsncpy( pwszType, L"VT_USERDEFINED", cchType );
117InBlock.gif        break;
118InBlock.gif    case VT_LPSTR:
119InBlock.gif        wcsncpy( pwszType, L"VT_LPSTR", cchType );
120InBlock.gif        break;
121InBlock.gif    case VT_LPWSTR:
122InBlock.gif        wcsncpy( pwszType, L"VT_LPWSTR", cchType );
123InBlock.gif        break;
124InBlock.gif    case VT_RECORD:
125InBlock.gif        wcsncpy( pwszType, L"VT_RECORD", cchType );
126InBlock.gif        break;
127InBlock.gif    case VT_FILETIME:
128InBlock.gif        wcsncpy( pwszType, L"VT_FILETIME", cchType );
129InBlock.gif        break;
130InBlock.gif    case VT_BLOB:
131InBlock.gif        wcsncpy( pwszType, L"VT_BLOB", cchType );
132InBlock.gif        break;
133InBlock.gif    case VT_STREAM:
134InBlock.gif        wcsncpy( pwszType, L"VT_STREAM", cchType );
135InBlock.gif        break;
136InBlock.gif    case VT_STORAGE:
137InBlock.gif        wcsncpy( pwszType, L"VT_STORAGE", cchType );
138InBlock.gif        break;
139InBlock.gif    case VT_STREAMED_OBJECT:
140InBlock.gif        wcsncpy( pwszType, L"VT_STREAMED_OBJECT", cchType );
141InBlock.gif        break;
142InBlock.gif    case VT_STORED_OBJECT:
143InBlock.gif        wcsncpy( pwszType, L"VT_BLOB_OBJECT", cchType );
144InBlock.gif        break;
145InBlock.gif    case VT_CF:
146InBlock.gif        wcsncpy( pwszType, L"VT_CF", cchType );
147InBlock.gif        break;
148InBlock.gif    case VT_CLSID:
149InBlock.gif        wcsncpy( pwszType, L"VT_CLSID", cchType );
150InBlock.gif        break;
151InBlock.gif    default:
152InBlock.gif        _snwprintf( pwszType, cchType, L"Unknown (%d)", vt & VT_TYPEMASK );
153InBlock.gif        break;
154ExpandedSubBlockEnd.gif    }

155InBlock.gif
156InBlock.gif    // Adjust cchType for the characters we just added
157InBlock.gif
158InBlock.gif    cchType -= wcslen(pwszType);
159InBlock.gif
160InBlock.gif    // Add the type modifiers if present
161InBlock.gif
162InBlock.gif    if( vt & VT_VECTOR )
163ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
164InBlock.gif        pwszModifier = L" | VT_VECTOR";        
165InBlock.gif        wcsncat( pwszType, pwszModifier, cchType );
166InBlock.gif        cchType -= wcslen( pwszModifier );
167ExpandedSubBlockEnd.gif    }

168InBlock.gif
169InBlock.gif    if( vt & VT_ARRAY )
170ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
171InBlock.gif        pwszModifier = L" | VT_ARRAY";        
172InBlock.gif        wcsncat( pwszType, pwszModifier, cchType );
173InBlock.gif        cchType -= wcslen( pwszModifier );
174ExpandedSubBlockEnd.gif    }

175InBlock.gif
176InBlock.gif    if( vt & VT_RESERVED )
177ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
178InBlock.gif        pwszModifier = L" | VT_RESERVED";        
179InBlock.gif        wcsncat( pwszType, pwszModifier, cchType );
180InBlock.gif        cchType -= wcslen( pwszModifier );
181ExpandedSubBlockEnd.gif    }

182InBlock.gif
183ExpandedBlockEnd.gif}

184 None.gif
185 None.gif
186 None.gif // +----------------------------------------------------------------------------
187 None.gif //
188 None.gif //   ConvertValueToString
189 None.gif //   
190 None.gif //   Generate a string for the value in a given PROPVARIANT structure.
191 None.gif //   The most common types are supported (that is, those that can be displayed
192 None.gif //   with printf).  For other types, only an ellipses "dot.gif" is displayed.
193 None.gif //
194 None.gif //   The property to string-ize is in propvar, the resulting string goes
195 None.gif //   into pwszValue, which is a buffer with room for cchValue characters
196 None.gif //   (including the string terminator).
197 None.gif //
198 None.gif // +----------------------------------------------------------------------------
199 None.gif
200 None.gif void
201 None.gifConvertValueToString(  const  PROPVARIANT  & propvar,
202 None.gif                      WCHAR  * pwszValue,
203 None.gif                      ULONG cchValue )
204 ExpandedBlockStart.gifContractedBlock.gif dot.gif {
205InBlock.gif    // Make sure the output string will be terminated
206InBlock.gif
207InBlock.gif    pwszValue[ cchValue - 1 ] = L'\0';
208InBlock.gif    --cchValue;
209InBlock.gif
210InBlock.gif    // Based on the type, put the value into pwszValue as a string.
211InBlock.gif
212InBlock.gif    switch( propvar.vt )
213ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
214InBlock.gif    case VT_EMPTY:
215InBlock.gif        wcsncpy( pwszValue, L"", cchValue );
216InBlock.gif        break;
217InBlock.gif    case VT_NULL:
218InBlock.gif        wcsncpy( pwszValue, L"", cchValue );
219InBlock.gif        break;
220InBlock.gif    case VT_I2:
221InBlock.gif        _snwprintf( pwszValue, cchValue, L"%i", propvar.iVal );
222InBlock.gif        break;
223InBlock.gif    case VT_I4:
224InBlock.gif    case VT_INT:
225InBlock.gif        _snwprintf( pwszValue, cchValue, L"%li", propvar.lVal );
226InBlock.gif        break;
227InBlock.gif    case VT_I8:
228InBlock.gif        _snwprintf( pwszValue, cchValue, L"%I64i", propvar.hVal );
229InBlock.gif        break;
230InBlock.gif    case VT_UI2:
231InBlock.gif        _snwprintf ( pwszValue, cchValue, L"%u", propvar.uiVal );
232InBlock.gif        break;
233InBlock.gif    case VT_UI4:
234InBlock.gif    case VT_UINT:
235InBlock.gif        _snwprintf ( pwszValue, cchValue, L"%lu", propvar.ulVal );
236InBlock.gif        break;
237InBlock.gif    case VT_UI8:
238InBlock.gif        _snwprintf ( pwszValue, cchValue, L"%I64u", propvar.uhVal );
239InBlock.gif        break;
240InBlock.gif    case VT_R4:
241InBlock.gif        _snwprintf ( pwszValue, cchValue, L"%f", propvar.fltVal );
242InBlock.gif        break;
243InBlock.gif    case VT_R8:
244InBlock.gif        _snwprintf ( pwszValue, cchValue, L"%lf", propvar.dblVal );
245InBlock.gif        break;
246InBlock.gif    case VT_BSTR:
247InBlock.gif        _snwprintf ( pwszValue, cchValue, L"\"%s\"", propvar.bstrVal );
248InBlock.gif        break;
249InBlock.gif    case VT_ERROR:
250InBlock.gif        _snwprintf ( pwszValue, cchValue, L"0x%08X", propvar.scode );
251InBlock.gif        break;
252InBlock.gif    case VT_BOOL:
253InBlock.gif        _snwprintf ( pwszValue, cchValue, L"%s",
254InBlock.gif                     VARIANT_TRUE == propvar.boolVal ? L"True" : L"False" );
255InBlock.gif        break;
256InBlock.gif    case VT_I1:
257InBlock.gif        _snwprintf ( pwszValue, cchValue, L"%i", propvar.cVal );
258InBlock.gif        break;
259InBlock.gif    case VT_UI1:
260InBlock.gif        _snwprintf ( pwszValue, cchValue, L"%u", propvar.bVal );
261InBlock.gif        break;
262InBlock.gif    case VT_VOID:
263InBlock.gif        wcsncpy( pwszValue, L"", cchValue );
264InBlock.gif        break;
265InBlock.gif    case VT_LPSTR:
266InBlock.gif        if0 >_snwprintf ( pwszValue, cchValue, L"\"%hs\"", propvar.pszVal ))
267InBlock.gif            // String is too big for pwszValue
268InBlock.gif            wcsncpy( pwszValue, L"dot.gif", cchValue );
269InBlock.gif        break;
270InBlock.gif    case VT_LPWSTR:
271InBlock.gif        if0 > _snwprintf ( pwszValue, cchValue, L"\"%s\"", propvar.pwszVal ))
272InBlock.gif            // String is too big for pwszValue
273InBlock.gif            wcsncpy( pwszValue, L"dot.gif", cchValue );
274InBlock.gif        break;
275InBlock.gif    case VT_FILETIME:
276InBlock.gif        _snwprintf ( pwszValue, cchValue, L"%08x:%08x",
277InBlock.gif                     propvar.filetime.dwHighDateTime,
278InBlock.gif                     propvar.filetime.dwLowDateTime );
279InBlock.gif        break;
280InBlock.gif    case VT_CLSID:
281InBlock.gif        pwszValue[0= L'\0';
282InBlock.gif        StringFromGUID2( *propvar.puuid, pwszValue, cchValue );
283InBlock.gif        break;
284InBlock.gif    default:
285InBlock.gif        wcsncpy( pwszValue, L"dot.gif", cchValue );
286InBlock.gif        break;
287ExpandedSubBlockEnd.gif    }

288InBlock.gif
289ExpandedBlockEnd.gif}

290 None.gif
291 None.gif
292 None.gif // +----------------------------------------------------------------------------
293 None.gif //
294 None.gif //   DisplayProperty
295 None.gif //
296 None.gif //   Dump the ID, name, type, and value of a property.
297 None.gif //
298 None.gif // +----------------------------------------------------------------------------
299 None.gif
300 None.gif void
301 None.gifDisplayProperty(  const  PROPVARIANT  & propvar,  const  STATPROPSTG  & statpropstg )
302 ExpandedBlockStart.gifContractedBlock.gif dot.gif {
303InBlock.gif    WCHAR wsz[ MAX_PATH + 1 ];
304InBlock.gif
305InBlock.gif    ConvertVarTypeToString( statpropstg.vt, wsz, sizeof(wsz)/sizeof(wsz[0]) );
306InBlock.gif
307InBlock.gif    wprintf( L"   ----------------------------------------------------\n"
308InBlock.gif             L"   PropID = %-5d VarType = %-23s",
309InBlock.gif             statpropstg.propid, wsz );
310InBlock.gif
311InBlock.gif    if( NULL != statpropstg.lpwstrName )
312InBlock.gif        wprintf( L" Name = %s", statpropstg.lpwstrName );
313InBlock.gif
314InBlock.gif    ConvertValueToString( propvar, wsz, sizeof(wsz)/sizeof(wsz[0]) );
315InBlock.gif
316InBlock.gif    wprintf( L"\n   Value = %s\n", wsz ); 
317InBlock.gif
318ExpandedBlockEnd.gif}

319 None.gif
320 None.gif
321 None.gif // +----------------------------------------------------------------------------
322 None.gif //
323 None.gif //   DisplayPropertySet
324 None.gif //
325 None.gif //   Dump all the properties into a given property set.
326 None.gif //
327 None.gif // +----------------------------------------------------------------------------
328 None.gif
329 None.gif void
330 None.gifDisplayPropertySet( FMTID fmtid,
331 None.gif                     const  WCHAR  * pwszStorageName,
332 None.gif                    IPropertyStorage  * pPropStg )
333 ExpandedBlockStart.gifContractedBlock.gif dot.gif {
334InBlock.gif    IEnumSTATPROPSTG *penum = NULL;
335InBlock.gif    HRESULT hr = S_OK;
336InBlock.gif    STATPROPSTG statpropstg;
337InBlock.gif    PROPVARIANT propvar;
338InBlock.gif    PROPSPEC propspec;
339InBlock.gif    PROPID propid;
340InBlock.gif    WCHAR *pwszFriendlyName = NULL;
341InBlock.gif
342InBlock.gif    // This string will hold a string-ized FMTID.  It needs
343InBlock.gif    // to be 38 characters, plus the terminator
344InBlock.gif    // character.  But just to be safe we'll make
345InBlock.gif    // it a little bigger.
346ExpandedSubBlockStart.gifContractedSubBlock.gif    WCHAR wszFMTID[ 64 ] = dot.gif{ L"" };
347InBlock.gif
348InBlock.gif    PropVariantInit( &propvar );
349InBlock.gif    memset( &statpropstg, 0sizeof(statpropstg) );
350InBlock.gif
351InBlock.gif    try
352ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
353InBlock.gif        // Display the ID of the property set
354InBlock.gif
355InBlock.gif        StringFromGUID2( fmtid,
356InBlock.gif                         wszFMTID,
357InBlock.gif                         sizeof(wszFMTID)/sizeof(wszFMTID[0]) );
358InBlock.gif        wprintf( L"\n Property Set %s\n", wszFMTID );
359InBlock.gif
360InBlock.gif        // If this is one of common property sets, show which one.
361InBlock.gif
362InBlock.gif        if( FMTID_SummaryInformation == fmtid )
363InBlock.gif            wprintf( L"   (SummaryInformation property set)\n" );
364InBlock.gif        else if( FMTID_DocSummaryInformation == fmtid )
365InBlock.gif            wprintf( L"   (DocumentSummaryInformation property set)\n" );
366InBlock.gif        else if( FMTID_UserDefinedProperties == fmtid )
367InBlock.gif            wprintf( L"   (UserDefined property set)\n" );
368InBlock.gif
369InBlock.gif        // Also display the name of the storage that contains
370InBlock.gif        // this property set
371InBlock.gif
372InBlock.gif        wprintf( L"   in \"%s\":\n", pwszStorageName );
373InBlock.gif
374InBlock.gif        // If this property set has a friendly name, display it now.
375InBlock.gif        // (Property names are stored in the special dictionary
376InBlock.gif        // property - the name of the property set is indicated by naming
377InBlock.gif        // the dictionary property itself.)
378InBlock.gif
379InBlock.gif        propid = PID_DICTIONARY;
380InBlock.gif        pwszFriendlyName = NULL;
381InBlock.gif
382InBlock.gif        hr = pPropStg->ReadPropertyNames( 1&propid, &pwszFriendlyName );
383InBlock.gif        if( S_OK == hr )
384ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
385InBlock.gif            wprintf( L"   (Friendly name is \"%s\")\n\n", pwszFriendlyName );
386InBlock.gif            CoTaskMemFree( pwszFriendlyName );
387InBlock.gif            pwszFriendlyName = NULL;
388ExpandedSubBlockEnd.gif        }

389InBlock.gif        else
390InBlock.gif            wprintf( L"\n" );
391InBlock.gif
392InBlock.gif        // Get a property enumerator
393InBlock.gif
394InBlock.gif        hr = pPropStg->Enum( &penum );
395InBlock.gif        if( FAILED(hr) ) throw L"Failed IPropertyStorage::Enum";
396InBlock.gif
397InBlock.gif        // Get the first property in the enumeration
398InBlock.gif
399InBlock.gif        hr = penum->Next( 1&statpropstg, NULL );
400InBlock.gif
401InBlock.gif        // Loop through and display each property.  The ‘Next'
402InBlock.gif        // call above (and at the bottom of the while loop)
403InBlock.gif        // will return S_OK if it returns another property,
404InBlock.gif        // S_FALSE if there are no more properties,
405InBlock.gif        // and anything else is an error.
406InBlock.gif
407InBlock.gif        while( S_OK == hr )
408ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
409InBlock.gif
410InBlock.gif            // Read the property out of the property set
411InBlock.gif
412InBlock.gif            PropVariantInit( &propvar );
413InBlock.gif            propspec.ulKind = PRSPEC_PROPID;
414InBlock.gif            propspec.propid = statpropstg.propid;
415InBlock.gif
416InBlock.gif            hr = pPropStg->ReadMultiple( 1&propspec, &propvar );
417InBlock.gif            if( FAILED(hr) ) throw L"Failed IPropertyStorage::ReadMultiple";
418InBlock.gif
419InBlock.gif            // Display the property value, type, etc.
420InBlock.gif
421InBlock.gif            DisplayProperty( propvar, statpropstg );
422InBlock.gif
423InBlock.gif            // Free buffers that were allocated during the read and
424InBlock.gif            // by the enumerator.
425InBlock.gif
426InBlock.gif            PropVariantClear( &propvar );
427InBlock.gif            CoTaskMemFree( statpropstg.lpwstrName );
428InBlock.gif            statpropstg.lpwstrName = NULL;
429InBlock.gif
430InBlock.gif            // Move to the next property in the enumeration
431InBlock.gif
432InBlock.gif            hr = penum->Next( 1&statpropstg, NULL );
433ExpandedSubBlockEnd.gif        }

434InBlock.gif        if( FAILED(hr) ) throw L"Failed IEnumSTATPROPSTG::Next";
435ExpandedSubBlockEnd.gif    }

436InBlock.gif    catch( LPCWSTR pwszErrorMessage )
437ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
438InBlock.gif        wprintf( L"Error in DumpPropertySet: %s (hr = %08x)\n",
439InBlock.gif                 pwszErrorMessage, hr );
440ExpandedSubBlockEnd.gif    }

441InBlock.gif
442InBlock.gif    if( NULL != penum )
443InBlock.gif        penum->Release();
444InBlock.gif
445InBlock.gif    if( NULL != statpropstg.lpwstrName )
446InBlock.gif        CoTaskMemFree( statpropstg.lpwstrName );
447InBlock.gif
448InBlock.gif    PropVariantClear( &propvar );
449ExpandedBlockEnd.gif}

450 None.gif
451 None.gif
452 None.gif // +----------------------------------------------------------------------------
453 None.gif //
454 None.gif //   DisplayPropertySetsInStorage
455 None.gif //
456 None.gif //   Dump the property sets in the top level of a given storage.
457 None.gif //
458 None.gif // +----------------------------------------------------------------------------
459 None.gif
460 None.gif void
461 None.gifDisplayPropertySetsInStorage(  const  WCHAR  * pwszStorageName, 
462 None.gif                              IPropertySetStorage  * pPropSetStg )
463 ExpandedBlockStart.gifContractedBlock.gif dot.gif {
464InBlock.gif    IEnumSTATPROPSETSTG *penum = NULL;
465InBlock.gif    HRESULT hr = S_OK;
466InBlock.gif    IPropertyStorage *pPropStg = NULL;
467InBlock.gif    STATPROPSETSTG statpropsetstg;
468InBlock.gif
469InBlock.gif    try
470ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
471InBlock.gif        // Get a property-set enumerator (which only enumerates the property
472InBlock.gif        // sets at this level of the storage, not its children).
473InBlock.gif
474InBlock.gif        hr = pPropSetStg->Enum( &penum );
475InBlock.gif        if( FAILED(hr) ) throw L"failed IPropertySetStorage::Enum";
476InBlock.gif
477InBlock.gif        // Get the first property set in the enumeration.
478InBlock.gif        // (The field we're interested in is
479InBlock.gif        // statpropsetstg.fmtid, so that we can open the
480InBlock.gif        // property set.)
481InBlock.gif
482InBlock.gif        memset( &statpropsetstg, 0sizeof(statpropsetstg) );
483InBlock.gif        hr = penum->Next( 1&statpropsetstg, NULL );
484InBlock.gif
485InBlock.gif        // Loop through all the property sets
486InBlock.gif
487InBlock.gif        while( S_OK == hr )
488ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
489InBlock.gif            // Open the property set
490InBlock.gif
491InBlock.gif            hr = pPropSetStg->Open( statpropsetstg.fmtid,
492InBlock.gif                                    STGM_READ | STGM_SHARE_EXCLUSIVE,
493InBlock.gif                                    &pPropStg );
494InBlock.gif            if( FAILED(hr) ) throw L"failed IPropertySetStorage::Open";
495InBlock.gif
496InBlock.gif            // Display the properties in the property set
497InBlock.gif
498InBlock.gif            DisplayPropertySet( statpropsetstg.fmtid,
499InBlock.gif                                pwszStorageName,
500InBlock.gif                                pPropStg );
501InBlock.gif
502InBlock.gif            pPropStg->Release();
503InBlock.gif            pPropStg = NULL;
504InBlock.gif
505InBlock.gif            // Get the FMTID of the next property set in the enumeration.
506InBlock.gif
507InBlock.gif            hr = penum->Next( 1&statpropsetstg, NULL );
508InBlock.gif
509ExpandedSubBlockEnd.gif        }

510InBlock.gif        if( FAILED(hr) ) throw L"Failed IEnumSTATPROPSETSTG::Next";
511InBlock.gif
512InBlock.gif        // Special-case handling for the UserDefined property set:
513InBlock.gif        // This property set actually lives inside the well-known
514InBlock.gif        // DocumentSummaryInformation property set.  It is the only
515InBlock.gif        // property set which is allowed to live inside another
516InBlock.gif        // (and exists for legacy compatibility).  It does not get
517InBlock.gif        // included in a normal enumeration, so we have to check for
518InBlock.gif        // it explicitely.  We'll handle it by looking for it when
519InBlock.gif        // we reach the end of the enumerator.
520InBlock.gif
521InBlock.gif        hr = pPropSetStg->Open( FMTID_UserDefinedProperties,
522InBlock.gif                                STGM_READ | STGM_SHARE_EXCLUSIVE,
523InBlock.gif                                &pPropStg );
524InBlock.gif        if( SUCCEEDED(hr) )
525ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
526InBlock.gif            DisplayPropertySet( FMTID_UserDefinedProperties,
527InBlock.gif                                pwszStorageName,
528InBlock.gif                                pPropStg );
529InBlock.gif            pPropStg = NULL;
530ExpandedSubBlockEnd.gif        }

531InBlock.gif
532ExpandedSubBlockEnd.gif    }

533InBlock.gif    catch( LPCWSTR pwszErrorMessage )
534ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
535InBlock.gif        wprintf( L"Error in DumpPropertySetsInStorage: %s (hr = %08x)\n",
536InBlock.gif                 pwszErrorMessage, hr );
537ExpandedSubBlockEnd.gif    }

538InBlock.gif
539InBlock.gif    if( NULL != pPropStg )
540InBlock.gif        pPropStg->Release();
541InBlock.gif    if( NULL != penum )
542InBlock.gif        penum->Release();
543ExpandedBlockEnd.gif}

544 None.gif
545 None.gif
546 None.gif // +----------------------------------------------------------------------------
547 None.gif //
548 None.gif //   DisplayStorageTree
549 None.gif //
550 None.gif //   Dump all the property sets in the given storage and recursively in
551 None.gif //   all its children.
552 None.gif //
553 None.gif // +----------------------------------------------------------------------------
554 None.gif
555 None.gif void
556 None.gifDisplayStorageTree(  const  WCHAR  * pwszStorageName, IStorage  * pStg )
557 ExpandedBlockStart.gifContractedBlock.gif dot.gif {
558InBlock.gif    IPropertySetStorage *pPropSetStg = NULL;
559InBlock.gif    IStorage *pStgChild = NULL;
560InBlock.gif    WCHAR *pwszChildStorageName = NULL;
561InBlock.gif    IEnumSTATSTG *penum = NULL;
562InBlock.gif    HRESULT hr = S_OK;
563InBlock.gif    STATSTG statstg;
564InBlock.gif
565InBlock.gif    memset( &statstg, 0sizeof(statstg) );
566InBlock.gif
567InBlock.gif    try
568ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
569InBlock.gif        // Dump the property sets at this storage level
570InBlock.gif
571InBlock.gif        hr = pStg->QueryInterface( IID_IPropertySetStorage,
572InBlock.gif                                   reinterpret_cast<void**>(&pPropSetStg) );
573InBlock.gif        if( FAILED(hr) )
574InBlock.gif            throw L"Failed IStorage::QueryInterface(IID_IPropertySetStorage)";
575InBlock.gif
576InBlock.gif        DisplayPropertySetsInStorage( pwszStorageName, pPropSetStg );
577InBlock.gif
578InBlock.gif        // Get an enumerator for this storage.
579InBlock.gif
580InBlock.gif        hr = pStg->EnumElements( NULL, NULL, NULL, &penum );
581InBlock.gif        if( FAILED(hr) ) throw L"failed IStorage::Enum";
582InBlock.gif
583InBlock.gif        // Get the name of the first element (stream/storage)
584InBlock.gif        // in the enumeration.  As usual, ‘Next' will return
585InBlock.gif        // S_OK if it returns an element of the enumerator,
586InBlock.gif        // S_FALSE if there are no more elements, and an
587InBlock.gif        // error otherwise.
588InBlock.gif
589InBlock.gif        hr = penum->Next( 1&statstg, 0 );
590InBlock.gif
591InBlock.gif        // Loop through all the direct children of this storage.
592InBlock.gif
593InBlock.gif        while( S_OK == hr )
594ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
595InBlock.gif            // Check if this is a storage that isn't a property set
596InBlock.gif            // (since we already displayed the property sets above).
597InBlock.gif            // You can tell if a stream/storage is a property set
598InBlock.gif            // because the first character of it's name is the
599InBlock.gif            // ‘\005' reserved character.
600InBlock.gif
601InBlock.gif            if( STGTY_STORAGE == statstg.type
602InBlock.gif                &&
603InBlock.gif                L'\005' != statstg.pwcsName[0] )
604ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
605InBlock.gif                // Yes, this is a normal storage, not a propset.
606InBlock.gif                // Open the storage.
607InBlock.gif
608InBlock.gif                ULONG cchChildStorageName;
609InBlock.gif
610InBlock.gif                hr = pStg->OpenStorage( statstg.pwcsName,
611InBlock.gif                                        NULL,
612InBlock.gif                                        STGM_READ | STGM_SHARE_EXCLUSIVE,
613InBlock.gif                                        NULL, 0,
614InBlock.gif                                        &pStgChild );
615InBlock.gif                if( FAILED(hr) ) throw L"failed IStorage::OpenStorage";
616InBlock.gif
617InBlock.gif                // Compose a name of the form "Storage\ChildStorage\dot.gif"
618InBlock.gif                // for display purposes.  First, allocate it.
619InBlock.gif
620InBlock.gif                cchChildStorageName = wcslen(pwszStorageName)
621InBlock.gif                                        + wcslen(statstg.pwcsName)
622InBlock.gif                                        + 2  // For the two "\" chars
623InBlock.gif                                        + 1// For the string terminator
624InBlock.gif
625InBlock.gif                pwszChildStorageName = new WCHAR[ cchChildStorageName ];
626InBlock.gif                if( NULL == pwszChildStorageName )
627ExpandedSubBlockStart.gifContractedSubBlock.gif                dot.gif{
628InBlock.gif                    hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
629InBlock.gif                    throw L"couldn't allocate memory";
630ExpandedSubBlockEnd.gif                }

631InBlock.gif
632InBlock.gif                // Terminate the name
633InBlock.gif
634InBlock.gif                pwszChildStorageName[ cchChildStorageName-1 ] = L'\0';
635InBlock.gif                --cchChildStorageName;
636InBlock.gif
637InBlock.gif                // Build the name.
638InBlock.gif
639InBlock.gif                wcsncpy( pwszChildStorageName, pwszStorageName,
640InBlock.gif                         cchChildStorageName );
641InBlock.gif                cchChildStorageName -= wcslen(pwszStorageName);
642InBlock.gif
643InBlock.gif                wcsncat( pwszChildStorageName, L"\\",
644InBlock.gif                         cchChildStorageName );
645InBlock.gif                cchChildStorageName -= 2;
646InBlock.gif
647InBlock.gif                wcsncat( pwszChildStorageName, statstg.pwcsName,
648InBlock.gif                         cchChildStorageName );
649InBlock.gif
650InBlock.gif                // Dump all the property sets under this child storage.
651InBlock.gif
652InBlock.gif                DisplayStorageTree( pwszChildStorageName, pStgChild );
653InBlock.gif
654InBlock.gif                pStgChild->Release();
655InBlock.gif                pStgChild = NULL;
656InBlock.gif
657InBlock.gif                delete pwszChildStorageName;
658InBlock.gif                pwszChildStorageName = NULL;
659ExpandedSubBlockEnd.gif            }

660InBlock.gif
661InBlock.gif            // Move on to the next element in the enumeration of this storage.
662InBlock.gif
663InBlock.gif            CoTaskMemFree( statstg.pwcsName );
664InBlock.gif            statstg.pwcsName = NULL;
665InBlock.gif
666InBlock.gif            hr = penum->Next( 1&statstg, 0 );
667ExpandedSubBlockEnd.gif        }

668InBlock.gif        if( FAILED(hr) ) throw L"failed IEnumSTATSTG::Next";
669ExpandedSubBlockEnd.gif    }

670InBlock.gif    catch( LPCWSTR pwszErrorMessage )
671ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
672InBlock.gif        wprintf( L"Error in DumpStorageTree: %s (hr = %08x)\n",
673InBlock.gif                 pwszErrorMessage, hr );
674ExpandedSubBlockEnd.gif    }

675InBlock.gif
676InBlock.gif    // Clean up before returning.
677InBlock.gif
678InBlock.gif    if( NULL != statstg.pwcsName )
679InBlock.gif        CoTaskMemFree( statstg.pwcsName );
680InBlock.gif    if( NULL != pStgChild )
681InBlock.gif        pStgChild->Release();
682InBlock.gif    if( NULL != pStg )
683InBlock.gif        pStg->Release();
684InBlock.gif    if( NULL != penum )
685InBlock.gif        penum->Release();
686InBlock.gif    if( NULL != pwszChildStorageName )
687InBlock.gif        delete pwszChildStorageName;
688InBlock.gif    
689ExpandedBlockEnd.gif}

690 None.gif
691 None.gif
692 None.gif // +----------------------------------------------------------------------------
693 None.gif //
694 None.gif //   wmain
695 None.gif //
696 None.gif //   Dump all the property sets in a file which is a storage.
697 None.gif //
698 None.gif // +----------------------------------------------------------------------------
699 None.gif
700 None.gif extern   " C "   void  wmain(  int  cArgs, WCHAR  * rgwszArgs[] )
701 ExpandedBlockStart.gifContractedBlock.gif dot.gif {
702InBlock.gif    HRESULT hr = S_OK;
703InBlock.gif    IStorage *pStg = NULL;
704InBlock.gif
705InBlock.gif    // Display usage information if necessary.
706InBlock.gif
707InBlock.gif    if1 == cArgs
708InBlock.gif        ||
709InBlock.gif        0 == wcscmp( L"-?", rgwszArgs[1] )
710InBlock.gif        ||
711InBlock.gif        0 == wcscmp( L"/?", rgwszArgs[1] ))
712ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
713InBlock.gif        printf( "\n"
714InBlock.gif                "Purpose:  Enumerate all properties in all\n"
715InBlock.gif                "          property sets for a storage file\n"
716InBlock.gif                "Usage:    PropDump <filename>\n"
717InBlock.gif                "E.g.:     PropDump word.doc\n"
718InBlock.gif                "\n" );
719InBlock.gif        exit(0);
720ExpandedSubBlockEnd.gif    }

721InBlock.gif
722InBlock.gif    // Open the root storage.
723InBlock.gif
724InBlock.gif    hr = StgOpenStorageEx( rgwszArgs[1],
725InBlock.gif                           STGM_READ | STGM_SHARE_DENY_WRITE,
726InBlock.gif                           STGFMT_ANY,
727InBlock.gif                           0,
728InBlock.gif                           NULL,
729InBlock.gif                           NULL,
730InBlock.gif                           IID_IStorage,
731InBlock.gif                           reinterpret_cast<void**>(&pStg) );
732InBlock.gif
733InBlock.gif    // Dump all the properties in all the property sets within this
734InBlock.gif    // storage.
735InBlock.gif
736InBlock.gif    if( FAILED(hr) )
737ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
738InBlock.gif        wprintf( L"Error:  couldn't open storage \"%s\" (hr = %08x)\n",
739InBlock.gif                 rgwszArgs[1], hr );
740ExpandedSubBlockEnd.gif    }

741InBlock.gif    else
742ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
743InBlock.gif        printf( "\nDisplaying all property sets dot.gif\n" );
744InBlock.gif        DisplayStorageTree( rgwszArgs[1], pStg );
745InBlock.gif        pStg->Release();
746ExpandedSubBlockEnd.gif    }

747InBlock.gif
748InBlock.gif
749ExpandedBlockEnd.gif}

750 None.gif
751 None.gif
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值