0

我正在尝试获取文件属性,例如标题、主题、作者、版权、评论和各种文件日期。其他属性会很好,但不是必需的。我的搜索似乎都导致了我在这里这里找到的代码的变体。复制和粘贴代码,我必须做一些调整才能让它工作。我终于能够让它部分工作,但仅限于 .doc 文件。其他文件产生“EOleSysError with message '%1 could not be found'”。我认为这与复合文件有关,但 .docx 和 .xls 文件也发生了同样的错误。

我尝试过 STGFMT_STORAGE、STGFMT_FILE、STGFMT_ANY 和 STGFMT_DOCFILE,但唯一有效的是 STGFMT_ANY。同样,这只适用于 .doc 文件。即使在 .doc 文件上,它也不返回日期,尽管我只将它们视为字符串值。这是我的代码和结果。

在 TListView 中输出

unit u_fSummary;

interface

uses Windows, ComObj, ActiveX, Variants, Sysutils, dialogs;

function GetFileSummaryInfo(const FileName: WideString): String;
function IsNTFS(AFileName : string) : boolean;

implementation

const

FmtID_SummaryInformation: TGUID =     '{F29F85E0-4FF9-1068-AB91-08002B27B3D9}';
FMTID_DocSummaryInformation : TGUID = '{D5CDD502-2E9C-101B-9397-08002B2CF9AE}';
FMTID_UserDefinedProperties : TGUID = '{D5CDD505-2E9C-101B-9397-08002B2CF9AE}';
IID_IPropertySetStorage : TGUID =     '{0000013A-0000-0000-C000-000000000046}';

STGFMT_STORAGE = 0; {Indicates that the file must be a compound file}

STGFMT_FILE =    3; {Indicates that the file must not be a compound file.
                    This element is only valid when using the StgCreateStorageEx
                    or StgOpenStorageEx functions to access the NTFS file system
                    implementation of the IPropertySetStorage interface.
                    Therefore, these functions return an error if the riid
                    parameter does not specify the IPropertySetStorage interface,
                    or if the specified file is not located on an NTFS file system volume.}

STGFMT_ANY =     4; {Indicates that the system will determine the file type and
                    use the appropriate structured storage or property set
                    implementation.
                    This value cannot be used with the StgCreateStorageEx function.}

STGFMT_DOCFILE = 5; {Indicates that the file must be a compound file, and is
                    similar to the STGFMT_STORAGE flag, but indicates that the
                    compound-file form of the compound-file implementation must
                    be used. For more information}


// Summary Information
 PID_TITLE        = 2;
 PID_SUBJECT      = 3;
 PID_AUTHOR       = 4;
 PID_KEYWORDS     = 5;
 PID_COMMENTS     = 6;
 PID_TEMPLATE     = 7;
 PID_LASTAUTHOR   = 8;
 PID_REVNUMBER    = 9;
 PID_EDITTIME     = 10;
 PID_LASTPRINTED  = 11;
 PID_CREATE_DTM   = 12;
 PID_LASTSAVE_DTM = 13;
 PID_PAGECOUNT    = 14;
 PID_WORDCOUNT    = 15;
 PID_CHARCOUNT    = 16;
 PID_THUMBNAIL    = 17;
 PID_APPNAME      = 18;
 PID_SECURITY     = 19;

 // Document Summary Information
 PID_CATEGORY     = 2;
 PID_PRESFORMAT   = 3;
 PID_BYTECOUNT    = 4;
 PID_LINECOUNT    = 5;
 PID_PARCOUNT     = 6;
 PID_SLIDECOUNT   = 7;
 PID_NOTECOUNT    = 8;
 PID_HIDDENCOUNT  = 9;
 PID_MMCLIPCOUNT  = 10;
 PID_SCALE        = 11;
 PID_HEADINGPAIR  = 12;
 PID_DOCPARTS     = 13;
 PID_MANAGER      = 14;
 PID_COMPANY      = 15;
 PID_LINKSDIRTY   = 16;
 PID_CHARCOUNT2   = 17;

function IsNTFS(AFileName : string) : boolean;
var
fso, drv : OleVariant;
begin
  IsNTFS := False;
  fso := CreateOleObject('Scripting.FileSystemObject');
  drv := fso.GetDrive(fso.GetDriveName(AFileName));
  if drv.FileSystem = 'NTFS' then
    IsNTFS := True;
end;

function StgOpenStorageEx (
 const pwcsName : POleStr;  //Pointer to the path of the
                            //file containing storage object
 grfMode : LongInt;         //Specifies the access mode for the object
 stgfmt : DWORD;            //Specifies the storage file format
 grfAttrs : DWORD;          //Reserved; must be zero
 pStgOptions : Pointer;     //Address of STGOPTIONS pointer
 reserved2 : Pointer;       //Reserved; must be zero
 riid : PGUID;              //Specifies the GUID of the interface pointer
 out stgOpen :              //Address of an interface pointer
 IStorage ) : HResult; stdcall; external 'ole32.dll';


function GetFileSummaryInfo(const FileName: WideString): String;
var
  I: Integer;
  PropSetStg: IPropertySetStorage;
  PropSpec: array of TPropSpec;
  PropStg: IPropertyStorage;
  PropVariant: array of TPropVariant;
  Rslt: HResult;
  S: String;
  Stg: IStorage;
  PropEnum: IEnumSTATPROPSTG;
  HR : HResult;
  PropStat: STATPROPSTG;
  k : integer;

      function _PropertyPIDToCaption(const ePID: Cardinal): string;
      begin
        case ePID of
          PID_TITLE:
            Result := 'Title';
          PID_SUBJECT:
            Result := 'Subject';
          PID_AUTHOR:
            Result := 'Author';
          PID_KEYWORDS:
            Result := 'Keywords';
          PID_COMMENTS:
            Result := 'Comments';
          PID_TEMPLATE:
            Result := 'Template';
          PID_LASTAUTHOR:
            Result := 'Last Saved By';
          PID_REVNUMBER:
            Result := 'Revision Number';
          PID_EDITTIME:
            Result := 'Total Editing Time';
          PID_LASTPRINTED:
            Result := 'Last Printed';
          PID_CREATE_DTM:
            Result := 'Create Time/Date';
          PID_LASTSAVE_DTM:
            Result := 'Last Saved Time/Date';
          PID_PAGECOUNT:
            Result := 'Number of Pages';
          PID_WORDCOUNT:
            Result := 'Number of Words';
          PID_CHARCOUNT:
            Result := 'Number of Characters';
          PID_THUMBNAIL:
            Result := 'Thumbnail';
          PID_APPNAME:
            Result := 'Creating Application';
          PID_SECURITY:
            Result := 'Security';
        else
         Result := '$' + IntToHex(ePID, 8);
        end
      end;

begin
 Result := '';
  try

    OleCheck(StgOpenStorageEx(StringToOleStr(FileName), STGM_READ or STGM_SHARE_DENY_WRITE,
      STGFMT_ANY, 0, nil,  nil, @IID_IPropertySetStorage, stg));

    PropSetStg := Stg as IPropertySetStorage;

    OleCheck(PropSetStg.Open(FmtID_SummaryInformation,
      STGM_READ or STGM_SHARE_EXCLUSIVE, PropStg));

    OleCheck(PropStg.Enum(PropEnum));
    i := 0;

    hr := PropEnum.Next(1, PropStat, nil);
    while hr = S_OK do
    begin
      inc(I);
      SetLength(PropSpec,I);
      PropSpec[i-1].ulKind := PRSPEC_PROPID;
      PropSpec[i-1].propid := PropStat.propid;
      hr := PropEnum.Next(1, PropStat, nil);
    end;

    SetLength(PropVariant,i);
    Rslt := PropStg.ReadMultiple(i, @PropSpec[0], @PropVariant[0]);

    if Rslt <>  S_FALSE then;
    begin
    for k := 0 to i -1 do
      begin
        S := '';
        if PropVariant[k].vt = VT_LPSTR then
          if Assigned(PropVariant[k].pszVal) then
           S := PropVariant[k].pszVal;
        S := Trim(Format(_PropertyPIDToCaption(PropSpec[k].Propid)+ ': %s',[s]));
        if S <> '' then Result := Result + S + #176;
      end;
    end;
  finally
  end;
end;

end.
4

0 回答 0