Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / MFC

Access the Summary Information Property Set of a file using Visual C++

4.57/5 (15 votes)
9 Nov 20064 min read 1   1.7K  
How to access the Summary Information Property Set of a file, using Visual C++.

Introduction

This area of programming in Visual C++ is a little bit hidden. Many professionals want to know if it is possible to get and set the summary information of a file through Visual C++ (without using .NET), and if yes, then how?

When you right click a text file or any other file, you will find under Properties, a tab called 'Summary'. Inside this tab, there are many options like Title, Subject, Author, Keywords, and Comments. Yes, it is possible that you can change these entries from within your code in Visual C++.

In this article, I will explain the complete process and finally I will demonstrate this, to get and set the value of some property in the Summary tab of a file, using Visual C++ 6.0

The code

There is a function named StgOpenStorageEx available in Ole32.lib, and you can use this to open an existing root storage object in the file system. This function can be used to open compound files and regular files. To create a new file, use the StgCreateStorageEx function.

When you open a file, the system selects a structured storage implementation depending on which STGFMT flag you specify on the file type and on the type of drive where the file is stored.

When you call StgOpenStorageEx for an existing file, it will give you the pointer of IPropertySetStorage. The IPropertySetStorage interface creates, opens, deletes, and enumerates property set storages that support instances of the IPropertyStorage interface. For our current task, we should be familiar with the interface IPropertyStorage.

The IPropertyStorage interface manages a single property set in a property storage subobject; and the IPropertySetStorage interface manages the storage of groups of such property sets. Any file system entity can support IPropertySetStorage that is currently implemented in the COM compound file object.

The stand-alone implementation also provides the StgCreatePropStg and StgOpenPropStg helper functions, in addition to the Create and Open methods, to create and open property sets. These two functions add support the PROPSETFLAG_UNBUFFERED value so you can write changes directly to the property set instead of buffering them in a cache.

IPropertySetStorage::Create use property set Format Identifiers (FMTIDs) of the property which you are going to refer.

Below is the table of Predefined Property Set Format Identifiers which we can use according to our requirements:

NameValueUsage
FMTID_SummaryInformation{F29F85E0-4FF9-1068-AB91-08002B27B3D9}The Summary Information Property Set
FMTID_DocSummaryInformation{D5CDD502-2E9C-101B-9397-08002B2CF9AE}The DocumentSummaryInformation and UserDefined Property Sets
FMTID_UserDefinedProperties{D5CDD505-2E9C-101B-9397-08002B2CF9AE}The DocumentSummaryInformation and UserDefined Property Sets

These FMTIDs are defined in the UUID.LIB library file and the declaration is available in the OLE2.H header file.

According to our current task, we will use ‘FMTID_SummaryInformation’.

After create the property set successfully, we will use a structure ‘PROPSPEC’ to specify a property either by its property identifier (ID) or the associated string name.

The following table lists the string property names for the Summary Information property set, along with the respective property identifiers and variable type (VT) indicators. The names are not typically stored in the property set, but are inferred from the Property ID value. The Property ID String entries shown here correspond to the definitions found in the Win32 API header files.

NameProperty ID stringProperty IDVT type
TitlePIDSI_TITLE0x00000002VT_LPSTR
SubjectPIDSI_SUBJECT0x00000003VT_LPSTR
AuthorPIDSI_AUTHOR0x00000004VT_LPSTR
KeywordsPIDSI_KEYWORDS0x00000005VT_LPSTR
CommentsPIDSI_COMMENTS0x00000006VT_LPSTR
TemplatePIDSI_TEMPLATE0x00000007VT_LPSTR
Last Saved ByPIDSI_LASTAUTHOR0x00000008VT_LPSTR
Revision NumberPIDSI_REVNUMBER0x00000009VT_LPSTR
Total Editing TimePIDSI_EDITTIME0x0000000AVT_FILETIME (UTC)
Last PrintedPIDSI_LASTPRINTED0x0000000BVT_FILETIME (UTC)
Create Time/Date( (*))PIDSI_CREATE_DTM0x0000000CVT_FILETIME (UTC)
Last saved Time/Date( (*))PIDSI_LASTSAVE_DTM0x0000000DVT_FILETIME (UTC)

Number of Pages

Number of Words

Number of Characters

PIDSI_PAGECOUNT

PIDSI_WORDCOUNT

PIDSI_CHARCOUNT

0x0000000E

0x0000000F

0x00000010

VT_I4

VT_I4

VT_I4

ThumbnailPIDSI_THUMBNAIL0x00000011VT_CF
Name of Creating ApplicationPIDSI_APPNAME0x00000012VT_LPSTR
SecurityPIDSI_SECURITY0x00000013VT_I4

* Some methods of file transfer, such as a download from a BBS, do not maintain the file system version of this information correctly.

Then, we will use another structure ‘PROPVARIANT’ for calling the ReadMultiple and WriteMultiple methods of IPropertyStorage to define the type tag and the value of a property in a property set.

So in this way, we can get and set properties in the summary tab under the Properties window of a file. Below is the complete code to accomplish this task.

Make a new project in Visual C++ 6.0 (type ‘Win32 Application’) named ‘SummaryPropPage’. Select ‘A simple Win32 application’ in the project creation step 1 and click OK. Now, copy the code below and paste it in your project’s .cpp file.

Before executing this code, make a file C:\Document.txt (because I use StgOpenStorageEx, you can use StgCreateStorageEx to create new one). Now, you are ready to execute the code.

In this code, I write and then read the ‘Title’ property under the Summary tab of the properties of a file named ‘Document’. You can use this code to get and set any property under the Summary tab, just change the property name (or you can use the property ID) in the PROPSPEC structure.

// SummaryPropPage.cpp : Defines the entry point
// for the application.
//

#include "stdafx.h"

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


// Implicitly link ole32.dll
#pragma comment( lib, "ole32.lib" )



const FMTID PropSetfmtid ={
/* F29F85E0-4FF9-1068-AB91-08002B27B3D9 */
        0xf29f85e0,
        0x4ff9,
        0x1068,
        {0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9 }
        };



int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
     // TODO: Place code here.

    IPropertySetStorage *pPropSetStg = NULL;
    IPropertyStorage *pPropStg = NULL;
    PROPSPEC propspec; 
    PROPVARIANT propWrite; 
    PROPVARIANT propRead;
    HRESULT hr = S_OK;


    // Open a file and a property set within it.
    hr = StgOpenStorageEx( L"C:\\Document.txt",
                    STGM_DIRECT|STGM_SHARE_EXCLUSIVE|
                    STGM_READWRITE,
                    STGFMT_ANY,
                    // STGFMT_STORAGE //Structured 
                                      //Storage property sets
                    // STGFMT_FILE  //NTFS file system 
                                    //property sets
                    0,
                    NULL,
                    NULL,
                    IID_IPropertySetStorage,
                    reinterpret_cast<void**>(&pPropSetStg) );


    if( FAILED(hr) ) 
    throw L"Failed StgOpenStorageEx";

/*    
    hr = pPropSetStg->Open( PropSetfmtid, 
                            STGM_WRITE|
                            STGM_SHARE_EXCLUSIVE,
                            &pPropStg );
*/
    
    hr = pPropSetStg->Create( PropSetfmtid, NULL, 
                            PROPSETFLAG_DEFAULT,
                            STGM_CREATE|STGM_READWRITE|
                            STGM_SHARE_EXCLUSIVE,
                            &pPropStg );

    if( FAILED(hr) ) 
    throw L"Failed IPropertySetStorage::Open";


    //we can identify any property through its Name or its ID
//    propspec.ulKind = PRSPEC_LPWSTR;
//    propspec.lpwstr = L"Title";

    propspec.ulKind = PRSPEC_PROPID;
    propspec.propid  = 0x00000002;


    //specify the value of property
    propWrite.vt = VT_LPWSTR;
    propWrite.pwszVal = L"this value set through code";


    hr = pPropStg->WriteMultiple( 1, &propspec, 
         &propWrite, PID_FIRST_USABLE );

    if( FAILED(hr) ) 
    throw L"Failed IPropertyStorage::WriteMultiple";


    pPropStg->Release(); 
    pPropStg = NULL;


    //again open the property set

    hr = pPropSetStg->Open( PropSetfmtid, 
         STGM_READ|STGM_SHARE_EXCLUSIVE,
         &pPropStg );

    if( FAILED(hr) ) 
    throw L"Failed IPropertySetStorage::Open";


    // Read the property back and validate it
    hr = pPropStg->ReadMultiple( 1, &propspec, &propRead );
    if( FAILED(hr) ) 
    throw L"Failed IPropertyStorage::ReadMultiple";


    char* str = new char [wcslen(propRead.pwszVal) + 1];
    //    the "%S" will implicitly convert UNICODE to ANSI.
    wsprintfA ( str, "%S", propRead.pwszVal); 

    //if you want to display
    //    MessageBox(NULL,str,"Reading Value",MB_OK);

    if( hr == S_FALSE )
       throw L"Property didn't exist after " 
             L"reopening the property set"; 
    else if( propWrite.vt != propRead.vt )
       throw L"Property types didn't match " 
             L"after reopening the property set";
    else if( wcscmp( propWrite.pwszVal, propRead.pwszVal ) != 0 )
       throw L"Property values didn't match" 
             L" after reopening the property set";
    else
       wprintf( L"Success\n" );

    return 0;
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here