Реализация Delphi IFilter

Мне нужно реализовать фильтр IFilter в Delphi 2010, который может выполнять поиск в файлах docx Office 2007 и возвращать текст, найденный в документе.

ifilter также должен использовать интерфейс IPersistStream.

Спасибо


person Phillip Roux    schedule 15.07.2010    source источник
comment
У вас есть конкретный вопрос? Как много вы уже знаете по рассматриваемой теме и в какой части вам нужна помощь?   -  person Mason Wheeler    schedule 15.07.2010


Ответы (2)


Вы не хотите реализовать IFilter для анализа docx Office 2007. Вы хотите использовать Microsoft уже написанные IFilter объекты, чтобы вы могли изучить содержимое docx файла.

Затем вы используете стандартные механизмы IFilter для разбора содержимого файла:

procedure TForm1.ProcessFile(filename: string);
var
    Filter: IFilter;
    hr: HRESULT;
    chunk: PSTAT_CHUNK;
//  attr: FULLPROPSPEC;
    flags: ULONG;
    c: Cardinal;
    buffer: WideString;
begin
    Log('Processing "'+filename+'"');

    Log('Calling LoadIFilter');
    filter := LoadIFilter(filename);
    if filter = nil then
    begin
        Log('filter is null; leaving');
        Exit;
    end;
    try
        Log('Calling filter.Init(IFILTER_INIT_INDEXING_ONLY)');
        hr := filter.Init(IFILTER_INIT_INDEXING_ONLY, 0, nil, flags);
        OleCheck(hr);

        Log('Init returned sucessfully, looking for chunks...');
        while True do
        begin
            New(chunk);
            try
                hr := filter.GetChunk(chunk);
                if Failed(hr) then
                begin
                    Log('No more chunks: '+IntToHex(hr, 8)+' ('+GetChunkHresultToStr(hr)+')');
                    Break;
                end;

                Log('== Got chunk. ChunkType='+IntToStr(chunk.flags)+' (1=text, 2=value) ==');

                if (chunk.Flags and CHUNK_TEXT) = CHUNK_TEXT then
                begin
                    c := 2048;
                    SetLength(buffer, c);
                    hr := filter.GetText(c, PWideChar(buffer));
                    if Succeeded(hr) then
                    begin
                        Log('=== Got text ===');
                        SetLength(buffer, c);
                        Log(buffer);

                        while Succeeded(hr) do
                        begin
                            c := 2048;
                            SetLength(buffer, c);
                            hr := filter.GetText(c, PWideChar(buffer));
                            if Succeeded(hr) then
                            begin
                                SetLength(buffer, c);
                                Log('==== Really long chunk, here''s the next 2048 characters ====');
                                Log(buffer);
                            end;
                        end;
                    end
                    else
                    begin
                        Log('Could not get text from chunk: '+IntToHex(hr, 8)+' ('+GetChunkHResultToStr(hr)+')');
                        Log('   It might be a "Value" chunk, meaning i should call filter.GetValue rather than filter.GetText. But i''m too lazy');
                    end;
                end
                else if (chunk.flags and CHUNK_VALUE) = CHUNK_VALUE then
                begin
                    Log('This is a "VALUE" chunk. i''m not going to read anything out of it cause it''s too hard :(');
                end
                else
                    Log('Unknown chunk type');
            finally
            Dispose(chunk);
            end;
        end; //end while true getting chunks
    finally
        filter := nil;
    end;
end;

Где Windows уже предоставляет код, который загружает IFilter для указанного имени файла:

function TForm1.LoadIFilter(const filename: WideString): IFilter;
var
    hr: HRESULT;
    unk: IUnknown;
begin
    hr := ntQuery.LoadIFilter(PWideChar(filename), nil, unk);
    OleCheck(hr);

    Result := unk as IFilter;
end;

Блок объявлений IFilter:

unit Filter;

interface

uses
  Windows, SysUtils, Classes, ActiveX;

type
    IFILTER_INIT = TOleEnum;
const
    IFILTER_INIT_CANON_PARAGRAPHS             = 1;
    IFILTER_INIT_HARD_LINE_BREAKS             = 2;
    IFILTER_INIT_CANON_HYPHENS                = 4;
    IFILTER_INIT_CANON_SPACES                 = 8;
    IFILTER_INIT_APPLY_INDEX_ATTRIBUTES   = 16;
    IFILTER_INIT_APPLY_OTHER_ATTRIBUTES   = 32;
    IFILTER_INIT_INDEXING_ONLY                = 64;
    IFILTER_INIT_SEARCH_LINKS                 = 128;

type
    IFILTER_FLAGS = TOleEnum;
const
    IFILTER_FLAGS_OLE_PROPERTIES = 1;

type
    CHUNKSTATE = TOleEnum;
const
    CHUNK_TEXT =    $01;
    CHUNK_VALUE =   $02;

type
    CHUNK_BREAKTYPE = TOleEnum;
const
    CHUNK_NO_BREAK =    0;
    CHUNK_EOW =         1;
    CHUNK_EOS =         2;
    CHUNK_EOP =         3;
    CHUNK_EOC =         4;

type
    FILTERREGION = packed record
        idChunk: ULONG;
        cwcStart: ULONG;
        cwcExtent: ULONG;
    end;
    tagFILTERREGION = FILTERREGION;


const
    PRSPEC_LPWSTR =     0;
    PRSPEC_PROPID =     1;

type
    PROPID = ULONG;

type
    PROPSPEC = packed record
        ulKind: ULONG;
        case integer of
        0: (prid: PROPID);
        1: (lpws: PWideChar);
    end;
    tagPROPSPEC = PROPSPEC;

type
    FULLPROPSPEC = packed record
        guidPropSet: TGUID;
        psProperty: PROPSPEC;
    end;
    tagFULLPROPSPEC =   FULLPROPSPEC;
    PFULLPROPSPEC =         ^FULLPROPSPEC;

type
    STAT_CHUNK = packed record
        idChunk: ULONG;
        breakType: CHUNK_BREAKTYPE;
        flags: CHUNKSTATE;
        locale: LCID;
        attribute: FULLPROPSPEC;
        idChunkSource: ULONG;
        cwcStartSource: ULONG;
        cwcLenSource: ULONG;
    end;
    tagSTAT_CHUNK =     STAT_CHUNK;
    PSTAT_CHUNK =       ^STAT_CHUNK;

// From filtererr.h
const
    FILTER_E_END_OF_CHUNKS = HRESULT($80041700);

//
// MessageId: FILTER_E_NO_MORE_TEXT
//
// MessageText:
//
//  No more text available in chunk.
//
const
    FILTER_E_NO_MORE_TEXT = HRESULT($80041701);

//
// MessageId: FILTER_E_NO_MORE_VALUES
//
// MessageText:
//
//  No more property values available in chunk.
//
const
    FILTER_E_NO_MORE_VALUES = HRESULT($80041702);

//
// MessageId: FILTER_E_ACCESS
//
// MessageText:
//
//  Unable to access object.
//
const
    FILTER_E_ACCESS = HRESULT($80041703);

//
// MessageId: FILTER_W_MONIKER_CLIPPED
//
// MessageText:
//
//  Moniker doesn't cover entire region.
//
const
    FILTER_W_MONIKER_CLIPPED = HRESULT($80041704);

//
// MessageId: FILTER_E_NO_TEXT
//
// MessageText:
//
//  No text in current chunk.
//
const
    FILTER_E_NO_TEXT = HRESULT($80041705);

//
// MessageId: FILTER_E_NO_VALUES
//
// MessageText:
//
//  No values in current chunk.
//
const
    FILTER_E_NO_VALUES = HRESULT($80041706);

//
// MessageId: FILTER_E_EMBEDDING_UNAVAILABLE
//
// MessageText:
//
//  Unable to bind IFilter for embedded object.
//
const
    FILTER_E_EMBEDDING_UNAVAILABLE = HRESULT($80041707);

//
// MessageId: FILTER_E_LINK_UNAVAILABLE
//
// MessageText:
//
//  Unable to bind IFilter for linked object.
//
const
    FILTER_E_LINK_UNAVAILABLE             =  HRESULT($80041708);

//
// MessageId: FILTER_S_LAST_TEXT
//
// MessageText:
//
//  This is the last text in the current chunk.
//
const
    FILTER_S_LAST_TEXT = HRESULT($00041709);

//
// MessageId: FILTER_S_LAST_VALUES
//
// MessageText:
//
//  This is the last value in the current chunk.
//
const
    FILTER_S_LAST_VALUES = HRESULT($0004170A);

//
// MessageId: FILTER_E_PASSWORD
//
// MessageText:
//
//  File was not filtered due to password protection.
//
const
    FILTER_E_PASSWORD = HRESULT($8004170B);

//
// MessageId: FILTER_E_UNKNOWNFORMAT
//
// MessageText:
//
//  The document format is not recognized by the flter.
//
const
    FILTER_E_UNKNOWNFORMAT = HRESULT($8004170C);


const
    IID_IFilter: TGUID = '{89BCB740-6119-101A-BCB7-00DD010655AF}';

type
    IFilter = interface(IUnknown)
        ['{89BCB740-6119-101A-BCB7-00DD010655AF}']
        function Init(grfFlags: ULONG; cAttributes: ULONG; aAttributes: PFULLPROPSPEC; out pFlags: ULONG): HResult; stdcall;
        function GetChunk(pStat: PSTAT_CHUNK): HResult; stdcall;
        function GetText(var pcwcBuffer: ULONG; awcBuffer: PWideChar): HResult; stdcall;
        function GetValue(out ppPropValue: PROPVARIANT): HResult; stdcall;
        function BindRegion(origPos: FILTERREGION; riid: TGUID; out ppUnk): HResult; stdcall;
    end;

implementation

end.
person Ian Boyd    schedule 04.06.2011
comment
Где определены/объявлены IFilter и PSTAT_CHUNK? - person user1580348; 27.11.2016

Если вы ищете старые группы новостей Borland/CodeGear, вы можете найти ссылки на реализацию IFilter от "Soluciones Vulcano", которая имеет ссылку на develop.shorterpath.com, который все еще существует. Кроме того, я никогда не видел никакого другого компонента реализации, и мне пока не удалось посмотреть на него самому.

person mj2008    schedule 15.07.2010