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;
 | |
|     }
 | |
|   }
 | |
| }
 |