如何用VC++直接读取复合文档属性(如作者、公司、创建时间等)

 

如何读取直接与 VC++ 复合文档属性

概要

没有服务器正在运行甚至安装使用标准接口从文档可检索复合文档属性。 例如, 可检索内置文档属性如 Microsoft Office 97 文档的作者、 上次修改时间和页数属性以及其他自定义文档属性。

更多信息

以下步骤说明如何生成复合文档属性查看器与 VisualC++ Microsoft。 示例是一个 Win 32 控制台应用程序项目, 并可修改以满足需要。

步骤创建示例

1. 创建新的 Win 32 控制台应用程序项目, 并 PropDump 调用它。
2. 添加新文件称为 main.cpp 到项目。
3. 将以下代码复制到 main.cpp:
   
         
         
         
         
   #include  < stdio.h >
   #include 
< windows.h >
   #include 
< ole2.h >
   #include 
< locale.h >



   
//  Dumps simple PROPVARIANT values.
    void  DumpPropVariant(PROPVARIANT  * pPropVar)  {
      
// Don't iterate arrays, just inform as an array.
      if(pPropVar->vt & VT_ARRAY) {
         printf(
"(Array) ");
         
return;
      }


      
// Don't handle byref for simplicity, just inform byref.
      if(pPropVar->vt & VT_BYREF) {
         printf(
"(ByRef) ");
         
return;
       }


      
// Switch types.
      switch(pPropVar->vt) {
      
case VT_EMPTY:
         printf(
"(VT_EMPTY) ");
         
break;
      
case VT_NULL:
         printf(
"(VT_NULL) ");
         
break;
      
case VT_BLOB:
         printf(
"(VT_BLOB) ");
         
break;
      
case VT_BOOL:
         printf(
"%s (VT_BOOL) ",
         pPropVar
->boolVal ? "TRUE/YES" : "FALSE/NO");
         
break;
      
case VT_I2: // 2-byte signed int.
         printf("%d (VT_I2) ", (int)pPropVar->iVal);
         
break;
      
case VT_I4: // 4-byte signed int.
         printf("%d (VT_I4) ", (int)pPropVar->lVal);
         
break;
      
case VT_R4: // 4-byte real.
         printf("%.2lf (VT_R4) ", (double)pPropVar->fltVal);
         
break;
      
case VT_R8: // 8-byte real.
         printf("%.2lf (VT_R8) ", (double)pPropVar->dblVal);
         
break;
         
case VT_BSTR: // OLE Automation string.
         {
            
// Translate into ASCII.
            char dbcs[1024];
            
char *pbstr = (char *)pPropVar->bstrVal;
            
int i = wcstombs(
            dbcs, pPropVar
->bstrVal, *((DWORD *)(pbstr-4)));
            dbcs[i] 
= 0;
            printf(
"%s (VT_BSTR) ", dbcs);
         }

         
break;
      
case VT_LPSTR: // Null-terminated string.
         {
         printf(
"%s (VT_LPSTR) ", pPropVar->pszVal);
         }

         
break;
      
case VT_FILETIME:
         
{
            
char *dayPre[] =
                         
{"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};

            FILETIME lft;
            FileTimeToLocalFileTime(
&pPropVar->filetime, &lft);                SYSTEMTIME lst;
            FileTimeToSystemTime(
&lft, &lst);

            printf(
"%02d:%02d.%02d %s, %s %02d/%02d/%d (VT_FILETIME) ",
               
1+(lst.wHour-1)%12, lst.wMinute, lst.wSecond,
               (lst.wHour
>=12? "pm" : "am",
               dayPre[lst.wDayOfWeek
%7],
               lst.wMonth, lst.wDay, lst.wYear);
         }

         
break;
      
case VT_CF: // Clipboard format.
         printf("(Clipboard format) ");

         
break;
      
default// Unhandled type, consult wtypes.h's VARENUM structure.
         printf("(Unhandled type: 0x%08lx) ", pPropVar->vt);
         
break;
      }

   }


   
//  Dump's built-in properties of a property storage.
    void  DumpBuiltInProps(IPropertySetStorage  * pPropSetStg)  {
      printf(
" ================================================== ");
      printf(
"BuiltInProperties Properties... ");
      printf(
"================================================== ");

      IPropertyStorage 
*pPropStg = NULL;
      HRESULT hr;

      
// Open summary information, getting an IpropertyStorage.
      hr = pPropSetStg->Open(FMTID_SummaryInformation,
      STGM_READ 
| STGM_SHARE_EXCLUSIVE, &pPropStg);
      
//hr = pPropSetStg->Open(FMTID_UserDefinedProperties,
         
//STGM_READ | STGM_SHARE_EXCLUSIVE, &pPropStg);
      if(FAILED(hr)) {
         printf(
"No Summary-Information. ");
         
return;
      }

      
// Array of PIDSI's you are interested in.
      struct pidsiStruct {
         
char *name;
         
long pidsi;
      }
 pidsiArr[] = {
         
{"Title",            PIDSI_TITLE}// VT_LPSTR
         {"Subject",          PIDSI_SUBJECT}// ...
         {"Author",           PIDSI_AUTHOR},
         
{"Keywords",         PIDSI_KEYWORDS},
         
{"Comments",         PIDSI_COMMENTS},
         
{"Template",         PIDSI_TEMPLATE},
         
{"LastAuthor",       PIDSI_LASTAUTHOR},
         
{"Revision Number",  PIDSI_REVNUMBER},
         
{"Edit Time",        PIDSI_EDITTIME}// VT_FILENAME (UTC)
         {"Last printed",     PIDSI_LASTPRINTED}// ...
         {"Created",          PIDSI_CREATE_DTM},
         
{"Last Saved",       PIDSI_LASTSAVE_DTM},
         
{"Page Count",       PIDSI_PAGECOUNT}// VT_I4
         {"Word Count",       PIDSI_WORDCOUNT}// ...
         {"Char Count",       PIDSI_CHARCOUNT},

         
{"Thumpnail",        PIDSI_THUMBNAIL}// VT_CF
         {"AppName",          PIDSI_APPNAME}// VT_LPSTR
         {"Doc Security",     PIDSI_DOC_SECURITY}// VT_I4
         {00}
      }
;
      
// Count elements in pidsiArr.
      int nPidsi = 0;
      
for(nPidsi=0; pidsiArr[nPidsi].name; nPidsi++);

      
// Initialize PROPSPEC for the properties you want.
      PROPSPEC *pPropSpec = new PROPSPEC [nPidsi];
      PROPVARIANT 
*pPropVar = new PROPVARIANT [nPidsi];

      
for(int i=0; i<nPidsi; i++{
         ZeroMemory(
&pPropSpec[i], sizeof(PROPSPEC));
         pPropSpec[i].ulKind 
= PRSPEC_PROPID;
         pPropSpec[i].propid 
= pidsiArr[i].pidsi;
      }




      
// Read properties.
      hr = pPropStg->ReadMultiple(nPidsi, pPropSpec, pPropVar);

      
if(FAILED(hr)) {
         printf(
"IPropertyStg::ReadMultiple() failed w/error %08lx ",
                hr);
      }

      
else {
         
// Dump properties.
         for(i=0; i<nPidsi; i++{
            printf(
"%16s: ", pidsiArr[i].name);
            DumpPropVariant(pPropVar 
+ i);
         }

      }


      
// De-allocate memory.
      delete [] pPropVar;
      delete [] pPropSpec;

      
// Release obtained interface.
      pPropStg->Release();

   }


   
//  Dump's custom properties of a property storage.
    void  DumpCustomProps(IPropertySetStorage  * pPropSetStg)  {
      printf(
" ================================================== ");
      printf(
"Custom Properties... ");
      printf(
"================================================== ");

      IPropertyStorage 
*pPropStg = NULL;
      HRESULT hr;
      IEnumSTATPROPSTG 
*pEnumProp;

      
// Open User-Defined-Properties, getting an IpropertyStorage.
      hr = pPropSetStg->Open(FMTID_UserDefinedProperties,
         STGM_READ 
| STGM_SHARE_EXCLUSIVE, &pPropStg);
      
if(FAILED(hr)) {
         printf(
"No User Defined Properties. ");
         
return;
      }


      
// Get property enumerator.
      hr = pPropStg->Enum(&pEnumProp);
      
if(FAILED(hr)) {
      pPropStg
->Release();
         printf(
"Couldn't enumerate custom properties. ");
         
return;
      }


      
// Enumerate properties.
      STATPROPSTG sps;
      ULONG fetched;
      PROPSPEC propSpec[
1];
      PROPVARIANT propVar[
1];
      
while(pEnumProp->Next(1&sps, &fetched) == S_OK) {
         
// Build a PROPSPEC for this property.
         ZeroMemory(&propSpec[0], sizeof(PROPSPEC));
         propSpec[
0].ulKind = PRSPEC_PROPID;
         propSpec[
0].propid = sps.propid;

         
// Read this property.

         hr 
= pPropStg->ReadMultiple(1&propSpec[0], &propVar[0]);
         
if(!FAILED(hr)) {
            
// Translate Prop name into ASCII.
            char dbcs[1024];
            
char *pbstr = (char *)sps.lpwstrName;
            
int i = wcstombs(dbcs, sps.lpwstrName,
                             
*((DWORD *)(pbstr-4)));
            dbcs[i] 
= 0;

            
// Dump this property.
            printf("%16s: ", dbcs);
            DumpPropVariant(
&propVar[0]);
         }

      }


      
// Release obtained interface.
      pEnumProp->Release();
      pPropStg
->Release();

   }


   
//  Dump's custom and built-in properties of a compound document.
    void  DumpProps( char   * filename)  {
      
// Translate filename to Unicode.
      WCHAR wcFilename[1024];
      setlocale( LC_ALL, 
"" );
      
int i = mbstowcs(wcFilename, filename, strlen(filename));
      setlocale( LC_ALL, 
"C" );
      wcFilename[i] 
= 0;

      IStorage 
*pStorage = NULL;
      IPropertySetStorage 
*pPropSetStg = NULL;
      HRESULT hr;

      
// Open the document as an OLE compound document.
      hr = ::StgOpenStorage(wcFilename, NULL,
      STGM_READ 
| STGM_SHARE_EXCLUSIVE, NULL, 0&pStorage);

      
if(FAILED(hr)) {
         
if(hr == STG_E_FILENOTFOUND)
            printf(
"File not found.");
         
else if(hr == STG_E_FILEALREADYEXISTS)
            printf(
"Not a compound file.");
         
else
            printf(
"StgOpenStorage() failed w/error %08lx", hr);
         
return;
      }


      
// Obtain the IPropertySetStorage interface.
      hr = pStorage->QueryInterface(
              IID_IPropertySetStorage, (
void **)&pPropSetStg);
      
if(FAILED(hr)) {
         printf(
"QI for IPropertySetStorage failed w/error %08lx", hr);
         pStorage
->Release();
         
return;
      }


      
// Dump properties.
      DumpBuiltInProps(pPropSetStg);
      DumpCustomProps(pPropSetStg);

      
// Release obtained interfaces.
      pPropSetStg->Release();
      pStorage
->Release();
   }


   
//  Program entry-point.
    void  main( int  argc,  char   ** argv)  {
      
// Validate arguments.
      if(argc != 2{
         printf(
"- OLE Document Property Viewer ");
         printf(
"- Usage: %s filename", argv[0]);
         
return;
      }


      
// Pass filename to the subroutine.
      DumpProps(argv[1]);
   }

4. 编译程序。
要运行示例, 您应将 PropDump.exe 文件默认路径中目录 ; 例如 c:/Windows/ 或 c:/Windows/Command/。 在包含复合文档文件, 目录, 然后键入 PropDump 跟文件的名称。 您应看到类似于以下输出:

 ================================================== 
           Title: MyTitle (VT_LPSTR)
         Subject: MySubject (VT_LPSTR)
          Author: MyAuthor (VT_LPSTR)
        Keywords: MyKeywords (VT_LPSTR)
        Comments: MyComments (VT_LPSTR)
        Template: Normal (VT_LPSTR)
      LastAuthor: Me (VT_LPSTR)

 Revision Number: 8 (VT_LPSTR)

       Edit Time: 01:05.47 pm, Mon 01/01/1601 (VT_FILETIME)
    Last printed: (VT_EMPTY)
         Created: 01:42.00 pm, Fri 05/29/1998 (VT_FILETIME)
      Last Saved: 12:31.00 pm, Mon 06/01/1998 (VT_FILETIME)
      Page Count: 1 (VT_I4)
      Word Count: 3 (VT_I4)
      Char Count: 19 (VT_I4)
       Thumpnail: (VT_EMPTY)
         AppName: Microsoft Word 8.0 (VT_LPSTR)
    Doc Security: 0 (VT_I4)
                ================================================== 
 
   _PID_LINKBASE: (VT_BLOB)

       _PID_GUID: (VT_BLOB)
       CustProp1: CustProp1TextValue (VT_LPSTR)
       CustProp2: 77777 (VT_I4)
       CustProp3: TRUE/YES (VT_BOOL)
       CustProp4: 00:00.00 am, Tue 05/17/1977 (VT_FILETIME)
   

其他备注

是原始版本的 COM 中未定义 IPropertyStorage 和 IPropertySetStorage 接口 ; 因此示例代码需要与系统:
Windows NT 4.0 或更高
Windows 95 与 Internet Explorer Version 4.0 或更高版本
用安装 DCOM 95
非常指定 COM 的早期版本少用尊重和属性及其用法, 但做定义序列化格式允许开发人员 IStorage 实例中存储属性和属性集。 还定义属性标识符和语义的单个属性集, 用于文档, 摘要信息。 此时, 它是需要创建和操纵结构直接作为数据流。 有关详细信息属性上设置序列化数据格式结构, 在 Microsoft Developer Network 引用到 " OLE 系列属性设置格式 "。

(c) Microsoft Corporation 1999, 保留所有权利。 由 Joe, Crump MicrosoftCorporation 供稿。
 

参考

Microsoft Developer Network: 永久属性集

Microsoft Developer Network: OLE 序列属性设置格式
 
这篇文章中的信息适用于:
Microsoft Project 2000 Standard Edition
Microsoft Excel 2000 Standard Edition
Microsoft Visual C++ 5.0 Enterprise Edition
Microsoft Visual C++ 5.0 Professional Edition
Microsoft Excel 97 Standard Edition
Microsoft PowerPoint 97 Standard Edition
Microsoft Word 97 Standard Edition
Microsoft PowerPoint 2000 Standard Edition
Microsoft Word 2000 Standard Edition
Microsoft Excel 2002 Standard Edition
Microsoft PowerPoint 2002 Standard Edition
Microsoft Word 2002 Standard Edition
 
关键字: 
kbhowto kbcmpdoc kbfaq KB186898 KbMtzh kbmt
 
Microsoft和/或其各供应商对于为任何目的而在本服务器上发布的文件及有关图形所含信息的适用性,不作任何声明。 所有该等文件及有关图形均"依样"提供,而不带任何性质的保证。Microsoft和/或其各供应商特此声明,对所有与该等信息有关的保证和条件不负任何责任,该等保证和条件包括关于适销性、符合特定用途、所有权和非侵权的所有默示保证和条件。在任何情况下,在由于使用或运行本服务器上的信息所引起的或与该等使用或运行有关的诉讼中,Microsoft和/或其各供应商就因丧失使用、数据或利润所导致的任何特别的、

你可能感兴趣的:(如何用VC++直接读取复合文档属性(如作者、公司、创建时间等))