Как извлечь "Сводку" свойств файла?
Материал из DRKB
Как извлечь "Сводку" свойств файла?[править | править код]
Ниже показан пример получения набора свойств файла (которые отображаются на вкладке "Сводка" диалогового окна "Свойства:"). В файловой системе 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