65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Visual C++ 访问文件的摘要信息属性集

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.57/5 (14投票s)

2006年11月9日

4分钟阅读

viewsIcon

132400

downloadIcon

1681

如何使用 Visual C++ 访问文件的摘要信息属性集。

引言

Visual C++ 中的这个编程领域有点隐藏。许多专业人士想知道是否可以通过 Visual C++(不使用 .NET)来获取和设置文件的摘要信息,如果可以,那么如何实现?

当您右键单击文本文件或任何其他文件时,在“属性”下会找到一个名为“摘要”的选项卡。在此选项卡中,有许多选项,如标题、主题、作者、关键字和注释。是的,您可以在 Visual C++ 代码中更改这些条目。

在本文中,我将解释完整的过程,最后我将演示如何使用 Visual C++ 6.0 获取和设置文件中“摘要”选项卡中某些属性的值。

代码

Ole32.lib 中有一个名为 StgOpenStorageEx 的函数,您可以使用它来打开文件系统中的现有根存储对象。此函数可用于打开复合文件和常规文件。要创建新文件,请使用 StgCreateStorageEx 函数。

打开文件时,系统会根据您在文件类型上指定的 STGFMT 标志以及文件存储所在驱动器的类型来选择结构化存储实现。

当您为现有文件调用 StgOpenStorageEx 时,它会为您提供 IPropertySetStorage 的指针。IPropertySetStorage 接口创建、打开、删除和枚举支持 IPropertyStorage 接口实例的属性集存储。对于我们当前的任务,我们应该熟悉 IPropertyStorage 接口。

IPropertyStorage 接口管理属性存储子对象中的单个属性集;IPropertySetStorage 接口管理此类属性集组的存储。任何文件系统实体都可以支持 IPropertySetStorage,而 IPropertySetStorage 目前是在 COM 复合文件对象中实现的。

除了 CreateOpen 方法之外,独立实现还提供了 StgCreatePropStgStgOpenPropStg 辅助函数来创建和打开属性集。这两个函数支持 PROPSETFLAG_UNBUFFERED 值,因此您可以直接将更改写入属性集,而不是将其缓冲在缓存中。

IPropertySetStorage::Create 使用属性集格式标识符 (FMTID) 来引用您将要操作的属性。

下表是我们根据需要可用的预定义属性集格式标识符的列表。

名称 用法
FMTID_SummaryInformation {F29F85E0-4FF9-1068-AB91-08002B27B3D9} 摘要信息属性集
FMTID_DocSummaryInformation {D5CDD502-2E9C-101B-9397-08002B2CF9AE} 文档摘要信息和用户定义属性集
FMTID_UserDefinedProperties {D5CDD505-2E9C-101B-9397-08002B2CF9AE} 文档摘要信息和用户定义属性集

这些 FMTID 定义在 UUID.LIB 库文件中,并且声明在 OLE2.H 头文件中。

根据我们当前的任务,我们将使用“FMTID_SummaryInformation”。

成功创建属性集后,我们将使用 PROPSPEC 结构通过属性标识符 (ID) 或关联的字符串名称来指定属性。

下表列出了摘要信息属性集的字符串属性名称,以及相应的属性标识符和变量类型 (VT) 指示符。名称通常不存储在属性集中,而是从属性 ID 值推断出来的。此处显示的属性 ID 字符串条目对应于 Win32 API 头文件中找到的定义。

名称 属性 ID 字符串 属性 ID VT 类型
标题 PIDSI_TITLE 0x00000002 VT_LPSTR
主题 PIDSI_SUBJECT 0x00000003 VT_LPSTR
作者 PIDSI_AUTHOR 0x00000004 VT_LPSTR
关键词 PIDSI_KEYWORDS 0x00000005 VT_LPSTR
注释 PIDSI_COMMENTS 0x00000006 VT_LPSTR
模板 PIDSI_TEMPLATE 0x00000007 VT_LPSTR
最后保存者 PIDSI_LASTAUTHOR 0x00000008 VT_LPSTR
修订号 PIDSI_REVNUMBER 0x00000009 VT_LPSTR
总编辑时间 PIDSI_EDITTIME 0x0000000A VT_FILETIME (UTC)
最后打印日期 PIDSI_LASTPRINTED 0x0000000B VT_FILETIME (UTC)
创建日期/时间(*) PIDSI_CREATE_DTM 0x0000000C VT_FILETIME (UTC)
最后保存日期/时间(*) PIDSI_LASTSAVE_DTM 0x0000000D VT_FILETIME (UTC)

页数

字数

字符数

PIDSI_PAGECOUNT

PIDSI_WORDCOUNT

PIDSI_CHARCOUNT

0x0000000E

0x0000000F

0x00000010

VT_I4

VT_I4

VT_I4

Thumbnail PIDSI_THUMBNAIL 0x00000011 VT_CF
创建应用程序名称 PIDSI_APPNAME 0x00000012 VT_LPSTR
安全 PIDSI_SECURITY 0x00000013 VT_I4

* 一些文件传输方法,例如从 BBS 下载,不会正确维护此信息的 文件系统版本。

然后,我们将使用另一个结构 'PROPVARIANT' 来调用 IPropertyStorageReadMultipleWriteMultiple 方法,以定义属性集中属性的类型标签和值。

这样,我们就可以在文件的“属性”窗口下的“摘要”选项卡中获取和设置属性。下面是完成此任务的完整代码。

在 Visual C++ 6.0 中创建一个新项目(类型为“Win32 应用程序”),项目名称为“SummaryPropPage”。在项目创建步骤 1 中选择“一个简单的 Win32 应用程序”并单击“确定”。现在,复制下面的代码并粘贴到您项目的 .cpp 文件中。

在执行此代码之前,请创建一个文件 C:\Document.txt(因为我使用的是 StgOpenStorageEx,您可以使用 StgCreateStorageEx 来创建新文件)。现在,您可以执行代码了。

在此代码中,我编写然后读取名为“Document”的文件属性的“摘要”选项卡下的“Title”属性。您可以使用此代码获取和设置“摘要”选项卡下的任何属性,只需更改 PROPSPEC 结构中的属性名称(或使用属性 ID)。

// 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;
}
© . All rights reserved.