add preview handler
This commit is contained in:
		@@ -0,0 +1,42 @@
 | 
			
		||||
#if PREVIEW_HANDLER
 | 
			
		||||
using System.IO;
 | 
			
		||||
 | 
			
		||||
namespace ShellExtensions
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// This interface exposes the <see cref="Load"/> function for initializing the 
 | 
			
		||||
    /// Preview Handler with a <typeparamref name="Stream"/>.
 | 
			
		||||
    /// This interface can be used in conjunction with the other intialization interfaces,
 | 
			
		||||
    /// but only 1 will be accessed according to the priorities preset by the Windows Shell:
 | 
			
		||||
    /// <typeparamref name="IPreviewFromStream"/>
 | 
			
		||||
    /// <typeparamref name="IPreviewFromShellObject"/>
 | 
			
		||||
    /// <typeparamref name="IPreviewFromFile"/>
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public interface IPreviewFromStream
 | 
			
		||||
    {
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Provides the <typeparamref name="Stream"/> to the item from which a preview should be created.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="stream">Stream to the previewed file, this stream is only available in the scope of this method.</param>
 | 
			
		||||
        void Load(Stream stream);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// This interface exposes the <see cref="Load"/> function for initializing the 
 | 
			
		||||
    /// Preview Handler with a <typeparamref name="FileInfo"/>.
 | 
			
		||||
    /// This interface can be used in conjunction with the other intialization interfaces,
 | 
			
		||||
    /// but only 1 will be accessed according to the priorities preset by the Windows Shell:
 | 
			
		||||
    /// <typeparamref name="IPreviewFromStream"/>
 | 
			
		||||
    /// <typeparamref name="IPreviewFromShellObject"/>
 | 
			
		||||
    /// <typeparamref name="IPreviewFromFile"/>
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public interface IPreviewFromFile
 | 
			
		||||
    {
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Provides the <typeparamref name="FileInfo"/> to the item from which a preview should be created.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="info">File information to the previewed file.</param>
 | 
			
		||||
        void Load(FileInfo info);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										377
									
								
								ShellExtensions/PreviewHandlers/PreviewHandler.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										377
									
								
								ShellExtensions/PreviewHandlers/PreviewHandler.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,377 @@
 | 
			
		||||
#if PREVIEW_HANDLER
 | 
			
		||||
using Microsoft.Win32;
 | 
			
		||||
using ShellExtensions.Interop;
 | 
			
		||||
using ShellExtensions.Interop.Common;
 | 
			
		||||
using ShellExtensions.Resources;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Runtime.InteropServices;
 | 
			
		||||
 | 
			
		||||
namespace ShellExtensions
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// This is the base class for all preview handlers and provides their basic functionality.
 | 
			
		||||
    /// To create a custom preview handler a class must derive from this, use the <typeparamref name="PreviewHandlerAttribute"/>,
 | 
			
		||||
    /// and implement 1 or more of the following interfaces: 
 | 
			
		||||
    /// <typeparamref name="IPreviewFromStream"/>, 
 | 
			
		||||
    /// <typeparamref name="IPreviewFromShellObject"/>, 
 | 
			
		||||
    /// <typeparamref name="IPreviewFromFile"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public abstract class PreviewHandler : ICustomQueryInterface, IPreviewHandler, IPreviewHandlerVisuals, IOleWindow, IObjectWithSite, IInitializeWithStream, IInitializeWithFile
 | 
			
		||||
    {
 | 
			
		||||
        private bool _isPreviewShowing;
 | 
			
		||||
        private IntPtr _parentHwnd;
 | 
			
		||||
        private IPreviewHandlerFrame _frame;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets whether the preview is currently showing
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public bool IsPreviewShowing => _isPreviewShowing;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Called immediately before the preview is to be shown.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        protected virtual void Initialize() { }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Called when the preview is no longer shown.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        protected virtual void Uninitialize() { }
 | 
			
		||||
 | 
			
		||||
#region Required functions - Abstract functions
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// This should return the window handle to be displayed in the Preview.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        protected abstract IntPtr Handle { get; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Called to update the bounds and position of the preview control
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="bounds"></param>
 | 
			
		||||
        protected abstract void UpdateBounds(NativeRect bounds);
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Called when an exception occurs during the initialization of the control
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="caughtException"></param>
 | 
			
		||||
        protected abstract void HandleInitializeException(Exception caughtException);
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Called when the preview control obtains focus.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        protected abstract void SetFocus();
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Called when a request is received to set or change the background color according to the user's preferences.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="color">An int representing the ARGB color</param>
 | 
			
		||||
        protected abstract void SetBackground(int argb);
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Called when a request is received to set or change the foreground color according to the user's preferences.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="color">An int representing the ARGB color</param>
 | 
			
		||||
        protected abstract void SetForeground(int argb);
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Called to set the font of the preview control according to the user's preferences.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="font"></param>
 | 
			
		||||
        protected abstract void SetFont(LogFont font);
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Called to set the parent of the preview control.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="handle"></param>
 | 
			
		||||
        protected abstract void SetParentHandle(IntPtr handle);
 | 
			
		||||
 | 
			
		||||
#endregion
 | 
			
		||||
 | 
			
		||||
#region IPreviewHandler Members
 | 
			
		||||
 | 
			
		||||
        void IPreviewHandler.SetWindow(IntPtr hwnd, ref NativeRect rect)
 | 
			
		||||
        {
 | 
			
		||||
            _parentHwnd = hwnd;
 | 
			
		||||
            UpdateBounds(rect);
 | 
			
		||||
            SetParentHandle(_parentHwnd);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void IPreviewHandler.SetRect(ref NativeRect rect)
 | 
			
		||||
        {
 | 
			
		||||
            UpdateBounds(rect);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void IPreviewHandler.DoPreview()
 | 
			
		||||
        {
 | 
			
		||||
            _isPreviewShowing = true;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                Initialize();
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception exc)
 | 
			
		||||
            {
 | 
			
		||||
                HandleInitializeException(exc);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void IPreviewHandler.Unload()
 | 
			
		||||
        {
 | 
			
		||||
            Uninitialize();
 | 
			
		||||
            _isPreviewShowing = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void IPreviewHandler.SetFocus()
 | 
			
		||||
        {
 | 
			
		||||
            SetFocus();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void IPreviewHandler.QueryFocus(out IntPtr phwnd)
 | 
			
		||||
        {
 | 
			
		||||
            phwnd = HandlerNativeMethods.GetFocus();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        HResult IPreviewHandler.TranslateAccelerator(ref Message pmsg)
 | 
			
		||||
        {
 | 
			
		||||
            return _frame != null ? _frame.TranslateAccelerator(ref pmsg) : HResult.False;
 | 
			
		||||
        }
 | 
			
		||||
#endregion
 | 
			
		||||
 | 
			
		||||
#region IPreviewHandlerVisuals Members
 | 
			
		||||
 | 
			
		||||
        void IPreviewHandlerVisuals.SetBackgroundColor(NativeColorRef color)
 | 
			
		||||
        {
 | 
			
		||||
            SetBackground((int)color.Dword);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void IPreviewHandlerVisuals.SetTextColor(NativeColorRef color)
 | 
			
		||||
        {
 | 
			
		||||
            SetForeground((int)color.Dword);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void IPreviewHandlerVisuals.SetFont(ref LogFont plf)
 | 
			
		||||
        {
 | 
			
		||||
            SetFont(plf);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
#endregion
 | 
			
		||||
 | 
			
		||||
#region IOleWindow Members
 | 
			
		||||
 | 
			
		||||
        void IOleWindow.GetWindow(out IntPtr phwnd)
 | 
			
		||||
        {
 | 
			
		||||
            phwnd = Handle;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void IOleWindow.ContextSensitiveHelp(bool fEnterMode)
 | 
			
		||||
        {
 | 
			
		||||
            // Preview handlers don't support context sensitive help. (As far as I know.)
 | 
			
		||||
            throw new NotImplementedException();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
#endregion
 | 
			
		||||
 | 
			
		||||
#region IObjectWithSite Members
 | 
			
		||||
 | 
			
		||||
        void IObjectWithSite.SetSite(object pUnkSite)
 | 
			
		||||
        {
 | 
			
		||||
            _frame = pUnkSite as IPreviewHandlerFrame;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void IObjectWithSite.GetSite(ref Guid riid, out object ppvSite)
 | 
			
		||||
        {
 | 
			
		||||
            ppvSite = _frame;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
#endregion
 | 
			
		||||
 | 
			
		||||
#region IInitializeWithStream Members
 | 
			
		||||
 | 
			
		||||
        void IInitializeWithStream.Initialize(System.Runtime.InteropServices.ComTypes.IStream stream, AccessModes fileMode)
 | 
			
		||||
        {
 | 
			
		||||
            IPreviewFromStream preview = this as IPreviewFromStream;
 | 
			
		||||
            if (preview == null)
 | 
			
		||||
            {
 | 
			
		||||
                throw new InvalidOperationException(
 | 
			
		||||
                    string.Format(System.Globalization.CultureInfo.InvariantCulture,
 | 
			
		||||
                        LocalizedMessages.PreviewHandlerUnsupportedInterfaceCalled,
 | 
			
		||||
                        nameof(IPreviewFromStream)));
 | 
			
		||||
            }
 | 
			
		||||
            using (var storageStream = new StorageStream(stream, fileMode != AccessModes.ReadWrite))
 | 
			
		||||
            {
 | 
			
		||||
                preview.Load(storageStream);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
#endregion
 | 
			
		||||
 | 
			
		||||
#region IInitializeWithFile Members
 | 
			
		||||
 | 
			
		||||
        void IInitializeWithFile.Initialize(string filePath, AccessModes fileMode)
 | 
			
		||||
        {
 | 
			
		||||
            IPreviewFromFile preview = this as IPreviewFromFile;
 | 
			
		||||
            if (preview == null)
 | 
			
		||||
            {
 | 
			
		||||
                throw new InvalidOperationException(
 | 
			
		||||
                    string.Format(System.Globalization.CultureInfo.InvariantCulture,
 | 
			
		||||
                        LocalizedMessages.PreviewHandlerUnsupportedInterfaceCalled,
 | 
			
		||||
                        nameof(IPreviewFromFile)));
 | 
			
		||||
            }
 | 
			
		||||
            preview.Load(new FileInfo(filePath));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
#endregion
 | 
			
		||||
 | 
			
		||||
#region ComRegistration
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Called when the assembly is registered via RegAsm.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="registerType">Type to register.</param>
 | 
			
		||||
        [ComRegisterFunction]
 | 
			
		||||
        private static void Register(Type registerType)
 | 
			
		||||
        {
 | 
			
		||||
            if (registerType != null && registerType.IsSubclassOf(typeof(PreviewHandler)))
 | 
			
		||||
            {
 | 
			
		||||
                object[] attrs = registerType.GetCustomAttributes(typeof(PreviewHandlerAttribute), true);
 | 
			
		||||
                if (attrs != null && attrs.Length == 1)
 | 
			
		||||
                {
 | 
			
		||||
                    PreviewHandlerAttribute attr = attrs[0] as PreviewHandlerAttribute;
 | 
			
		||||
                    ThrowIfNotValid(registerType);
 | 
			
		||||
                    RegisterPreviewHandler(registerType.GUID, attr);
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    throw new NotSupportedException(
 | 
			
		||||
                        string.Format(System.Globalization.CultureInfo.InvariantCulture,
 | 
			
		||||
                            LocalizedMessages.PreviewHandlerInvalidAttributes, registerType.Name));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Called when the assembly is Unregistered via RegAsm.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="registerType">Type to unregister</param>
 | 
			
		||||
        [ComUnregisterFunction]
 | 
			
		||||
        private static void Unregister(Type registerType)
 | 
			
		||||
        {
 | 
			
		||||
            if (registerType != null && registerType.IsSubclassOf(typeof(PreviewHandler)))
 | 
			
		||||
            {
 | 
			
		||||
                object[] attrs = registerType.GetCustomAttributes(typeof(PreviewHandlerAttribute), true);
 | 
			
		||||
                if (attrs != null && attrs.Length == 1)
 | 
			
		||||
                {
 | 
			
		||||
                    PreviewHandlerAttribute attr = attrs[0] as PreviewHandlerAttribute;
 | 
			
		||||
                    UnregisterPreviewHandler(registerType.GUID, attr);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void RegisterPreviewHandler(Guid previewerGuid, PreviewHandlerAttribute attribute)
 | 
			
		||||
        {
 | 
			
		||||
            string guid = previewerGuid.ToString("B");
 | 
			
		||||
            // Create a new prevhost AppID so that this always runs in its own isolated process
 | 
			
		||||
            using (RegistryKey appIdsKey = Registry.ClassesRoot.OpenSubKey("AppID", true))
 | 
			
		||||
            using (RegistryKey appIdKey = appIdsKey.CreateSubKey(attribute.AppId))
 | 
			
		||||
            {
 | 
			
		||||
                appIdKey.SetValue("DllSurrogate", @"%SystemRoot%\system32\prevhost.exe", RegistryValueKind.ExpandString);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Add preview handler to preview handler list
 | 
			
		||||
            using (RegistryKey handlersKey = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\PreviewHandlers", true))
 | 
			
		||||
            {
 | 
			
		||||
                handlersKey.SetValue(guid, attribute.Name, RegistryValueKind.String);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Modify preview handler registration
 | 
			
		||||
            using (RegistryKey clsidKey = Registry.ClassesRoot.OpenSubKey("CLSID"))
 | 
			
		||||
            using (RegistryKey idKey = clsidKey.OpenSubKey(guid, true))
 | 
			
		||||
            {
 | 
			
		||||
                idKey.SetValue("DisplayName", attribute.Name, RegistryValueKind.String);
 | 
			
		||||
                idKey.SetValue("AppID", attribute.AppId, RegistryValueKind.String);
 | 
			
		||||
                idKey.SetValue("DisableLowILProcessIsolation", attribute.DisableLowILProcessIsolation ? 1 : 0, RegistryValueKind.DWord);
 | 
			
		||||
 | 
			
		||||
                using (RegistryKey inproc = idKey.OpenSubKey("InprocServer32", true))
 | 
			
		||||
                {
 | 
			
		||||
                    inproc.SetValue("ThreadingModel", "Apartment", RegistryValueKind.String);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            foreach (string extension in attribute.Extensions.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
 | 
			
		||||
            {
 | 
			
		||||
                Trace.WriteLine("Registering extension '" + extension + "' with previewer '" + guid + "'");
 | 
			
		||||
 | 
			
		||||
                // Set preview handler for specific extension
 | 
			
		||||
                using (RegistryKey extensionKey = Registry.ClassesRoot.CreateSubKey(extension))
 | 
			
		||||
                using (RegistryKey shellexKey = extensionKey.CreateSubKey("shellex"))
 | 
			
		||||
                using (RegistryKey previewKey = shellexKey.CreateSubKey(HandlerNativeMethods.IPreviewHandlerGuid.ToString("B")))
 | 
			
		||||
                {
 | 
			
		||||
                    previewKey.SetValue(null, guid, RegistryValueKind.String);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void UnregisterPreviewHandler(Guid previewerGuid, PreviewHandlerAttribute attribute)
 | 
			
		||||
        {
 | 
			
		||||
            string guid = previewerGuid.ToString("B");
 | 
			
		||||
            foreach (string extension in attribute.Extensions.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
 | 
			
		||||
            {
 | 
			
		||||
                Trace.WriteLine("Unregistering extension '" + extension + "' with previewer '" + guid + "'");
 | 
			
		||||
                using (RegistryKey shellexKey = Registry.ClassesRoot.OpenSubKey(extension + "\\shellex", true))
 | 
			
		||||
                {
 | 
			
		||||
                    shellexKey.DeleteSubKey(HandlerNativeMethods.IPreviewHandlerGuid.ToString(), false);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            using (RegistryKey appIdsKey = Registry.ClassesRoot.OpenSubKey("AppID", true))
 | 
			
		||||
            {
 | 
			
		||||
                appIdsKey.DeleteSubKey(attribute.AppId, false);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            using (RegistryKey classesKey = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\PreviewHandlers", true))
 | 
			
		||||
            {
 | 
			
		||||
                classesKey.DeleteValue(guid, false);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void ThrowIfNotValid(Type type)
 | 
			
		||||
        {
 | 
			
		||||
            var interfaces = type.GetInterfaces();
 | 
			
		||||
            if (!interfaces.Any(x => x is IPreviewFromStream || x is IPreviewFromFile))
 | 
			
		||||
            {
 | 
			
		||||
                throw new NotImplementedException(
 | 
			
		||||
                    string.Format(System.Globalization.CultureInfo.InvariantCulture,
 | 
			
		||||
                        LocalizedMessages.PreviewHandlerInterfaceNotImplemented,
 | 
			
		||||
                        type.Name));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
#endregion
 | 
			
		||||
 | 
			
		||||
#region ICustomQueryInterface Members
 | 
			
		||||
 | 
			
		||||
        CustomQueryInterfaceResult ICustomQueryInterface.GetInterface(ref Guid iid, out IntPtr ppv)
 | 
			
		||||
        {
 | 
			
		||||
            ppv = IntPtr.Zero;
 | 
			
		||||
            // Forces COM to not use the managed (free threaded) marshaler
 | 
			
		||||
            if (iid == HandlerNativeMethods.IMarshalGuid)
 | 
			
		||||
            {
 | 
			
		||||
                return CustomQueryInterfaceResult.Failed;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if ((iid == HandlerNativeMethods.IInitializeWithStreamGuid && !(this is IPreviewFromStream)) ||
 | 
			
		||||
                (iid == HandlerNativeMethods.IInitializeWithFileGuid && !(this is IPreviewFromFile)))
 | 
			
		||||
            {
 | 
			
		||||
                return CustomQueryInterfaceResult.Failed;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return CustomQueryInterfaceResult.NotHandled;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endregion
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										48
									
								
								ShellExtensions/PreviewHandlers/PreviewHandlerAttribute.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								ShellExtensions/PreviewHandlers/PreviewHandlerAttribute.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
			
		||||
#if PREVIEW_HANDLER
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace ShellExtensions
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// This class attribute is applied to a Preview Handler to specify registration parameters.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
 | 
			
		||||
    public sealed class PreviewHandlerAttribute : Attribute
 | 
			
		||||
    {
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Creates a new instance of the attribute.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="name">Name of the Handler</param>
 | 
			
		||||
        /// <param name="extensions">Semi-colon-separated list of file extensions supported by the handler.</param>
 | 
			
		||||
        /// <param name="appId">A unique guid used for process isolation.</param>
 | 
			
		||||
        public PreviewHandlerAttribute(string name, string extensions, string appId)
 | 
			
		||||
        {
 | 
			
		||||
            Name = name ?? throw new ArgumentNullException(nameof(name));
 | 
			
		||||
            Extensions = extensions ?? throw new ArgumentNullException(nameof(extensions));
 | 
			
		||||
            AppId = appId ?? throw new ArgumentNullException(nameof(appId));
 | 
			
		||||
            DisableLowILProcessIsolation = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the name of the handler.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public string Name { get; private set; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the semi-colon-separated list of extensions supported by the preview handler.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public string Extensions { get; private set; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the AppId associated with the handler for use with the surrogate host process.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public string AppId { get; private set; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Disables low integrity-level process isolation.
 | 
			
		||||
        /// <remarks>This should be avoided as it could be a security risk.</remarks>
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public bool DisableLowILProcessIsolation { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										119
									
								
								ShellExtensions/PreviewHandlers/WinFormsPreviewHandler.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								ShellExtensions/PreviewHandlers/WinFormsPreviewHandler.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,119 @@
 | 
			
		||||
#if PREVIEW_HANDLER
 | 
			
		||||
using ShellExtensions.Interop;
 | 
			
		||||
using ShellExtensions.Interop.Common;
 | 
			
		||||
using ShellExtensions.Resources;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Drawing;
 | 
			
		||||
using System.Windows.Forms;
 | 
			
		||||
 | 
			
		||||
namespace ShellExtensions
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// This is the base class for all WinForms-based preview handlers and provides their basic functionality.
 | 
			
		||||
    /// To create a custom preview handler that contains a WinForms user control,
 | 
			
		||||
    /// a class must derive from this, use the <typeparamref name="PreviewHandlerAttribute"/>,
 | 
			
		||||
    /// and implement 1 or more of the following interfaces: 
 | 
			
		||||
    /// <typeparamref name="IPreviewFromStream"/>, 
 | 
			
		||||
    /// <typeparamref name="IPreviewFromShellObject"/>, 
 | 
			
		||||
    /// <typeparamref name="IPreviewFromFile"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public abstract class WinFormsPreviewHandler : PreviewHandler, IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// This control must be populated by the deriving class before the preview is shown.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public UserControl Control { get; protected set; }
 | 
			
		||||
 | 
			
		||||
        protected void ThrowIfNoControl()
 | 
			
		||||
        {
 | 
			
		||||
            if (Control == null)
 | 
			
		||||
            {
 | 
			
		||||
                throw new InvalidOperationException(LocalizedMessages.PreviewHandlerControlNotInitialized);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Called when an exception is thrown during itialization of the preview control.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="caughtException"></param>
 | 
			
		||||
        protected override void HandleInitializeException(Exception caughtException)
 | 
			
		||||
        {
 | 
			
		||||
            if (caughtException == null) { throw new ArgumentNullException(nameof(caughtException)); }
 | 
			
		||||
 | 
			
		||||
            Control = new UserControl();
 | 
			
		||||
            Control.Controls.Add(new TextBox
 | 
			
		||||
            {
 | 
			
		||||
                ReadOnly = true,
 | 
			
		||||
                Multiline = true,
 | 
			
		||||
                Dock = DockStyle.Fill,
 | 
			
		||||
                Text = caughtException.ToString(),
 | 
			
		||||
                BackColor = Color.OrangeRed
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override void UpdateBounds(NativeRect bounds)
 | 
			
		||||
        {
 | 
			
		||||
            Control.Bounds = Rectangle.FromLTRB(bounds.Left, bounds.Top, bounds.Right, bounds.Bottom);
 | 
			
		||||
            Control.Visible = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override void SetFocus()
 | 
			
		||||
        {
 | 
			
		||||
            Control.Focus();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override void SetBackground(int argb)
 | 
			
		||||
        {
 | 
			
		||||
            Control.BackColor = Color.FromArgb(argb);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override void SetForeground(int argb)
 | 
			
		||||
        {
 | 
			
		||||
            Control.ForeColor = Color.FromArgb(argb);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override void SetFont(Interop.LogFont font)
 | 
			
		||||
        {
 | 
			
		||||
            Control.Font = Font.FromLogFont(font);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override IntPtr Handle
 | 
			
		||||
        {
 | 
			
		||||
            get
 | 
			
		||||
            {
 | 
			
		||||
                {
 | 
			
		||||
                    return Control.Handle;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override void SetParentHandle(IntPtr handle)
 | 
			
		||||
        {
 | 
			
		||||
            HandlerNativeMethods.SetParent(Control.Handle, handle);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
#region IDisposable Members
 | 
			
		||||
 | 
			
		||||
        ~WinFormsPreviewHandler()
 | 
			
		||||
        {
 | 
			
		||||
            Dispose(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            Dispose(true);
 | 
			
		||||
            GC.SuppressFinalize(this);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected virtual void Dispose(bool disposing)
 | 
			
		||||
        {
 | 
			
		||||
            if (disposing && Control != null)
 | 
			
		||||
            {
 | 
			
		||||
                Control.Dispose();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
#endregion
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										186
									
								
								ShellExtensions/PreviewHandlers/WpfPreviewHandler.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										186
									
								
								ShellExtensions/PreviewHandlers/WpfPreviewHandler.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,186 @@
 | 
			
		||||
#if PREVIEW_HANDLER
 | 
			
		||||
using ShellExtensions.Interop;
 | 
			
		||||
using ShellExtensions.Interop.Common;
 | 
			
		||||
using ShellExtensions.Resources;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Windows.Controls;
 | 
			
		||||
using System.Windows.Interop;
 | 
			
		||||
using System.Windows.Media;
 | 
			
		||||
 | 
			
		||||
namespace ShellExtensions.PreviewHandlers
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// This is the base class for all WPF-based preview handlers and provides their basic functionality.
 | 
			
		||||
    /// To create a custom preview handler that contains a WPF user control,
 | 
			
		||||
    /// a class must derive from this, use the <typeparamref name="PreviewHandlerAttribute"/>,
 | 
			
		||||
    /// and implement 1 or more of the following interfaces: 
 | 
			
		||||
    /// <typeparamref name="IPreviewFromStream"/>, 
 | 
			
		||||
    /// <typeparamref name="IPreviewFromShellObject"/>, 
 | 
			
		||||
    /// <typeparamref name="IPreviewFromFile"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public abstract class WpfPreviewHandler : PreviewHandler, IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        HwndSource _source = null;
 | 
			
		||||
        private IntPtr _parentHandle = IntPtr.Zero;
 | 
			
		||||
        private NativeRect _bounds;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// This control must be populated by the deriving class before the preview is shown.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public UserControl Control { get; protected set; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Throws an exception if the Control property has not been populated.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        protected void ThrowIfNoControl()
 | 
			
		||||
        {
 | 
			
		||||
            if (Control == null)
 | 
			
		||||
            {
 | 
			
		||||
                throw new InvalidOperationException(LocalizedMessages.PreviewHandlerControlNotInitialized);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Updates the placement of the Control.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        protected void UpdatePlacement()
 | 
			
		||||
        {
 | 
			
		||||
            if (_source != null)
 | 
			
		||||
            {
 | 
			
		||||
                HandlerNativeMethods.SetParent(_source.Handle, _parentHandle);
 | 
			
		||||
 | 
			
		||||
                HandlerNativeMethods.SetWindowPos(_source.Handle, new IntPtr((int)SetWindowPositionInsertAfter.Top),
 | 
			
		||||
                0, 0, Math.Abs(_bounds.Left - _bounds.Right), Math.Abs(_bounds.Top - _bounds.Bottom), SetWindowPositionOptions.ShowWindow);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override void SetParentHandle(IntPtr handle)
 | 
			
		||||
        {
 | 
			
		||||
            _parentHandle = handle;
 | 
			
		||||
            UpdatePlacement();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override void Initialize()
 | 
			
		||||
        {
 | 
			
		||||
            if (_source == null)
 | 
			
		||||
            {
 | 
			
		||||
                ThrowIfNoControl();
 | 
			
		||||
 | 
			
		||||
                HwndSourceParameters p = new HwndSourceParameters
 | 
			
		||||
                {
 | 
			
		||||
                    WindowStyle = (int)(WindowStyles.Child | WindowStyles.Visible | WindowStyles.ClipSiblings),
 | 
			
		||||
                    ParentWindow = _parentHandle,
 | 
			
		||||
                    Width = Math.Abs(_bounds.Left - _bounds.Right),
 | 
			
		||||
                    Height = Math.Abs(_bounds.Top - _bounds.Bottom)
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                _source = new HwndSource(p);
 | 
			
		||||
                _source.CompositionTarget.BackgroundColor = Brushes.WhiteSmoke.Color;
 | 
			
		||||
                _source.RootVisual = (Visual)Control.Content;
 | 
			
		||||
            }
 | 
			
		||||
            UpdatePlacement();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override IntPtr Handle
 | 
			
		||||
        {
 | 
			
		||||
            get
 | 
			
		||||
            {
 | 
			
		||||
                {
 | 
			
		||||
                    if (_source == null)
 | 
			
		||||
                    {
 | 
			
		||||
                        throw new InvalidOperationException(LocalizedMessages.WpfPreviewHandlerNoHandle);
 | 
			
		||||
                    }
 | 
			
		||||
                    return _source.Handle;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override void UpdateBounds(NativeRect bounds)
 | 
			
		||||
        {
 | 
			
		||||
            _bounds = bounds;
 | 
			
		||||
            UpdatePlacement();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override void HandleInitializeException(Exception caughtException)
 | 
			
		||||
        {
 | 
			
		||||
            if (caughtException == null) { return; }
 | 
			
		||||
 | 
			
		||||
            TextBox text = new TextBox
 | 
			
		||||
            {
 | 
			
		||||
                IsReadOnly = true,
 | 
			
		||||
                MaxLines = 20,
 | 
			
		||||
                Text = caughtException.ToString()
 | 
			
		||||
            };
 | 
			
		||||
            Control = new UserControl() { Content = text };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override void SetFocus()
 | 
			
		||||
        {
 | 
			
		||||
            Control.Focus();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override void SetBackground(int argb)
 | 
			
		||||
        {
 | 
			
		||||
            Control.Background = new SolidColorBrush(Color.FromArgb(
 | 
			
		||||
                (byte)((argb >> 24) & 0xFF), //a
 | 
			
		||||
                (byte)((argb >> 16) & 0xFF), //r
 | 
			
		||||
                (byte)((argb >> 8) & 0xFF), //g
 | 
			
		||||
                (byte)(argb & 0xFF))); //b
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override void SetForeground(int argb)
 | 
			
		||||
        {
 | 
			
		||||
            Control.Foreground = new SolidColorBrush(Color.FromArgb(
 | 
			
		||||
                 (byte)((argb >> 24) & 0xFF), //a
 | 
			
		||||
                 (byte)((argb >> 16) & 0xFF), //r
 | 
			
		||||
                 (byte)((argb >> 8) & 0xFF), //g
 | 
			
		||||
                 (byte)(argb & 0xFF))); //b
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override void SetFont(LogFont font)
 | 
			
		||||
        {
 | 
			
		||||
            if (font == null) { throw new ArgumentNullException(nameof(font)); }
 | 
			
		||||
 | 
			
		||||
            Control.FontFamily = new FontFamily(font.FaceName);
 | 
			
		||||
            Control.FontSize = font.Height;
 | 
			
		||||
            Control.FontWeight = font.Weight > 0 && font.Weight < 1000 ?
 | 
			
		||||
                System.Windows.FontWeight.FromOpenTypeWeight(font.Weight) :
 | 
			
		||||
                System.Windows.FontWeights.Normal;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
#region IDisposable Members
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Preview handler control finalizer
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        ~WpfPreviewHandler()
 | 
			
		||||
        {
 | 
			
		||||
            Dispose(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Disposes the control
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            Dispose(true);
 | 
			
		||||
            GC.SuppressFinalize(this);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Provides means to dispose the object.
 | 
			
		||||
        /// When overriden, it is imperative that base.Dispose(true) is called within the implementation.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="disposing"></param>
 | 
			
		||||
        protected virtual void Dispose(bool disposing)
 | 
			
		||||
        {
 | 
			
		||||
            if (disposing && _source != null)
 | 
			
		||||
            {
 | 
			
		||||
                _source.Dispose();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
#endregion
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
		Reference in New Issue
	
	Block a user