Sources
Delphi Russian Knowledge Base
DRKB - это самая большая и удобная в использовании база знаний по Дельфи в рунете, составленная Виталием Невзоровым

Как извлечь «Сводку» свойств файла?

01.01.2007

Ниже показан пример получения набора свойств файла (которые отображаются на вкладке "Сводка" диалогового окна "Свойства:").
В файловой системе NTFS читаются свойства любого файла (если они вообще есть, конечно). В других ФС читаются св-ва только compound-файлов (они же structured storage, т.е. файлы хранения структурированной информации, такие как файлы MS Office, пакеты MSI, etc.), т.к. в этом случае вся информация о св-вах находится в самих файлах (опять же, она может там и отсутствовать). Ну и, естественно, не читаются нестандартные свойства, т.к. они нигде не хранятся, а динамически добавляются на вкладку соответствующим файлу COM-сервером - обработчиком вкладок св-в (PropertySheetHandlers).

В этом примере считывается несколько св-в из набора SummaryInformation.

unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls;
 
type
  TForm1 = class(TForm)
    Button1: TButton;
    ListView1: TListView;
    OpenDialog1: TOpenDialog;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
uses ActiveX, ComObj;
 
function StgOpenStorageEx(const pwcsName : POleStr; grfMode : LongInt; stgfmt : DWORD;
                           grfAttrs : DWORD;  pStgOptions : Pointer; reserved2 : Pointer;
                            riid : PGUID; out stgOpen : IStorage ) : HResult; stdcall; external 'ole32.dll';
 
 
const
// GUID'ы для набора св-в SummaryInformation
 FMTID_SummaryInformation  : TGUID = '{F29F85E0-4FF9-1068-AB91-08002B27B3D9}';
 IID_IPropertySetStorage   : TGUID = '{0000013A-0000-0000-C000-000000000046}';
 
  STGFMT_FILE = 3;
  STGFMT_ANY = 4;
 
type
 PPropSpecArray=^TPropSpecArray;  // массив спецификаций св-в
 TPropSpecArray=array[0..999] of TPropSpec; 
 
 PPropVariantArray=^TPropVariantArray; // массив - приемник, куда будут помещены значения нужных св-в
 TPropVariantArray=array[0..999] of TPropVariant;
 
 
// вспомогательные ф-ции  *******
 
function IsNTFS(AFileName : string) : boolean;
var
 fso, drv : OleVariant;
begin
 fso := CreateOleObject('Scripting.FileSystemObject');
 drv := fso.GetDrive(fso.GetDriveName(AFileName));
 Result:=drv.FileSystem = 'NTFS'
end;
 
function FileTimeToLocalSystemTime(ft:FILETIME):TSystemTime;
var
 t:FILETIME;
begin
 FileTimeToLocalFileTime(ft,t);
 FileTimeToSystemTime(t,result);
end;
 
function SysTimeToStr(ST : TSystemTime):string;
begin
 SetLength(result,15);
 GetTimeFormat(LOCALE_USER_DEFAULT,0,@st,nil,@result[1],15);
 SetLength(result, StrLen(@result[1]));
end;
 
function SysDateToStr(ST : TSystemTime) : string;
begin
 SetLength(Result, 255);
 GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, @ST, nil, @result[1], 255);
 SetLength(Result, LStrLen(@result[1]));
end;
 
function SysDateTimeToStr(ST:TSystemTime):string;
begin
 result:=SysDateToStr(ST)+' '+SysTimeToStr(ST)
end;
 
// *******
 
procedure TForm1.Button1Click(Sender: TObject);
var
 stgRoot:IStorage;
 stgPS:IPropertySetStorage;
 stgP:IPropertyStorage;
 ps:PPropSpecArray;
 pv:PPropVariantArray;
 lit:TListItem;  // значения св-в записываем в ListView
begin
 
 if (not OpenDialog1.Execute) then exit;  // выбираем файл
 
 // Проверяем: если это не compound file и система - не NTFS, тогда выходим.
 // (для compound файлов FS не важна)
 if (StgIsStorageFile(StringToOleStr(OpenDialog1.FileName))<>S_OK) then
  if (not IsNTFS(OpenDialog1.FileName)) then
  begin
   MessageBox(Handle,'NTFS needed for non-compound files','Error',MB_ICONERROR);
   exit;
  end;
 
 
  ListView1.Clear;
 
  if (StgOpenStorageEx(StringToOleStr(OpenDialog1.FileName), STGM_READ or STGM_SHARE_DENY_WRITE,
                        STGFMT_ANY, 0, nil,  nil, 
                       @IID_IPropertySetStorage, stgRoot)<>S_OK) then  // открываем файл
  begin
   MessageBox(Handle,'Can not open file','Error',MB_ICONERROR);
   exit;
  end;
 
 stgPS:=stgRoot as IPropertySetStorage;  // ссылаемся на нужный интерфейс
//открываем набор св-в
 if (stgPS.Open(FMTID_SummaryInformation,STGM_READ or STGM_SHARE_EXCLUSIVE,stgP)<>S_OK) then
 begin
  MessageBox(Handle,'Can not open property set','Error',MB_ICONERROR);
  exit;
 end;
 
 ps:=nil;
 pv:=nil;
 try
   GetMem(ps,SizeOf(TPropSpec));
   GetMem(pv,SizeOf(TPropVariant));
 
   ps[0].ulKind:=PRSPEC_PROPID;   // считываем св-ва по их идентификатору (см. ActiveX.pas)
 
//  Прочитаем несколько св-в файла.
//  В этом примере - для наглядности - читаем по одному св-ву из потока (можно за один раз прочитать и больше),
//  поэтому каждый раз значение будет лежать в pv[0].
 
   ps[0].propid:=PIDSI_TITLE;     // заголовок
   lit:=ListView1.Items.Add;
   lit.Caption:='Title';
   if (stgP.ReadMultiple(1, @ps[0], @pv[0])=S_OK) then  // читаем св-во
   lit.SubItems.Add(pv[0].pszVal) // добавляем в ListView
   else lit.SubItems.Add('');
 
   ps[0].propid:=PIDSI_SUBJECT;   // тема
   lit:=ListView1.Items.Add;
   lit.Caption:='Subject';
   if (stgP.ReadMultiple(1, @ps[0], @pv[0])=S_OK) then
   lit.SubItems.Add(pv[0].pszVal)
   else lit.SubItems.Add('');
 
   ps[0].propid:=PIDSI_AUTHOR;   // автор
   lit:=ListView1.Items.Add;
   lit.Caption:='Author';
   if (stgP.ReadMultiple(1, @ps[0], @pv[0])=S_OK) then
   lit.SubItems.Add(pv[0].pszVal)
   else lit.SubItems.Add('');
 
   ps[0].propid:=PIDSI_COMMENTS; // комментарий
   lit:=ListView1.Items.Add;
   lit.Caption:='Comment';
   if (stgP.ReadMultiple(1, @ps[0], @pv[0])=S_OK) then
   lit.SubItems.Add(pv[0].pszVal)
   else lit.SubItems.Add('');
 
   ps[0].propid:=PIDSI_REVNUMBER; // номер редакции
   lit:=ListView1.Items.Add;
   lit.Caption:='Revision';
   if (stgP.ReadMultiple(1, @ps[0], @pv[0])=S_OK) then
   lit.SubItems.Add(pv[0].pszVal)
   else lit.SubItems.Add('');
 
   ps[0].propid:=PIDSI_APPNAME;   // приложение, создавшее пакет
   lit:=ListView1.Items.Add;
   lit.Caption:='Application';
   if (stgP.ReadMultiple(1, @ps[0], @pv[0])=S_OK) then
   lit.SubItems.Add(pv[0].pszVal)
   else lit.SubItems.Add('');
 
   ps[0].propid:=PIDSI_CREATE_DTM;   // Дата создания
   lit:=ListView1.Items.Add;
   lit.Caption:='Creation date';
   if (stgP.ReadMultiple(1, @ps[0], @pv[0])=S_OK) then
   lit.SubItems.Add(SysDateTimeToStr(FileTimeToLocalSystemTime(pv[0].filetime)))
   else lit.SubItems.Add('');
 
   ps[0].propid:=PIDSI_WORDCOUNT; // кол-во слов в документе
   lit:=ListView1.Items.Add;
   lit.Caption:='Word count';
   if (stgP.ReadMultiple(1, @ps[0], @pv[0])=S_OK) then
   lit.SubItems.Add(IntToStr(pv[0].lVal))
   else lit.SubItems.Add('');
 
 finally
   if assigned(ps) then FreeMem(ps);
   if assigned(pv) then FreeMem(pv);
   stgP:=nil;
   stgPS:=nil;
   stgRoot:=nil;
 end;
end;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
 // добавим в список 2 столбца (лучше это делать в дизайнере)
 ListView1.ViewStyle:=vsReport;
 ListView1.Columns.Add.Caption:='Name';
 ListView1.Columns.Add.Caption:='Value';
 
 // добавим в диалог открытия несколько типов compound-файлов
 OpenDialog1.Filter:='All Files (*.*)|*.*|MS Office Documents (*.doc;*.xls;*.dot)'+
  '|*.doc; *.xls; *.dot|MSI Databases (*.msi)|*.msi';
end;
 
end.

Взято из https://forum.sources.ru

Автор: Krid