227 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			227 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using System;
 | 
						|
using System.Collections.Generic;
 | 
						|
using System.Text;
 | 
						|
using Microsoft.Win32;
 | 
						|
using System.IO;
 | 
						|
using System.Runtime.InteropServices.ComTypes;
 | 
						|
using System.Runtime.InteropServices;
 | 
						|
 | 
						|
namespace EPocalipse.IFilter
 | 
						|
{
 | 
						|
  /// <summary>
 | 
						|
  /// FilterLoader finds the dll and ClassID of the COM object responsible  
 | 
						|
  /// for filtering a specific file extension. 
 | 
						|
  /// It then loads that dll, creates the appropriate COM object and returns 
 | 
						|
  /// a pointer to an IFilter instance
 | 
						|
  /// </summary>
 | 
						|
  static class FilterLoader
 | 
						|
  {
 | 
						|
    #region CacheEntry
 | 
						|
    private class CacheEntry
 | 
						|
    {
 | 
						|
      public string DllName;
 | 
						|
      public string ClassName;
 | 
						|
 | 
						|
      public CacheEntry(string dllName, string className)
 | 
						|
      {
 | 
						|
        DllName=dllName;
 | 
						|
        ClassName=className;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    #endregion
 | 
						|
 | 
						|
    static Dictionary<string, CacheEntry> _cache=new Dictionary<string, CacheEntry>();
 | 
						|
 | 
						|
    #region Registry Read String helper
 | 
						|
    static string ReadStrFromHKLM(string key)
 | 
						|
    {
 | 
						|
      return ReadStrFromHKLM(key,null);
 | 
						|
    }
 | 
						|
    static string ReadStrFromHKLM(string key, string value)
 | 
						|
    {
 | 
						|
      RegistryKey rk=Registry.LocalMachine.OpenSubKey(key);
 | 
						|
      if (rk==null)
 | 
						|
        return null;
 | 
						|
 | 
						|
      using (rk)
 | 
						|
      {
 | 
						|
        return (string)rk.GetValue(value);
 | 
						|
      }
 | 
						|
    }
 | 
						|
    #endregion
 | 
						|
 | 
						|
    /// <summary>
 | 
						|
    /// finds an IFilter implementation for a file type
 | 
						|
    /// </summary>
 | 
						|
    /// <param name="ext">The extension of the file</param>
 | 
						|
    /// <returns>an IFilter instance used to retreive text from that file type</returns>
 | 
						|
    private static IFilter LoadIFilter(string ext)
 | 
						|
    {
 | 
						|
      string dllName, filterPersistClass;
 | 
						|
 | 
						|
      //Find the dll and ClassID
 | 
						|
      if (GetFilterDllAndClass(ext, out dllName, out filterPersistClass))
 | 
						|
      {
 | 
						|
        //load the dll and return an IFilter instance.
 | 
						|
        return LoadFilterFromDll(dllName, filterPersistClass);
 | 
						|
      }
 | 
						|
      return null;
 | 
						|
    }
 | 
						|
 | 
						|
    internal static IFilter LoadAndInitIFilter(string fileName)
 | 
						|
    {
 | 
						|
      return LoadAndInitIFilter(fileName,Path.GetExtension(fileName));
 | 
						|
    }
 | 
						|
 | 
						|
    internal static IFilter LoadAndInitIFilter(string fileName, string extension)
 | 
						|
    {
 | 
						|
      IFilter filter=LoadIFilter(extension);
 | 
						|
      if (filter==null)
 | 
						|
        return null;
 | 
						|
      IPersistFile persistFile=(filter as IPersistFile);
 | 
						|
      if (persistFile!=null)
 | 
						|
      {
 | 
						|
        persistFile.Load(fileName, 0);
 | 
						|
        IFILTER_FLAGS flags;
 | 
						|
        IFILTER_INIT iflags =
 | 
						|
					IFILTER_INIT.CANON_HYPHENS |
 | 
						|
					IFILTER_INIT.CANON_PARAGRAPHS |
 | 
						|
					IFILTER_INIT.CANON_SPACES |
 | 
						|
					IFILTER_INIT.APPLY_INDEX_ATTRIBUTES |
 | 
						|
					IFILTER_INIT.HARD_LINE_BREAKS |
 | 
						|
					IFILTER_INIT.FILTER_OWNED_VALUE_OK;
 | 
						|
 | 
						|
        if (filter.Init(iflags, 0, IntPtr.Zero, out flags)==IFilterReturnCode.S_OK)
 | 
						|
          return filter;
 | 
						|
      }
 | 
						|
      //If we failed to retreive an IPersistFile interface or to initialize 
 | 
						|
      //the filter, we release it and return null.
 | 
						|
      Marshal.ReleaseComObject(filter);
 | 
						|
      return null;
 | 
						|
    }
 | 
						|
 | 
						|
    private static IFilter LoadFilterFromDll(string dllName, string filterPersistClass)
 | 
						|
    {
 | 
						|
      //Get a classFactory for our classID
 | 
						|
      IClassFactory classFactory=ComHelper.GetClassFactory(dllName, filterPersistClass);
 | 
						|
      if (classFactory==null)
 | 
						|
        return null;
 | 
						|
 | 
						|
      //And create an IFilter instance using that class factory
 | 
						|
      Guid IFilterGUID=new Guid("89BCB740-6119-101A-BCB7-00DD010655AF");
 | 
						|
      Object obj;
 | 
						|
      classFactory.CreateInstance(null, ref IFilterGUID, out obj);
 | 
						|
      return (obj as IFilter);
 | 
						|
    }
 | 
						|
 | 
						|
    private static bool GetFilterDllAndClass(string ext, out string dllName, out string filterPersistClass)
 | 
						|
    {
 | 
						|
      if (!GetFilterDllAndClassFromCache(ext, out dllName, out filterPersistClass))
 | 
						|
      {
 | 
						|
        string persistentHandlerClass;
 | 
						|
 | 
						|
        persistentHandlerClass=GetPersistentHandlerClass(ext,true);
 | 
						|
        if (persistentHandlerClass!=null)
 | 
						|
        {
 | 
						|
          GetFilterDllAndClassFromPersistentHandler(persistentHandlerClass,
 | 
						|
            out dllName, out filterPersistClass);
 | 
						|
        }
 | 
						|
        AddExtensionToCache(ext, dllName, filterPersistClass);
 | 
						|
      }
 | 
						|
      return (dllName!=null && filterPersistClass!=null); 
 | 
						|
    }
 | 
						|
 | 
						|
    private static void AddExtensionToCache(string ext, string dllName, string filterPersistClass)
 | 
						|
    {
 | 
						|
      lock (_cache)
 | 
						|
      {
 | 
						|
        _cache.Add(ext.ToLower(), new CacheEntry(dllName, filterPersistClass));
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    private static bool GetFilterDllAndClassFromPersistentHandler(string persistentHandlerClass, out string dllName, out string filterPersistClass)
 | 
						|
    {
 | 
						|
      dllName=null;
 | 
						|
      filterPersistClass=null;
 | 
						|
 | 
						|
      //Read the CLASS ID of the IFilter persistent handler
 | 
						|
      filterPersistClass=ReadStrFromHKLM(@"Software\Classes\CLSID\" + persistentHandlerClass + 
 | 
						|
        @"\PersistentAddinsRegistered\{89BCB740-6119-101A-BCB7-00DD010655AF}");
 | 
						|
      if (String.IsNullOrEmpty(filterPersistClass))
 | 
						|
          return false;
 | 
						|
 | 
						|
      //Read the dll name 
 | 
						|
      dllName=ReadStrFromHKLM(@"Software\Classes\CLSID\" + filterPersistClass + 
 | 
						|
        @"\InprocServer32");
 | 
						|
      return (!String.IsNullOrEmpty(dllName));
 | 
						|
    }
 | 
						|
 | 
						|
    private static string GetPersistentHandlerClass(string ext, bool searchContentType)
 | 
						|
    {
 | 
						|
      //Try getting the info from the file extension
 | 
						|
      string persistentHandlerClass=GetPersistentHandlerClassFromExtension(ext);
 | 
						|
      if (String.IsNullOrEmpty(persistentHandlerClass))
 | 
						|
        //try getting the info from the document type 
 | 
						|
        persistentHandlerClass=GetPersistentHandlerClassFromDocumentType(ext);
 | 
						|
      if (searchContentType && String.IsNullOrEmpty(persistentHandlerClass))
 | 
						|
        //Try getting the info from the Content Type
 | 
						|
        persistentHandlerClass=GetPersistentHandlerClassFromContentType(ext);
 | 
						|
      return persistentHandlerClass;
 | 
						|
    }
 | 
						|
 | 
						|
    private static string GetPersistentHandlerClassFromContentType(string ext)
 | 
						|
    {
 | 
						|
      string contentType=ReadStrFromHKLM(@"Software\Classes\"+ext,"Content Type");
 | 
						|
      if (String.IsNullOrEmpty(contentType))
 | 
						|
        return null;
 | 
						|
      
 | 
						|
      string contentTypeExtension=ReadStrFromHKLM(@"Software\Classes\MIME\Database\Content Type\"+contentType,
 | 
						|
          "Extension");
 | 
						|
      if (ext.Equals(contentTypeExtension, StringComparison.CurrentCultureIgnoreCase))
 | 
						|
        return null; //No need to look further. This extension does not have any persistent handler
 | 
						|
    
 | 
						|
      //We know the extension that is assciated with that content type. Simply try again with the new extension
 | 
						|
      return GetPersistentHandlerClass(contentTypeExtension, false); //Don't search content type this time.
 | 
						|
    }
 | 
						|
 | 
						|
    private static string GetPersistentHandlerClassFromDocumentType(string ext)
 | 
						|
    {
 | 
						|
      //Get the DocumentType of this file extension
 | 
						|
      string docType=ReadStrFromHKLM(@"Software\Classes\"+ext);
 | 
						|
      if (String.IsNullOrEmpty(docType))
 | 
						|
        return null;
 | 
						|
      
 | 
						|
      //Get the Class ID for this document type
 | 
						|
      string docClass=ReadStrFromHKLM(@"Software\Classes\" + docType + @"\CLSID");
 | 
						|
      if (String.IsNullOrEmpty(docType))
 | 
						|
        return null;
 | 
						|
 | 
						|
      //Now get the PersistentHandler for that Class ID
 | 
						|
      return ReadStrFromHKLM(@"Software\Classes\CLSID\" + docClass + @"\PersistentHandler");
 | 
						|
    }
 | 
						|
 | 
						|
    private static string GetPersistentHandlerClassFromExtension(string ext)
 | 
						|
    {
 | 
						|
      return ReadStrFromHKLM(@"Software\Classes\"+ext+@"\PersistentHandler");
 | 
						|
    }
 | 
						|
 | 
						|
    private static bool GetFilterDllAndClassFromCache(string ext, out string dllName, out string filterPersistClass)
 | 
						|
    {
 | 
						|
      string lowerExt=ext.ToLower();
 | 
						|
      lock (_cache)
 | 
						|
      {
 | 
						|
        CacheEntry cacheEntry;
 | 
						|
        if (_cache.TryGetValue(lowerExt, out cacheEntry))
 | 
						|
        {
 | 
						|
          dllName=cacheEntry.DllName;
 | 
						|
          filterPersistClass=cacheEntry.ClassName;
 | 
						|
          return true;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      dllName=null;
 | 
						|
      filterPersistClass=null;
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 |