4

In a similar vein to this question, I'm after a way to pragmatically read the information in the "details" pane that is shown when you select "properties" in explorer.

For example in the screenshots below,

screenshot

a few random details are circled.

i am not after a way to determine the specific items circled in some other way (eg please don't suggest how to find out the width in pixels of an image) that is not what i am after. i need a way to parse all the information that is available, for display purposes in my own program, without having to "know" about the files myself. this is simply to create a specific user interface without having to actually open up the Dialogs shown.

For what its worth, the language du jour is Delphi, but i am quite capable of translating c++ or any other dialect of winapi code, but if you happen to have delphi code, that would be a bonus for me personally.

edit: i'd like to be able to get document specific details, eg the slide count in a powerPoint document, which does not conform to the standardarized constants you need to access properties that most documents have.

i can for example get some basic information from a powerpoint document using this code (but not the slide count).

uses shellapi,ComObj;
{$R *.dfm}

const
  FmtID_SummaryInformation: TGUID =
    '{F29F85E0-4FF9-1068-AB91-08002B27B3D9}';

function FileTimeToDateTimeStr(F: TFileTime): string;
var
  LocalFileTime: TFileTime;
  SystemTime: TSystemTime;
  DateTime: TDateTime;
begin
  if Comp(F) = 0 then Result := '-'
  else
  begin
    FileTimeToLocalFileTime(F, LocalFileTime);
    FileTimeToSystemTime(LocalFileTime, SystemTime);
    with SystemTime do
      DateTime := EncodeDate(wYear, wMonth, wDay) +
        EncodeTime(wHour, wMinute, wSecond, wMilliseconds);
    Result := DateTimeToStr(DateTime);
  end;
end;

function GetDocInfo(const FileName: WideString): string;
var
  I: Integer;
  PropSetStg: IPropertySetStorage;
  PropSpec: array[2..19] of TPropSpec;
  PropStg: IPropertyStorage;
  PropVariant: array[2..19] of TPropVariant;
  Rslt: HResult;
  S: string;
  Stg: IStorage;
begin
  Result := '';
  try
    OleCheck(StgOpenStorage(PWideChar(FileName), nil, STGM_READ or
      STGM_SHARE_DENY_WRITE,
      nil, 0, Stg));
    PropSetStg := Stg as IPropertySetStorage;
    OleCheck(PropSetStg.Open(FmtID_SummaryInformation,
      STGM_READ or STGM_SHARE_EXCLUSIVE, PropStg));
    for I := 2 to 19 do
    begin
      PropSpec[I].ulKind := PRSPEC_PROPID;
      PropSpec[I].PropID := I;
    end;
    Rslt := PropStg.ReadMultiple(18, @PropSpec, @PropVariant);
    OleCheck(Rslt);
    if Rslt <> S_FALSE then for I := 2 to 19 do
      begin
        S := '';
        if PropVariant[I].vt = VT_LPSTR then
          if Assigned(PropVariant[I].pszVal) then
            S := PropVariant[I].pszVal;
            case I of
              2:  S  := Format('Title: %s', [S]);
              3:  S  := Format('Subject: %s', [S]);
              4:  S  := Format('Author: %s', [S]);
              5:  S  := Format('Keywords: %s', [S]);
              6:  S  := Format('Comments: %s', [S]);
              7:  S  := Format('Template: %s', [S]);
              8:  S  := Format('Last saved by: %s', [S]);
              9:  S  := Format('Revision number: %s', [S]);
              10: S := Format('Total editing time: %g sec',
                  [Comp(PropVariant[I].filetime) / 1.0E9]);
              11: S := Format('Last printed: %s',
                  [FileTimeToDateTimeStr(PropVariant[I].filetime)]);
              12: S := Format('Create time/date: %s',
                  [FileTimeToDateTimeStr(PropVariant[I].filetime)]);
              13: S := Format('Last saved time/date: %s',
                  [FileTimeToDateTimeStr(PropVariant[I].filetime)]);
              14: S := Format('Number of pages: %d', [PropVariant[I].lVal]);
              15: S := Format('Number of words: %d', [PropVariant[I].lVal]);
              16: S := Format('Number of characters: %d',
                  [PropVariant[I].lVal]);
              17:; // thumbnail
              18: S := Format('Name of creating application: %s', [S]);
              19: S := Format('Security: %.8x', [PropVariant[I].lVal]);
            else
               S := Format('unknown property#%d: %s', [i,S]);

        end;
        if S <> '' then Result := Result + S + #13#10;
      end;
  finally
  end;
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  memo1.text :=GetDocInfo('C:\mypowerpoint.ppt');
end;
Community
  • 1
  • 1
unsynchronized
  • 4,828
  • 2
  • 31
  • 43
  • 5
    Start here: http://msdn.microsoft.com/en-gb/library/windows/desktop/ff728871.aspx – David Heffernan Mar 26 '13 at 09:40
  • 1
    @DavidHeffernan i had looked at that previously, and determined that it's not very obvious how to get much more than the basic properties. what my screenshots don't show is there are often more sections that are specific to the document type. for example in powerpoint there is a number of slides property. i can get all of the basic document properties like title, and word count, author etc, but anything more specific is not available. – unsynchronized Mar 26 '13 at 11:22
  • 1
    I concur that it's not the easiest API to use, but all the information is available through the properties store – David Heffernan Mar 26 '13 at 11:31
  • @DavidHeffernan thanks for your input. i have managed to get something working which will suffice for now, however it does rely somewhat on having predefined constants. i will leave this question open in case someone has an easy solution to get a simple list of properties, including their human readable descriptions. – unsynchronized Mar 26 '13 at 14:11

1 Answers1

2

There are samples in C++ in the Windows 7 SDK that demonstrate property enumeration (under Samples\winui\shell\appplatform\PropertyEdit), as well as a longer demo on CodePlex.

There isn't a "canonical" list of properties, as the property system is extensible; however, the Microsoft list of properties is part of the SDK and is found in propkey.h.

Eric Brown
  • 13,774
  • 7
  • 30
  • 71