Note

Access to this page requires authorization. You can try signing in or .

Access to this page requires authorization. You can try .

EnumAll Sample

The EnumAll.cpp sample application puts all properties in all property sets of a storage file.

//+===================================================================
//
// To Build: cl /GX enumall.cpp
//
// The following code example dumps all the properties in all property
// sets of a storage file.
//
//+===================================================================


#define UNICODE
#define _UNICODE

#include <stdio.h>
#include <windows.h>

#pragma comment( lib, "ole32.lib" )

//+-------------------------------------------------------------------
//
// ConvertVarTypeToString
// 
// Generate a string for a given PROPVARIANT variable type (VT). 
// For the given vt, write the string to pwszType, which is a buffer
// of size cchType characters.
//
//+-------------------------------------------------------------------

void
ConvertVarTypeToString( VARTYPE vt, WCHAR *pwszType, ULONG cchType )
{
 const WCHAR *pwszModifier;

 // Ensure that the output string is terminated
 // (wcsncpy does not guarantee termination)

 pwszType[ cchType-1 ] = L'\0';
 --cchType;

 // Create a string using the basic type.

 switch( vt & VT_TYPEMASK )
 {
 case VT_EMPTY:
 wcsncpy_s( pwszType, cchType, L"VT_EMPTY", cchType );
 break;
 case VT_NULL:
 wcsncpy_s( pwszType, cchType, L"VT_NULL", cchType );
 break;
 case VT_I2:
 wcsncpy_s( pwszType, cchType, L"VT_I2", cchType );
 break;
 case VT_I4:
 wcsncpy_s( pwszType, cchType, L"VT_I4", cchType );
 break;
 case VT_I8:
 wcsncpy_s( pwszType, cchType, L"VT_I8", cchType );
 break;
 case VT_UI2:
 wcsncpy_s( pwszType, cchType, L"VT_UI2", cchType );
 break;
 case VT_UI4:
 wcsncpy_s( pwszType, cchType, L"VT_UI4", cchType );
 break;
 case VT_UI8:
 wcsncpy_s( pwszType, cchType, L"VT_UI8", cchType );
 break;
 case VT_R4:
 wcsncpy_s( pwszType, cchType, L"VT_R4", cchType );
 break;
 case VT_R8:
 wcsncpy_s( pwszType, cchType, L"VT_R8", cchType );
 break;
 case VT_CY:
 wcsncpy_s( pwszType, cchType, L"VT_CY", cchType );
 break;
 case VT_DATE:
 wcsncpy_s( pwszType, cchType, L"VT_DATE", cchType );
 break;
 case VT_BSTR:
 wcsncpy_s( pwszType, cchType, L"VT_BSTR", cchType );
 break;
 case VT_ERROR:
 wcsncpy_s( pwszType, cchType, L"VT_ERROR", cchType );
 break;
 case VT_BOOL:
 wcsncpy_s( pwszType, cchType, L"VT_BOOL", cchType );
 break;
 case VT_VARIANT:
 wcsncpy_s( pwszType, cchType, L"VT_VARIANT", cchType );
 break;
 case VT_DECIMAL:
 wcsncpy_s( pwszType, cchType, L"VT_DECIMAL", cchType );
 break;
 case VT_I1:
 wcsncpy_s( pwszType, cchType, L"VT_I1", cchType );
 break;
 case VT_UI1:
 wcsncpy_s( pwszType, cchType, L"VT_UI1", cchType );
 break;
 case VT_INT:
 wcsncpy_s( pwszType, cchType, L"VT_INT", cchType );
 break;
 case VT_UINT:
 wcsncpy_s( pwszType, cchType, L"VT_UINT", cchType );
 break;
 case VT_VOID:
 wcsncpy_s( pwszType, cchType, L"VT_VOID", cchType );
 break;
 case VT_SAFEARRAY:
 wcsncpy_s( pwszType, cchType, L"VT_SAFEARRAY", cchType );
 break;
 case VT_USERDEFINED:
 wcsncpy_s( pwszType, cchType, L"VT_USERDEFINED", cchType );
 break;
 case VT_LPSTR:
 wcsncpy_s( pwszType, cchType, L"VT_LPSTR", cchType );
 break;
 case VT_LPWSTR:
 wcsncpy_s( pwszType, cchType, L"VT_LPWSTR", cchType );
 break;
 case VT_RECORD:
 wcsncpy_s( pwszType, cchType, L"VT_RECORD", cchType );
 break;
 case VT_FILETIME:
 wcsncpy_s( pwszType, cchType, L"VT_FILETIME", cchType );
 break;
 case VT_BLOB:
 wcsncpy_s( pwszType, cchType, L"VT_BLOB", cchType );
 break;
 case VT_STREAM:
 wcsncpy_s( pwszType, cchType, L"VT_STREAM", cchType );
 break;
 case VT_STORAGE:
 wcsncpy_s( pwszType, cchType, L"VT_STORAGE", cchType );
 break;
 case VT_STREAMED_OBJECT:
 wcsncpy_s( pwszType, cchType, L"VT_STREAMED_OBJECT", cchType );
 break;
 case VT_STORED_OBJECT:
 wcsncpy_s( pwszType, cchType, L"VT_BLOB_OBJECT", cchType );
 break;
 case VT_CF:
 wcsncpy_s( pwszType, cchType, L"VT_CF", cchType );
 break;
 case VT_CLSID:
 wcsncpy_s( pwszType, cchType, L"VT_CLSID", cchType );
 break;
 default:
 _snwprintf_s( pwszType, cchType, cchType, L"Unknown (%d)", 
 vt & VT_TYPEMASK );
 break;
 }

 // Adjust cchType for the added characters.

 cchType -= wcslen(pwszType);

 // Add the type modifiers, if present.

 if( vt & VT_VECTOR )
 {
 pwszModifier = L" | VT_VECTOR"; 
 wcsncat_s( pwszType, cchType, pwszModifier, cchType );
 cchType -= wcslen( pwszModifier );
 }

 if( vt & VT_ARRAY )
 {
 pwszModifier = L" | VT_ARRAY"; 
 wcsncat_s( pwszType, cchType, pwszModifier, cchType );
 cchType -= wcslen( pwszModifier );
 }

 if( vt & VT_RESERVED )
 {
 pwszModifier = L" | VT_RESERVED"; 
 wcsncat_s( pwszType, cchType, pwszModifier, cchType );
 cchType -= wcslen( pwszModifier );
 }

}


//+-------------------------------------------------------------------
//
// ConvertValueToString
// 
// Generate a string for the value in a given PROPVARIANT structure.
// The most common types are supported; that is, those that can be
// displayed with printf. For other types, only an ellipses (...) 
// is displayed.
//
// The property to create a string from is in propvar, the resulting
// string is placed into pwszValue, which is a buffer with space for
// cchValue characters (including the string terminator).
//
//+-------------------------------------------------------------------

void
ConvertValueToString( const PROPVARIANT &propvar,
 WCHAR *pwszValue,
 ULONG cchValue )
{
 // Ensure that the output string is terminated

 pwszValue[ cchValue - 1 ] = L'\0';
 --cchValue;

 // Based on the type, put the value into pwszValue as a string.

 switch( propvar.vt )
 {
 case VT_EMPTY:
 wcsncpy_s( pwszValue, cchValue, L"", cchValue );
 break;
 case VT_NULL:
 wcsncpy_s( pwszValue, cchValue, L"", cchValue );
 break;
 case VT_I2:
 _snwprintf_s( pwszValue, cchValue, cchValue, L"%i", propvar.iVal );
 break;
 case VT_I4:
 case VT_INT:
 _snwprintf_s( pwszValue, cchValue, cchValue, L"%li", propvar.lVal );
 break;
 case VT_I8:
 _snwprintf_s( pwszValue, cchValue, cchValue, L"%I64i", propvar.hVal );
 break;
 case VT_UI2:
 _snwprintf_s( pwszValue, cchValue, cchValue, L"%u", propvar.uiVal );
 break;
 case VT_UI4:
 case VT_UINT:
 _snwprintf_s( pwszValue, cchValue, cchValue, L"%lu", propvar.ulVal );
 break;
 case VT_UI8:
 _snwprintf_s( pwszValue, cchValue, cchValue, L"%I64u", propvar.uhVal );
 break;
 case VT_R4:
 _snwprintf_s( pwszValue, cchValue, cchValue, L"%f", propvar.fltVal );
 break;
 case VT_R8:
 _snwprintf_s( pwszValue, cchValue, cchValue, L"%lf", propvar.dblVal );
 break;
 case VT_BSTR:
 _snwprintf_s( pwszValue, cchValue, cchValue, L"\"%s\"", 
 propvar.bstrVal );
 break;
 case VT_ERROR:
 _snwprintf_s( pwszValue, cchValue, cchValue, L"0x%08X", propvar.scode );
 break;
 case VT_BOOL:
 _snwprintf_s( pwszValue, cchValue, cchValue, L"%s",
 VARIANT_TRUE == propvar.boolVal ? L"True" : L"False" );
 break;
 case VT_I1:
 _snwprintf_s( pwszValue, cchValue, cchValue, L"%i", propvar.cVal );
 break;
 case VT_UI1:
 _snwprintf_s( pwszValue, cchValue, cchValue, L"%u", propvar.bVal );
 break;
 case VT_VOID:
 wcsncpy_s( pwszValue, cchValue, L"", cchValue );
 break;
 case VT_LPSTR:
 if( 0 > _snwprintf_s( pwszValue, cchValue, cchValue, 
 L"\"%hs\"", propvar.pszVal ))
 // String is too large for pwszValue
 wcsncpy_s( pwszValue, cchValue, L"...", cchValue );
 break;
 case VT_LPWSTR:
 if( 0 > _snwprintf_s( pwszValue, cchValue, cchValue, 
 L"\"%s\"", propvar.pwszVal ))
 // String is too large for pwszValue
 wcsncpy_s( pwszValue, cchValue, L"...", cchValue );
 break;
 case VT_FILETIME:
 _snwprintf_s( pwszValue, cchValue, cchValue, L"%08x:%08x",
 propvar.filetime.dwHighDateTime,
 propvar.filetime.dwLowDateTime );
 break;
 case VT_CLSID:
 pwszValue[0] = L'\0';
 StringFromGUID2( *propvar.puuid, pwszValue, cchValue );
 break;
 default:
 wcsncpy_s( pwszValue, cchValue, L"...", cchValue );
 break;
 }

}


//+-------------------------------------------------------------------
//
// DisplayProperty
//
// Dump the ID, name, type, and value of a property.
//
//+-------------------------------------------------------------------

void
DisplayProperty( const PROPVARIANT &propvar, 
 const STATPROPSTG &statpropstg )
{
 WCHAR wsz[ MAX_PATH + 1 ];

 ConvertVarTypeToString( statpropstg.vt, wsz, 
 sizeof(wsz)/sizeof(wsz[0]) );

 wprintf( L" -------------------------------------------------\n"
 L" PropID = %-5d VarType = %-23s",
 statpropstg.propid, wsz );

 if( NULL != statpropstg.lpwstrName )
 wprintf( L" Name = %s", statpropstg.lpwstrName );

 ConvertValueToString( propvar, wsz, sizeof(wsz)/sizeof(wsz[0]) );

 wprintf( L"\n Value = %s\n", wsz ); 

}


//+-------------------------------------------------------------------
//
// DisplayPropertySet
//
// Dump all the properties into a given property set.
//
//+-------------------------------------------------------------------

void
DisplayPropertySet( FMTID fmtid,
 const WCHAR *pwszStorageName,
 IPropertyStorage *pPropStg )
{
 IEnumSTATPROPSTG *penum = NULL;
 HRESULT hr = S_OK;
 STATPROPSTG statpropstg;
 PROPVARIANT propvar;
 PROPSPEC propspec;
 PROPID propid;
 WCHAR *pwszFriendlyName = NULL;

 // This string will hold a string-formatted FMTID. It must
 // be 38 characters, plus the terminator character.
 // For best practice, create a moderately longer string.
 WCHAR wszFMTID[ 64 ] = { L"" };

 PropVariantInit( &propvar );
 memset( &statpropstg, 0, sizeof(statpropstg) );

 try
 {
 // Display the ID of the property set.

 StringFromGUID2( fmtid,
 wszFMTID,
 sizeof(wszFMTID)/sizeof(wszFMTID[0]) );
 wprintf( L"\n Property Set %s\n", wszFMTID );

 // If this is a common property set, display.

 if( FMTID_SummaryInformation == fmtid )
 wprintf( L" (SummaryInformation property set)\n" );
 else if( FMTID_DocSummaryInformation == fmtid )
 wprintf( L" (DocumentSummaryInformation property set)\n" );
 else if( FMTID_UserDefinedProperties == fmtid )
 wprintf( L" (UserDefined property set)\n" );

 // Also display the name of the storage that contains
 // this property set.

 wprintf( L" in \"%s\":\n", pwszStorageName );

 // If this property set has a friendly name, display it now.
 // (Property names are stored in the special dictionary
 // property - the name of the property set is indicated by
 // naming the dictionary property itself.)

 propid = PID_DICTIONARY;
 pwszFriendlyName = NULL;

 hr = pPropStg->ReadPropertyNames( 1, &propid, 
 &pwszFriendlyName );
 if( S_OK == hr )
 {
 wprintf( L" (Friendly name is \"%s\")\n\n", 
 pwszFriendlyName );
 CoTaskMemFree( pwszFriendlyName );
 pwszFriendlyName = NULL;
 }
 else
 wprintf( L"\n" );

 // Get a property enumerator.

 hr = pPropStg->Enum( &penum );
 if( FAILED(hr) ) 
 throw L"Failed IPropertyStorage::Enum";

 // Get the first property in the enumeration.

 hr = penum->Next( 1, &statpropstg, NULL );

 // Loop through and display each property. The 'Next'
 // call above, and at the bottom of the while loop,
 // will return S_OK if it returns another property,
 // S_FALSE if there are no more properties,
 // and anything else is an error.

 while( S_OK == hr )
 {

 // Read the property out of the property set

 PropVariantInit( &propvar );
 propspec.ulKind = PRSPEC_PROPID;
 propspec.propid = statpropstg.propid;

 hr = pPropStg->ReadMultiple( 1, &propspec, &propvar );
 if( FAILED(hr) ) 
 throw L"Failed IPropertyStorage::ReadMultiple";

 // Display the property value, type, and so on.

 DisplayProperty( propvar, statpropstg );

 // Free buffers allocated during the read, and
 // by the enumerator.

 PropVariantClear( &propvar );
 CoTaskMemFree( statpropstg.lpwstrName );
 statpropstg.lpwstrName = NULL;

 // Move to the next property in the enumeration

 hr = penum->Next( 1, &statpropstg, NULL );
 }
 if( FAILED(hr) ) throw L"Failed IEnumSTATPROPSTG::Next";
 }
 catch( LPCWSTR pwszErrorMessage )
 {
 wprintf( L"Error in DumpPropertySet: %s (hr = %08x)\n",
 pwszErrorMessage, hr );
 }

 if( NULL != penum )
 penum->Release();

 if( NULL != statpropstg.lpwstrName )
 CoTaskMemFree( statpropstg.lpwstrName );

 PropVariantClear( &propvar );
}


//+-------------------------------------------------------------------
//
// DisplayPropertySetsInStorage
//
// Dump the property sets in the top level of a given storage.
//
//+-------------------------------------------------------------------

void
DisplayPropertySetsInStorage( const WCHAR *pwszStorageName, 
 IPropertySetStorage *pPropSetStg )
{
 IEnumSTATPROPSETSTG *penum = NULL;
 HRESULT hr = S_OK;
 IPropertyStorage *pPropStg = NULL;
 STATPROPSETSTG statpropsetstg;

 try
 {
 // Get a property-set enumerator, which only enumerates
 // the property sets at this level of the storage, not 
 // its child objects.

 hr = pPropSetStg->Enum( &penum );
 if( FAILED(hr) ) 
 throw L"failed IPropertySetStorage::Enum";

 // Get the first property set in the enumeration.
 // (The field used to open the property set is
 // statpropsetstg.fmtid.

 memset( &statpropsetstg, 0, sizeof(statpropsetstg) );
 hr = penum->Next( 1, &statpropsetstg, NULL );

 // Loop through all the property sets.

 while( S_OK == hr )
 {
 // Open the property set.

 hr = pPropSetStg->Open( statpropsetstg.fmtid,
 STGM_READ | STGM_SHARE_EXCLUSIVE,
 &pPropStg );
 if( FAILED(hr) ) 
 throw L"failed IPropertySetStorage::Open";

 // Display the properties in the property set.

 DisplayPropertySet( statpropsetstg.fmtid,
 pwszStorageName,
 pPropStg );

 pPropStg->Release();
 pPropStg = NULL;

 // Get the FMTID of the next property set in the
 // enumeration.

 hr = penum->Next( 1, &statpropsetstg, NULL );

 }
 if( FAILED(hr) ) throw L"Failed IEnumSTATPROPSETSTG::Next";

 // Special-case handling for the UserDefined property set:
 // This property set actually lives inside the well-known
 // DocumentSummaryInformation property set. It is the only
 // property set which is allowed to live inside another
 // (and exists for legacy compatibility). It does not get
 // included in a normal enumeration, so verify that it is
 // done explicitly. Look for it when the end of the
 // enumerator is reached.

 hr = pPropSetStg->Open( FMTID_UserDefinedProperties,
 STGM_READ | STGM_SHARE_EXCLUSIVE,
 &pPropStg );
 if( SUCCEEDED(hr) )
 {
 DisplayPropertySet( FMTID_UserDefinedProperties,
 pwszStorageName,
 pPropStg );
 pPropStg->Release();
 pPropStg = NULL;
 }

 }
 catch( LPCWSTR pwszErrorMessage )
 {
 wprintf( L"Error in DumpPropertySetsInStorage: 
 %s (hr = %08x)\n",
 pwszErrorMessage, hr );
 }

 if( NULL != pPropStg )
 pPropStg->Release();
 if( NULL != penum )
 penum->Release();
}


//+-------------------------------------------------------------------
//
// DisplayStorageTree
//
// Dump all the property sets in the given storage and recursively in
// all its child objects.
//
//+-------------------------------------------------------------------

void
DisplayStorageTree( const WCHAR *pwszStorageName, IStorage *pStg )
{
 IPropertySetStorage *pPropSetStg = NULL;
 IStorage *pStgChild = NULL;
 WCHAR *pwszChildStorageName = NULL;
 IEnumSTATSTG *penum = NULL;
 HRESULT hr = S_OK;
 STATSTG statstg;

 memset( &statstg, 0, sizeof(statstg) );

 try
 {
 // Dump the property sets at this storage level

 hr = pStg->QueryInterface( IID_IPropertySetStorage,
 reinterpret_cast<void**>(&pPropSetStg) );
 if( FAILED(hr) )
 throw 
 L"Failed IStorage::QueryInterface(IID_IPropertySetStorage)";

 DisplayPropertySetsInStorage( pwszStorageName, pPropSetStg );

 // Get an enumerator for this storage.

 hr = pStg->EnumElements( NULL, NULL, NULL, &penum );
 if( FAILED(hr) ) throw L"failed IStorage::Enum";

 // Get the name of the first element (stream/storage)
 // in the enumeration. As usual, 'Next' will return
 // S_OK if it returns an element of the enumerator,
 // S_FALSE if there are no more elements, and an
 // error otherwise.

 hr = penum->Next( 1, &statstg, 0 );

 // Loop through all the child objects of this storage.

 while( S_OK == hr )
 {
 // Verify that this is a storage that is not a property
 // set, because the property sets are displayed above).
 // If the first character of its name is the '\005'
 // reserved character, it is a stream /storage property
 // set.

 if( STGTY_STORAGE == statstg.type
 &&
 L'\005' != statstg.pwcsName[0] )
 {
 // Indicates normal storage, not a propset.
 // Open the storage.

 ULONG cchChildStorageName;

 hr = pStg->OpenStorage( statstg.pwcsName,
 NULL,
 STGM_READ | STGM_SHARE_EXCLUSIVE,
 NULL, 0,
 &pStgChild );
 if( FAILED(hr) ) 
 throw L"failed IStorage::OpenStorage";

 // Compose a name of the form 
 // "Storage\ChildStorage\..." for display purposes.
 // First, allocate it.

 cchChildStorageName = wcslen(pwszStorageName)
 + wcslen(statstg.pwcsName)
 + 2 // For two "\" chars
 + 1; // For string terminator

 pwszChildStorageName = 
 new WCHAR[ cchChildStorageName ];
 if( NULL == pwszChildStorageName )
 {
 hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
 throw L"couldn't allocate memory";
 }

 // Terminate the name.

 pwszChildStorageName[ cchChildStorageName-1 ] = L'\0';
 --cchChildStorageName;

 // Build the name.

 wcsncpy_s( pwszChildStorageName, cchChildStorageName,
 pwszStorageName, cchChildStorageName );
 cchChildStorageName -= wcslen(pwszStorageName);

 wcsncat_s( pwszChildStorageName, cchChildStorageName,
 L"\\", cchChildStorageName );
 cchChildStorageName -= 2;

 wcsncat_s( pwszChildStorageName, cchChildStorageName,
 statstg.pwcsName, cchChildStorageName );

 // Dump all property sets under this child storage.

 DisplayStorageTree( pwszChildStorageName, pStgChild );

 pStgChild->Release();
 pStgChild = NULL;

 delete[] pwszChildStorageName;
 pwszChildStorageName = NULL;
 }

 // Move to the next element in the enumeration of 
 // this storage.

 CoTaskMemFree( statstg.pwcsName );
 statstg.pwcsName = NULL;

 hr = penum->Next( 1, &statstg, 0 );
 }
 if( FAILED(hr) ) throw L"failed IEnumSTATSTG::Next";
 }
 catch( LPCWSTR pwszErrorMessage )
 {
 wprintf( L"Error in DumpStorageTree: %s (hr = %08x)\n",
 pwszErrorMessage, hr );
 }

 // Cleanup before returning.

 if( NULL != statstg.pwcsName )
 CoTaskMemFree( statstg.pwcsName );
 if( NULL != pStgChild )
 pStgChild->Release();
 if( NULL != pStg )
 pStg->Release();
 if( NULL != penum )
 penum->Release();
 if( NULL != pwszChildStorageName )
 delete[] pwszChildStorageName;
 
}


//+-------------------------------------------------------------------
//
// wmain
//
// Dump all the property sets in a file which is a storage.
//
//+-------------------------------------------------------------------

extern "C" void wmain( int cArgs, WCHAR *rgwszArgs[] )
{
 HRESULT hr = S_OK;
 IStorage *pStg = NULL;

 // Display usage information if necessary.

 if( 1 == cArgs
 ||
 0 == wcscmp( L"-?", rgwszArgs[1] )
 ||
 0 == wcscmp( L"/?", rgwszArgs[1] ))
 {
 printf( "\n"
 "Purpose: Enumerate all properties in all\n"
 " property sets for a storage file\n"
 "Usage: PropDump <filename>\n"
 "E.g.: PropDump word.doc\n"
 "\n" );
 exit(0);
 }

 // Open the root storage.

 hr = StgOpenStorageEx( rgwszArgs[1],
 STGM_READ | STGM_SHARE_DENY_WRITE,
 STGFMT_ANY,
 0,
 NULL,
 NULL,
 IID_IStorage,
 reinterpret_cast<void**>(&pStg) );

 // Dump all the properties in all the property sets within this
 // storage.

 if( FAILED(hr) )
 {
 wprintf( L"Error: couldn't open storage \"%s\" 
 (hr = %08x)\n",
 rgwszArgs[1], hr );
 }
 else
 {
 printf( "\nDisplaying all property sets ...\n" );
 DisplayStorageTree( rgwszArgs[1], pStg );
 pStg->Release();
 }


}

Feedback

Was this page helpful?

Additional resources