diff --git a/QuickLook.Installer/Product.wxs b/QuickLook.Installer/Product.wxs
index a221250..eaf567b 100644
--- a/QuickLook.Installer/Product.wxs
+++ b/QuickLook.Installer/Product.wxs
@@ -1,7 +1,7 @@
-
+
-
@@ -13,7 +13,7 @@
-
+
@@ -64,4 +64,4 @@
-
+
\ No newline at end of file
diff --git a/QuickLook.Plugin/QuickLook.Plugin.IPreviewHandlers/PluginInterface.cs b/QuickLook.Plugin/QuickLook.Plugin.IPreviewHandlers/PluginInterface.cs
index d79edab..35bd807 100644
--- a/QuickLook.Plugin/QuickLook.Plugin.IPreviewHandlers/PluginInterface.cs
+++ b/QuickLook.Plugin/QuickLook.Plugin.IPreviewHandlers/PluginInterface.cs
@@ -1,8 +1,6 @@
using System;
using System.IO;
-using System.Runtime.InteropServices;
using System.Windows;
-using System.Windows.Interop;
namespace QuickLook.Plugin.IPreviewHandlers
{
@@ -60,7 +58,7 @@ namespace QuickLook.Plugin.IPreviewHandlers
_panel?.Dispose();
_panel = null;
}
-
+
~PluginInterface()
{
Cleanup();
diff --git a/QuickLook.Plugin/QuickLook.Plugin.PDFViewer/Plugin.cs b/QuickLook.Plugin/QuickLook.Plugin.PDFViewer/Plugin.cs
index 0d41bf7..19a16c8 100644
--- a/QuickLook.Plugin/QuickLook.Plugin.PDFViewer/Plugin.cs
+++ b/QuickLook.Plugin/QuickLook.Plugin.PDFViewer/Plugin.cs
@@ -1,6 +1,5 @@
using System;
using System.IO;
-using System.Text;
namespace QuickLook.Plugin.PDFViewer
{
diff --git a/QuickLook/BackgroundListener.cs b/QuickLook/BackgroundListener.cs
index a45f792..519297a 100644
--- a/QuickLook/BackgroundListener.cs
+++ b/QuickLook/BackgroundListener.cs
@@ -24,7 +24,7 @@ namespace QuickLook
if (e.Modifiers != Keys.None)
return;
- ViewWindowManager.GetInstance().InvokeRoutine(e.KeyCode != Keys.Space);
+ ViewWindowManager.GetInstance().InvokeRoutine(e.KeyCode);
}
private void InstallHook(KeyEventHandler handler)
@@ -32,6 +32,8 @@ namespace QuickLook
_hook = GlobalKeyboardHook.GetInstance();
_hook.HookedKeys.Add(Keys.Space);
+ //_hook.HookedKeys.Add(Keys.Enter);
+
_hook.HookedKeys.Add(Keys.Up);
_hook.HookedKeys.Add(Keys.Down);
_hook.HookedKeys.Add(Keys.Left);
diff --git a/QuickLook/Helpers/DpiHelpers.cs b/QuickLook/Helpers/DpiHelper.cs
similarity index 100%
rename from QuickLook/Helpers/DpiHelpers.cs
rename to QuickLook/Helpers/DpiHelper.cs
diff --git a/QuickLook/Helpers/FileHelper.cs b/QuickLook/Helpers/FileHelper.cs
new file mode 100644
index 0000000..55bbc3e
--- /dev/null
+++ b/QuickLook/Helpers/FileHelper.cs
@@ -0,0 +1,134 @@
+using System;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Text;
+using QuickLook.NativeMethods;
+
+namespace QuickLook.Helpers
+{
+ internal class FileHelper
+ {
+ private static string GetExecutable(string line)
+ {
+ var ret = line.StartsWith("\"")
+ ? line.Split(new[] {"\" "}, 2, StringSplitOptions.None)
+ : line.Split(new[] {' '}, 2, StringSplitOptions.None);
+
+ ret[0] = ret[0].StartsWith("\"") ? ret[0].Substring(1) : ret[0];
+ return ret[0];
+ }
+
+ public static bool? GetAssocApplication(string path, out string executePath, out string appFriendlyName)
+ {
+ executePath = string.Empty;
+ appFriendlyName = string.Empty;
+
+ if (string.IsNullOrEmpty(path))
+ return null;
+
+ if (Directory.Exists(path))
+ return null;
+
+ if (!File.Exists(path))
+ return null;
+
+ if (Path.GetExtension(path) == ".lnk")
+ {
+ var shell = (IWshShell) new WshShell();
+ var link = shell.CreateShortcut(path);
+ path = GetExecutable(link.TargetPath);
+ }
+
+ var ext = Path.GetExtension(path).ToLower();
+ var isExe = ext.ToLower() == ".exe";
+
+ // no assoc. app. found
+ if (string.IsNullOrEmpty(GetAssocApplicationNative(ext, AssocStr.Command)))
+ if (string.IsNullOrEmpty(GetAssocApplicationNative(ext, AssocStr.AppId))) // UWP
+ return null;
+
+ executePath = path;
+ appFriendlyName = isExe
+ ? FileVersionInfo.GetVersionInfo(path).FileDescription
+ : GetAssocApplicationNative(ext, AssocStr.FriendlyAppName);
+
+ if (string.IsNullOrEmpty(appFriendlyName))
+ appFriendlyName = Path.GetFileName(path);
+
+ return isExe;
+ }
+
+ [DllImport("shlwapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ private static extern uint AssocQueryString(AssocF flags, AssocStr str, string pszAssoc, string pszExtra,
+ [Out] StringBuilder sOut, [In] [Out] ref uint nOut);
+
+ private static string GetAssocApplicationNative(string fileExtensionIncludingDot, AssocStr str)
+ {
+ uint cOut = 0;
+ if (AssocQueryString(AssocF.Verify | AssocF.RemapRunDll | AssocF.InitIgnoreUnknown, str,
+ fileExtensionIncludingDot, null, null,
+ ref cOut) != 1)
+ return null;
+
+ var pOut = new StringBuilder((int) cOut);
+ if (AssocQueryString(AssocF.Verify | AssocF.RemapRunDll | AssocF.InitIgnoreUnknown, str,
+ fileExtensionIncludingDot, null, pOut,
+ ref cOut) != 0)
+ return null;
+
+ return pOut.ToString();
+ }
+
+ [SuppressMessage("ReSharper", "InconsistentNaming")]
+ [Flags]
+ private enum AssocF
+ {
+ InitNoRemapCLSID = 0x1,
+ InitByExeName = 0x2,
+ OpenByExeName = 0x2,
+ InitDefaultToStar = 0x4,
+ InitDefaultToFolder = 0x8,
+ NoUserSettings = 0x10,
+ NoTruncate = 0x20,
+ Verify = 0x40,
+ RemapRunDll = 0x80,
+ NoFixUps = 0x100,
+ IgnoreBaseClass = 0x200,
+ InitIgnoreUnknown = 0x400,
+ InitFixedProgid = 0x800,
+ IsProtocol = 0x1000,
+ InitForFile = 0x2000
+ }
+
+ //[SuppressMessage("ReSharper", "InconsistentNaming")]
+ private enum AssocStr
+ {
+ Command = 1,
+ Executable,
+ FriendlyDocName,
+ FriendlyAppName,
+ NoOpen,
+ ShellNewValue,
+ DdeCommand,
+ DdeIfExec,
+ DdeApplication,
+ DdeTopic,
+ InfoTip,
+ QuickTip,
+ TileInfo,
+ ContentType,
+ DefaultIcon,
+ ShellExtension,
+ DropTarget,
+ DelegateExecute,
+ SupportedUriProtocols,
+ ProgId,
+ AppId,
+ AppPublisher,
+ AppIconReference,
+ Max
+ }
+ }
+}
\ No newline at end of file
diff --git a/QuickLook/MainWindowTransparent.xaml b/QuickLook/MainWindowTransparent.xaml
index 5f650f3..55e9959 100644
--- a/QuickLook/MainWindowTransparent.xaml
+++ b/QuickLook/MainWindowTransparent.xaml
@@ -57,6 +57,11 @@
WindowChrome.IsHitTestVisibleInChrome="True"
Height="15" Margin="10,0" Foreground="Gray"
Cursor="Hand" />
+
public partial class MainWindowTransparent : Window
{
+ private string _path = string.Empty;
+
internal MainWindowTransparent()
{
// this object should be initialized before loading UI components, because many of which are binding to it.
@@ -31,10 +34,27 @@ namespace QuickLook
};
buttonCloseWindow.MouseLeftButtonUp += (sender, e) => BeginHide(true);
+
+ /*PreviewKeyUp += (sender, e) =>
+ {
+ if (e.Key == Key.Enter)
+ OpenWithAssocApp();
+ };*/
+
+ buttonOpenWith.Click += (sender, e) => OpenWithAssocApp();
}
public ContextObject ContextObject { get; private set; }
+ private void OpenWithAssocApp()
+ {
+ if (string.IsNullOrEmpty(_path))
+ return;
+
+ Process.Start(new ProcessStartInfo(_path) {WorkingDirectory = Path.GetDirectoryName(_path)});
+ BeginHide(true);
+ }
+
private new void Show()
{
// revert UI changes
@@ -107,6 +127,8 @@ namespace QuickLook
// get window size before showing it
ContextObject.ViewerPlugin.Prepare(path, ContextObject);
+ SetOpenWithButtonAndPath(path);
+
Show();
// load plugin, do not block UI
@@ -128,6 +150,15 @@ namespace QuickLook
throw thrown;
}
+ private void SetOpenWithButtonAndPath(string path)
+ {
+ var isExe = FileHelper.GetAssocApplication(path, out string executePath, out string appFriendlyName);
+
+ _path = executePath;
+ buttonOpenWith.Visibility = isExe == null ? Visibility.Collapsed : Visibility.Visible;
+ buttonOpenWith.Content = isExe == true ? $"Run {appFriendlyName}" : $"Open with {appFriendlyName}";
+ }
+
internal bool BeginHide(bool quit = false)
{
if (quit && App.RunningAsViewer)
diff --git a/QuickLook/NativeMethods/ShellLink.cs b/QuickLook/NativeMethods/ShellLink.cs
index 017e144..574f7d6 100644
--- a/QuickLook/NativeMethods/ShellLink.cs
+++ b/QuickLook/NativeMethods/ShellLink.cs
@@ -42,4 +42,36 @@ namespace QuickLook.NativeMethods
void Resolve(IntPtr hwnd, int fFlags);
void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
}
+
+ [ComImport]
+ [Guid("72C24DD5-D70A-438B-8A42-98424B88AFB8")]
+ internal class WshShell
+ {
+ }
+
+ [ComImport]
+ [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
+ [Guid("F935DC21-1CF0-11D0-ADB9-00C04FD58A0B")]
+ internal interface IWshShell
+ {
+ IWshShortcut CreateShortcut(string pathLink);
+ }
+
+ [ComImport]
+ [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
+ [Guid("F935DC23-1CF0-11D0-ADB9-00C04FD58A0B")]
+ internal interface IWshShortcut
+ {
+ string FullName { get; }
+ string Arguments { get; set; }
+ string Description { get; set; }
+ string Hotkey { get; set; }
+ string IconLocation { get; set; }
+ string RelativePath { set; }
+ string TargetPath { get; set; }
+ int WindowStyle { get; set; }
+ string WorkingDirectory { get; set; }
+ void Load([In] string pathLink);
+ void Save();
+ }
}
\ No newline at end of file
diff --git a/QuickLook/QuickLook.csproj b/QuickLook/QuickLook.csproj
index 7bb8d27..7bea191 100644
--- a/QuickLook/QuickLook.csproj
+++ b/QuickLook/QuickLook.csproj
@@ -105,6 +105,7 @@
+
@@ -118,7 +119,7 @@
-
+
diff --git a/QuickLook/ViewWindowManager.cs b/QuickLook/ViewWindowManager.cs
index 0c52de5..a222b92 100644
--- a/QuickLook/ViewWindowManager.cs
+++ b/QuickLook/ViewWindowManager.cs
@@ -5,6 +5,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
+using System.Windows.Forms;
using QuickLook.Helpers;
using QuickLook.Plugin;
@@ -26,8 +27,11 @@ namespace QuickLook
_currentMainWindow = _viewWindowTransparentTransparent;
}
- internal void InvokeRoutine(bool replaceView = false)
+ internal void InvokeRoutine(Keys key)
{
+ // do we need switch to another file?
+ var replaceView = key == Keys.Up || key == Keys.Down || key == Keys.Left || key == Keys.Right;
+
if (replaceView && _currentMainWindow.IsLoaded && _currentMainWindow.Visibility != Visibility.Visible)
return;