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 { /// /// 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 /// 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 _cache=new Dictionary(); #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 /// /// finds an IFilter implementation for a file type /// /// The extension of the file /// an IFilter instance used to retreive text from that file type 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; } } }