Visit our Sponsor   Visit our Sponsor
delphi3000.com - the free delphi knowledge platform
delphi3000.com - the free delphi knowledge platform
Have a look at your member-status

connecting people's knowledge


  - Recent ArticlesRSS feed for Recent Articles on delphi3000.com
  - List of All Articles
  - Top Viewed Articles
  - Articles (+Attachem.)
  - Articles Of Interest
  - Categories
  - Top Uploader
  - Search
  - Index

  - My Home
  - Submit an Article
  - My Articles
  - My Personal Data
  - My Bookmarks
  - Activities
  - Login/Logout

  - Sign Up
  - Why Sign Up
  - Newsletter

  - Press
  - Advertise

  - Contact
  - Feedback





Community
Borland
ClubeDelphi
Dr. Bob
UK-BUG
Delphi Meetings
Planeta Delphi







Startblatt.de






Share this article with friendsShare this article with friends
Rate this articleRate this article - to keep the quality of delphi3000.com !
Comment this article or read through previous comments (6)


Give Me the Details or File Summary Info Go to Serhiy Perevoznyk's websiteFormat this article printer-friendly!Bookmark function is only available for registered users!
Product:
Delphi all versions
Category:
Win API
Skill Level:
Scoring:
Last Update:
04/11/2003
Search Keys:
delphi delphi3000 article borland vcl code-snippet StgOpenStorageEx
Times Scored:
3
Visits:
4785
Uploader: Serhiy Perevoznyk
Company: http://users.chello.be/ws36637
Reference: N/A
 
Question/Problem/Abstract:
How to retrieve File Summary Information for non Office files
Answer:



On Windows 2000 you can right-click in Explorer to get the file properties on any file and can associate summary information to any type of files, including even text files.

For Word or Excel documents (compound files) the summary information is a part of document itself.
For other files the way of storing additional information are different. This feature are only available on volumes formatted with NTFS. The NTFS implementation stores property sets in alternate streams of an NTFS file. The alternate streams must be copied when the main file is copied. However, not all file systems support such streams. For example, if an NTFS file with property sets is copied to a FAT volume, only the data in the file is copied; the property set is lost.

First thing you probably want do is to detect whether the current volume is NTFS:

// IsNTFS() - Verifies whether the file's volume is NTFS
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;

But how to read these properties? Is it really nessesary to work with a streams?
No, NTFS file system 5.0 provides an implementation of IPropertySetStorage interface for files on an NTFS volume when the files themselves are not compound files. To get a pointer to the NTFS implementation of IPropertySetStorage, we have to call the StgCreateStorageEx function:

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';


All Microsoft Windows 2000 applications should use this new function, StgOpenStorageEx, instead of StgOpenStorage, to take advantage of the enhanced Windows 2000 Structured Storage features.

The implementation of IPropertySetStorage on NTFS file system is similar with compound file implementation and available only on Windows 2000. Windows 95 and Windows NT 4.0 and earlier versions cannot access this interface.
However, you cannot obtain the NTFS implementation of IPropertySetStorage for a compound file. When opening a compound file with StgOpenStorage, specifying the STGFMT_FILE enumeration value results in an error.

The next function dumps all properties of the specific file. By changing  the STGFMT_FILE flag in the StgOpenStorageEx call to STGMT_ANY you can open a Structured Storage property set or an NTFS file system property set.

function GetFileSummaryInfo(const FileName: WideString): String;

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}';

const
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.


// 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;

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(PWideChar(FileName),
STGM_READ or STGM_SHARE_DENY_WRITE,
STGFMT_FILE,
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 Exit;

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 := Format(PropertyPIDToCaption(PropSpec[k].Propid)+ ' %s',[s]);
   if S <> '' then Result := Result + S + #13;
end;
finally
end;
end;





Please rate this article!
Skill level:
BeginnerExpert

Useful:
No!Very!

Overall rating:
PoorExcellent



Comments to this article
Write a new comment
Category Info
    John Doe (Nov 16 2004 6:18AM)

nice...but I can't seem to get the "Category" info.
The rest like Title, Comments or Subject can be retrieved but not Category :(

Any ideas?
Respond

RE: Category Info
Serhiy Perevoznyk (Nov 16 2004 9:23PM)

The text properties can be stored as Ansi string or Wide string.
For reading both types is nessesary to make following changes:

  if PropVariant[I].vt = VT_LPSTR then
    Result := PropVariant[I].pszVal
      else
        if PropVariant[I].vt = VT_LPWSTR then
          Result := PropVariant[I].pwszVal;

Respond

RE: RE: Category Info
John Doe (Nov 17 2004 5:23AM)

hmmm...not quite. the problem lies before that code. but i figured it out anyway. i need to pass FMTID_DocSummaryInformation to PropSetStg.Open method since Category is actually part of Doc Summary Information.

but thanks for you reply Serhiy !
Respond

RE: Category Info
Serhiy Perevoznyk (Nov 17 2004 6:56PM)

I made more detail example how to read and write File Summary Info, including SummaryInformation, DocSummaryInformation and UserDefinedProperties.

http://users.chello.be/ws36637/download/psvFileProperties.zip
Respond

nice, but...
    hupu hupu (Aug 20 2004 1:43PM)

OK, but could you please tell what units to include to make this work?
Respond

RE: nice, but...
Serhiy Perevoznyk (Nov 16 2004 9:17PM)

Windows, Sysutils, ActiveX
Respond














 
Sign up to consume product discounts for Bronze memberships !

read more


  Visit our Sponsor

 

  Community Ad of
M. Kleiner
 
   














 







     
  Copyright © 2000 - 2007 delphi3000.com - All rights reserved. Terms of use. || Privacy
delphi3000.com is a service by bluestep.com IT-Services GmbH (Vienna)