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

=== Как извлечь "Сводку" свойств файла? ===
Ниже показан пример получения набора свойств файла (которые отображаются на вкладке "Сводка" диалогового окна "Свойства:"). В файловой системе 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.
Author: Krid
Source: Взято из http://forum.sources.ru
ID: 03147
Category:Файловая система