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