Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
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();
}
}