Использование IFilter в C # и получение файла из базы данных, а не из файловой системы - PullRequest
5 голосов
/ 06 сентября 2011

Для веб-приложения на C # я хочу индексировать текст из файлов PDF, DOC и т. Д., Хранящихся в базе данных.

Я экспериментировал с примером IFilter для Code Project , который отлично работает для файлов из файловой системы, но мои файлы хранятся в базе данных MS-SQL.

Может ли кто-нибудь помочь мне найти образец для извлечения текста из файлов, хранящихся в базе данных, или иметь представление о том, как изменить код Code Project для работы с базой данных вместо файловой системы?

Ответы [ 4 ]

13 голосов
/ 22 октября 2013

Наконец-то через много часов я разобрался, как заставить это работать!Мне нужно было запустить IFilter для содержимого PDF, хранящегося в базе данных, и я хотел избежать сохранения данных во временных файлах.

Сначала я попытался использовать API BindIFilterFromStream для создания IFilter для содержимогохранится в потоке, но кажется, что он не работает должным образом (по крайней мере, для этого сценария).Так что не иди этим путем.

Вместо этого вам нужно создать IFilter для расширения файла (или получить к нему доступ другим способом).Затем вы можете получить доступ к COM-интерфейсу IPersistStream и использовать его для загрузки содержимого PDF в IFilter.Остальное работает так же, как и для файлов.Однако обратите внимание, что API-интерфейс IPersistStream может быть реализован не каждым IFilter.Однако он работает для Adobe PDF IFilter.

Код должен выглядеть следующим образом (я удалил некоторую проверку кода возврата, чтобы сделать код более читабельным, однако вы должны проверить все возможные коды возврата).

private string ParseIFilter(Stream s)
{
   // Get an IFilter for a file or file extension
   IFilter filter = null;
   FilterReturnCodes result = NativeMethods.LoadIFilter(".pdf", null, ref filter);
   if (result != FilterReturnCodes.S_OK)
   {
      Marshal.ThrowExceptionForHR((int)result);
   }

   // Copy the content to global memory
   byte[] buffer = new byte[s.Length];
   s.Read(buffer, 0, buffer.Length);
   IntPtr nativePtr = Marshal.AllocHGlobal(buffer.Length);
   Marshal.Copy(buffer, 0, nativePtr, buffer.Length);

   // Create a COM stream
   System.Runtime.InteropServices.ComTypes.IStream comStream;
   NativeMethods.CreateStreamOnHGlobal(nativePtr, true, out comStream);

   // Load the contents to the iFilter using IPersistStream interface
   var persistStream = (IPersistStream)filter;
   persistStream.Load(comStream);

   // Initialize iFilter
   FilterFlags filterFlags;
   FilterReturnCodes result = filter.Init(
      FilterInit.IFILTER_INIT_INDEXING_ONLY, 0, IntPtr.Zero, out filterFlags);

   return ExtractTextFromIFilter(filter);
}

Извлечение текста из фильтра выглядит так в моем коде.Есть много примеров этого в сети, и это может быть реализовано различными способами в зависимости от того, что вам нужно.

private string ExtractTextFromIFilter(IFilter filter)
{
   var sb = new StringBuilder();

   while (true)
   {
      StatChunk chunk;
      result = filter.GetChunk(out chunk);

      if (result == FilterReturnCodes.S_OK)
      {
         if (chunk.flags == ChunkState.CHUNK_TEXT)
         {
            sb.Append(ExtractTextFromChunk(filter, chunk));
         }

         continue;
      }

      if (result == FilterReturnCodes.FILTER_E_END_OF_CHUNKS)
      {
         return sb.ToString();
      }

      Marshal.ThrowExceptionForHR((int)result);
   }
}

private virtual string ExtractTextFromChunk(IFilter filter, StatChunk chunk)
{
   var sb = new StringBuilder();

   var result = FilterReturnCodes.S_OK;
   while (result == FilterReturnCodes.S_OK)
   {
      int sizeBuffer = 16384;
      var buffer = new StringBuilder(sizeBuffer);
      result = filter.GetText(ref sizeBuffer, buffer);

      if ((result == FilterReturnCodes.S_OK) || (result == FilterReturnCodes.FILTER_S_LAST_TEXT))
      {
         if((sizeBuffer > 0) && (buffer.Length > 0))
         {
            sb.Append(buffer.ToString(0, sizeBuffer));
         }
      }

      if (result == FilterReturnCodes.FILTER_E_NO_TEXT)
      {
         return string.Empty;
      }

      if ((result == FilterReturnCodes.FILTER_S_LAST_TEXT) || (result == FilterReturnCodes.FILTER_E_NO_MORE_TEXT))
      {
         return sb.ToString();
      }
   }

   return sb.ToString();
}

А вот определения нативных методов и используемых ими структур.

internal static class NativeMethods
{
    [DllImport("query.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern FilterReturnCodes LoadIFilter(
        string pwcsPath,
        [MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter,
        ref IFilter ppIUnk);

    [DllImport("ole32.dll")]
    public static extern int CreateStreamOnHGlobal(IntPtr hGlobal, bool fDeleteOnRelease, out IStream ppstm);
}

[ComImport, Guid("89BCB740-6119-101A-BCB7-00DD010655AF")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IFilter
{
    [PreserveSig]
    FilterReturnCodes Init(FilterInit grfFlags, int cAttributes, IntPtr aAttributes, out FilterFlags pdwFlags);

    [PreserveSig]
    FilterReturnCodes GetChunk(out StatChunk pStat);

    [PreserveSig]
    FilterReturnCodes GetText(
        ref int pcwcBuffer,
        [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder awcBuffer);

    [PreserveSig]
    FilterReturnCodes GetValue(ref IntPtr propVal);

    [PreserveSig]
    FilterReturnCodes BindRegion(ref FilterRegion origPos, ref Guid riid, ref object ppunk);
}

[InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("0000010c-0000-0000-C000-000000000046")]
public interface IPersist
{
    void GetClassID(out Guid pClassID);
}

[InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00000109-0000-0000-C000-000000000046")]
public interface IPersistStream : IPersist
{
    new void GetClassID(out Guid pClassID);

    [PreserveSig]
    int IsDirty();

    void Load([In] IStream pStm);

    void Save(
        [In] IStream pStm,
        [In, MarshalAs(UnmanagedType.Bool)] bool fClearDirty);

    void GetSizeMax(out long pcbSize);
}

public struct StatChunk
{
    public int idChunk;
    [MarshalAs(UnmanagedType.U4)]
    public ChunkBreaktype breakType;
    [MarshalAs(UnmanagedType.U4)]
    public ChunkState flags;
    public int locale;
    public FullPropSpec attribute;
    public int idChunkSource;
    public int cwcStartSource;
    public int cwcLenSource;
}

public enum ChunkBreaktype
{
    CHUNK_NO_BREAK = 0,
    CHUNK_EOW = 1,
    CHUNK_EOS = 2,
    CHUNK_EOP = 3,
    CHUNK_EOC = 4
}

public enum ChunkState
{
    CHUNK_TEXT = 0x1,
    CHUNK_VALUE = 0x2,
    CHUNK_FILTER_OWNED_VALUE = 0x4
}

[Flags]
public enum FilterFlags
{
    IFILTER_FLAGS_OLE_PROPERTIES = 1
}

[Flags]
public enum FilterInit
{
    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_CRAWL_ATTRIBUTES = 256,
    IFILTER_INIT_APPLY_OTHER_ATTRIBUTES = 32,
    IFILTER_INIT_INDEXING_ONLY = 64,
    IFILTER_INIT_SEARCH_LINKS = 128,
    IFILTER_INIT_FILTER_OWNED_VALUE_OK = 512
}

public struct FilterRegion
{
    public int idChunk;
    public int cwcStart;
    public int cwcExtent;
}

public enum FilterReturnCodes : uint
{
    S_OK = 0,
    E_ACCESSDENIED = 0x80070005,
    E_HANDLE = 0x80070006,
    E_INVALIDARG = 0x80070057,
    E_OUTOFMEMORY = 0x8007000E,
    E_NOTIMPL = 0x80004001,
    E_FAIL = 0x80000008,
    FILTER_E_PASSWORD = 0x8004170B,
    FILTER_E_UNKNOWNFORMAT = 0x8004170C,
    FILTER_E_NO_TEXT = 0x80041705,
    FILTER_E_NO_VALUES = 0x80041706,
    FILTER_E_END_OF_CHUNKS = 0x80041700,
    FILTER_E_NO_MORE_TEXT = 0x80041701,
    FILTER_E_NO_MORE_VALUES = 0x80041702,
    FILTER_E_ACCESS = 0x80041703,
    FILTER_W_MONIKER_CLIPPED = 0x00041704,
    FILTER_E_EMBEDDING_UNAVAILABLE = 0x80041707,
    FILTER_E_LINK_UNAVAILABLE = 0x80041708,
    FILTER_S_LAST_TEXT = 0x00041709,
    FILTER_S_LAST_VALUES = 0x0004170A
}

public struct FullPropSpec
{
    public Guid guidPropSet;
    public PropSpec psProperty;
}

[StructLayout(LayoutKind.Explicit)]
public struct PropSpec
{
    [FieldOffset(0)]
    public int ulKind;     

    [FieldOffset(4)]
    public int propid;

    [FieldOffset(4)]
    public IntPtr lpwstr;
}
1 голос
/ 07 мая 2012

Я надеялся сделать то же самое, но в итоге я добавил еще один столбец в таблицу базы данных для TextContent. Я сохранил BinaryContent во временный файл, использовал библиотеку CodeProject Epocalisde.IFilter dll, чтобы найти текст, и добавил его в столбец TextContent.

1 голос
/ 06 сентября 2011

В прошлом я работал над созданием iFilter, предназначенного для предоставления любому инструменту поиска / индексирования доступа к текстовому содержимому в файле AutoCad DWG.Вы можете прочитать некоторые из моих приключений здесь: http://blogs.msdn.com/b/ifilter/archive/2006/12/25/chronicles-of-an-ifilter-development-inception-to-deployment.aspx

Код, на который вы ссылаетесь, старый, но все еще действующий.Однако теперь помимо GetTextFromFile используется больше интерфейсов.Вам нужно будет использовать потоковый ридер, прочитанный в IPersistStream по ссылке, которую я упомянул выше.Если я понимаю, что вы хотите сделать, вам нужно открыть файл в виде потока из базы данных и представить этот поток поиску / индексатору или iFilter по вашему выбору.1006 *

0 голосов
/ 23 октября 2018

Основываясь на примере Mareks, вот мое мнение, в котором используется реализация интерфейса IStream вместо выделения памяти через Marshal.AllocHGlobal для создания потока COM.

Работает с Adobe PDF iFilter 64 11.0.01 и множество форматов, таких как .doc, .docx, .html, .odt, .rtf, список можно продолжить.

Полный пример:

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;

namespace TextExtraction
{
    class Program
    {
        static void Main(string[] args)
        {
            var file = new FileInfo(@"C:\Path\To\Some.doc");

            using (var stream = file.OpenRead())
            {
                var filter = Load(stream, file.Extension);
                if (filter != null)
                {
                    var text = GetText(filter);
                    Console.WriteLine(text);
                }
            }

            Console.WriteLine("Press your favorite key to exit");
            Console.ReadKey();
        }

        private static IFilter Load(Stream stream, string extension)
        {
            IFilter filter = null;

            if (NativeMethods.LoadIFilter(extension, null, ref filter) == HRESULT.S_OK)
            {
                if (filter is IPersistStream persistStream)
                {
                    persistStream.Load(new ManagedStream(stream));

                    if (filter.Init(IFILTER_INIT.IFILTER_INIT_APPLY_INDEX_ATTRIBUTES, 0, IntPtr.Zero, out IFILTER_FLAGS filterFlags) == IFilterReturnCodes.S_OK)
                    {
                        return filter;
                    }
                }
            }

            return null;
        }

        private static string GetText(IFilter filter)
        {
            var text = new StringBuilder();

            while (filter.GetChunk(out var chunk) == IFilterReturnCodes.S_OK)
            {
                ReadChunk(filter, chunk, text);
            }

            return text.ToString();
        }

        private static void ReadChunk(IFilter filter, STAT_CHUNK chunk, StringBuilder text)
        {
            var textResult = IFilterReturnCodes.S_OK;
            while (textResult == IFilterReturnCodes.S_OK)
            {
                var bufferSize = 4096U;
                var buffer = new char[bufferSize];
                textResult = filter.GetText(ref bufferSize, buffer);

                if ((textResult == IFilterReturnCodes.S_OK || textResult == IFilterReturnCodes.FILTER_S_LAST_TEXT) && bufferSize > 0)
                {
                    if (chunk.breakType == CHUNK_BREAKTYPE.CHUNK_EOP)
                    {
                        text.Append('\n');
                    }

                    text.Append(buffer, 0, (int) bufferSize);
                }
            }
        }

        [Guid("89BCB740-6119-101A-BCB7-00DD010655AF")]
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IFilter
        {
            [PreserveSig]
            IFilterReturnCodes Init(IFILTER_INIT grfFlags, int cAttributes, IntPtr aAttributes,
                out IFILTER_FLAGS pdwFlags);

            [PreserveSig]
            IFilterReturnCodes GetChunk(out STAT_CHUNK pStat);

            [PreserveSig]
            IFilterReturnCodes GetText(ref uint pcwcBuffer, [Out, MarshalAs(UnmanagedType.LPArray)]
                char[] awcBuffer);

            [PreserveSig]
            IFilterReturnCodes GetValue(ref IntPtr propVal);

            [PreserveSig]
            IFilterReturnCodes BindRegion(ref FILTERREGION origPos, ref Guid riid, ref object ppunk);
        }

        [Guid("0000010C-0000-0000-C000-000000000046")]
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IPersist
        {
            void GetClassID(out Guid pClassID);
        }

        [Guid("00000109-0000-0000-C000-000000000046")]
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IPersistStream : IPersist
        {
            new void GetClassID(out Guid pClassID);

            [PreserveSig]
            int IsDirty();

            void Load([In] IStream pStm);

            void Save([In] IStream pStm, [In, MarshalAs(UnmanagedType.Bool)] bool fClearDirty);

            void GetSizeMax(out long pcbSize);
        }

        [Guid("0000000C-0000-0000-C000-000000000046")]
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IStream
        {
            [PreserveSig]
            HRESULT Read([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] [Out]
                byte[] pv, int cb, IntPtr pcbRead);

            [PreserveSig]
            HRESULT Write([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]
                byte[] pv, int cb, IntPtr pcbWritten);

            [PreserveSig]
            HRESULT Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition);

            [PreserveSig]
            HRESULT SetSize(long libNewSize);

            HRESULT CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten);

            [PreserveSig]
            HRESULT Commit(int grfCommitFlags);

            [PreserveSig]
            HRESULT Revert();

            [PreserveSig]
            HRESULT LockRegion(long libOffset, long cb, int dwLockType);

            [PreserveSig]
            HRESULT UnlockRegion(long libOffset, long cb, int dwLockType);

            [PreserveSig]
            HRESULT Stat(out STATSTG pstatstg, int grfStatFlag);

            [PreserveSig]
            HRESULT Clone(out IStream ppstm);
        }

        public class ManagedStream : IStream
        {
            private readonly Stream _stream;

            public ManagedStream(Stream stream)
            {
                _stream = stream ?? throw new ArgumentNullException(nameof(stream));
            }

            public HRESULT Clone(out IStream ppstm)
            {
                ppstm = null;
                return HRESULT.E_NOTIMPL;
            }

            public HRESULT Commit(int grfCommitFlags)
            {
                return HRESULT.E_NOTIMPL;
            }

            public HRESULT CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten)
            {
                return HRESULT.E_NOTIMPL;
            }

            public HRESULT LockRegion(long libOffset, long cb, int dwLockType)
            {
                return HRESULT.E_NOTIMPL;
            }

            public HRESULT Read(byte[] pv, int cb, IntPtr pcbRead)
            {
                var bytesRead = _stream.Read(pv, 0, cb);
                if (pcbRead != IntPtr.Zero)
                {
                    Marshal.WriteInt32(pcbRead, bytesRead);
                }

                return HRESULT.S_OK;
            }

            public HRESULT Revert()
            {
                return HRESULT.E_NOTIMPL;
            }

            public HRESULT Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition)
            {
                SeekOrigin seekOrigin;

                switch (dwOrigin)
                {
                    case (int) STREAM_SEEK.STREAM_SEEK_SET:
                        seekOrigin = SeekOrigin.Begin;
                        break;
                    case (int) STREAM_SEEK.STREAM_SEEK_CUR:
                        seekOrigin = SeekOrigin.Current;
                        break;
                    case (int) STREAM_SEEK.STREAM_SEEK_END:
                        seekOrigin = SeekOrigin.End;
                        break;
                    default:
                        return HRESULT.E_FAIL;
                }

                var position = _stream.Seek(dlibMove, seekOrigin);

                if (plibNewPosition != IntPtr.Zero)
                {
                    Marshal.WriteInt64(plibNewPosition, position);
                }

                return HRESULT.S_OK;
            }

            public HRESULT SetSize(long libNewSize)
            {
                return HRESULT.E_NOTIMPL;
            }

            public HRESULT Stat(out STATSTG pstatstg, int grfStatFlag)
            {
                pstatstg = new STATSTG
                {
                    type = (int) STGTY.STGTY_STREAM,
                    cbSize = _stream.Length,
                    grfMode = (int) STGM.STGM_READ
                };

                if (_stream.CanRead && _stream.CanWrite)
                {
                    pstatstg.grfMode |= (int) STGM.STGM_READWRITE;
                }
                else if (_stream.CanRead)
                {
                    pstatstg.grfMode |= (int) STGM.STGM_READ;
                }
                else if (_stream.CanWrite)
                {
                    pstatstg.grfMode |= (int) STGM.STGM_WRITE;
                }
                else
                {
                    return HRESULT.E_ACCESSDENIED;
                }

                return HRESULT.S_OK;
            }

            public HRESULT UnlockRegion(long libOffset, long cb, int dwLockType)
            {
                return HRESULT.E_NOTIMPL;
            }

            public HRESULT Write(byte[] pv, int cb, IntPtr pcbWritten)
            {
                return HRESULT.E_NOTIMPL;
            }
        }

        public class NativeMethods
        {
            [DllImport("query.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern HRESULT LoadIFilter(string pwcsPath, [MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter, ref IFilter ppIUnk);
        }

        public struct FILETIME
        {
            public uint DateTimeLow;
            public uint DateTimeHigh;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct FILTERREGION
        {
            public ulong idChunk;
            public ulong cwcStart;
            public ulong cwcExtent;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct FULLPROPSPEC
        {
            public Guid guidPropSet;
            public PROPSPEC psProperty;
        }

        [StructLayout(LayoutKind.Explicit)]
        public struct PROPSPEC
        {
            [FieldOffset(0)]
            public PROPSPECKIND ulKind;

            [FieldOffset(4)]
            public uint propid;

            [FieldOffset(4)]
            public IntPtr lpwstr;
        }

        public struct STAT_CHUNK
        {
            public int idChunk;

            [MarshalAs(UnmanagedType.U4)]
            public CHUNK_BREAKTYPE breakType;

            [MarshalAs(UnmanagedType.U4)]
            public CHUNKSTATE flags;

            public int locale;

            public FULLPROPSPEC attribute;

            public int idChunkSource;

            public int cwcStartSource;

            public int cwcLenSource;
        }

        public struct STATSTG
        {
            [MarshalAs(UnmanagedType.LPTStr)]
            public string pwcsName;
            public int type;
            public long cbSize;
            public FILETIME mtime;
            public FILETIME ctime;
            public FILETIME atime;
            public int grfMode;
            public int grfLocksSupported;
            public Guid clsid;
            public int grfStateBits;
            public int reserved;
        }

        [Flags]
        public enum IFilterReturnCodes : uint
        {
            S_OK = 0,
            E_ACCESSDENIED = 0x80070005,
            E_HANDLE = 0x80070006,
            E_INVALIDARG = 0x80070057,
            E_OUTOFMEMORY = 0x8007000E,
            E_NOTIMPL = 0x80004001,
            E_FAIL = 0x80000008,

            FILTER_E_PASSWORD = 0x8004170B,
            FILTER_E_UNKNOWNFORMAT = 0x8004170C,
            FILTER_E_NO_TEXT = 0x80041705,
            FILTER_E_NO_VALUES = 0x80041706,
            FILTER_E_END_OF_CHUNKS = 0x80041700,
            FILTER_E_NO_MORE_TEXT = 0x80041701,
            FILTER_E_NO_MORE_VALUES = 0x80041702,
            FILTER_E_ACCESS = 0x80041703,
            FILTER_W_MONIKER_CLIPPED = 0x00041704,
            FILTER_E_EMBEDDING_UNAVAILABLE = 0x80041707,
            FILTER_E_LINK_UNAVAILABLE = 0x80041708,
            FILTER_S_LAST_TEXT = 0x00041709,
            FILTER_S_LAST_VALUES = 0x0004170A
        }

        [Flags]
        public enum CHUNK_BREAKTYPE : uint
        {
            CHUNK_NO_BREAK = 0,
            CHUNK_EOW = 1,
            CHUNK_EOS = 2,
            CHUNK_EOP = 3,
            CHUNK_EOC = 4
        }

        [Flags]
        public enum CHUNKSTATE : uint
        {
            CHUNK_TEXT = 0x1,
            CHUNK_VALUE = 0x2,
            CHUNK_FILTER_OWNED_VALUE = 0x4
        }

        [Flags]
        public enum HRESULT : uint
        {
            S_OK = 0x00000000,
            E_NOTIMPL = 0x80004001,
            E_NOINTERFACE = 0x80004002,
            E_POINTER = 0x80004003,
            E_ABORT = 0x80004004,
            E_FAIL = 0x80004005,
            E_UNEXPECTED = 0x8000FFFF,
            E_ACCESSDENIED = 0x80070005,
            E_HANDLE = 0x80070006,
            E_OUTOFMEMORY = 0x8007000E,
            E_INVALIDARG = 0x80070057
        }

        [Flags]
        public enum IFILTER_FLAGS
        {
            IFILTER_FLAGS_OLE_PROPERTIES = 1
        }

        [Flags]
        public enum IFILTER_INIT
        {
            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_CRAWL_ATTRIBUTES = 256,
            IFILTER_INIT_APPLY_OTHER_ATTRIBUTES = 32,
            IFILTER_INIT_INDEXING_ONLY = 64,
            IFILTER_INIT_SEARCH_LINKS = 128,
            IFILTER_INIT_FILTER_OWNED_VALUE_OK = 512,
            IFILTER_INIT_FILTER_AGGRESSIVE_BREAK = 1024,
            IFILTER_INIT_DISABLED_EMBEDDED = 2048,
            IFILTER_INIT_EMIT_FORMATTING = 4096
        }

        [Flags]
        public enum PROPSPECKIND : ulong
        {
            PRSPEC_LPWSTR = 0,
            PRSPEC_PROPID = 1
        }

        [Flags]
        public enum STGM : ulong
        {
            STGM_READ = 0x00000000L,
            STGM_WRITE = 0x00000001L,
            STGM_READWRITE = 0x00000002L,
            STGM_SHARE_DENY_NONE = 0x00000040L,
            STGM_SHARE_DENY_READ = 0x00000030L,
            STGM_SHARE_DENY_WRITE = 0x00000020L,
            STGM_SHARE_EXCLUSIVE = 0x00000010L,
            STGM_PRIORITY = 0x00040000L,
            STGM_CREATE = 0x00001000L,
            STGM_CONVERT = 0x00020000L,
            STGM_FAILIFTHERE = 0x00000000L,
            STGM_DIRECT = 0x00000000L,
            STGM_TRANSACTED = 0x00010000L,
            STGM_NOSCRATCH = 0x00100000L,
            STGM_NOSNAPSHOT = 0x00200000L,
            STGM_SIMPLE = 0x08000000L,
            STGM_DIRECT_SWMR = 0x00400000L,
            STGM_DELETEONRELEASE = 0x04000000L
        }

        [Flags]
        public enum STGTY : int
        {
            STGTY_STORAGE = 1,
            STGTY_STREAM = 2,
            STGTY_LOCKBYTES = 3,
            STGTY_PROPERTY = 4
        }

        [Flags]
        public enum STREAM_SEEK : int
        {
            STREAM_SEEK_SET = 0,
            STREAM_SEEK_CUR = 1,
            STREAM_SEEK_END = 2
        }
    }
}
...