diff --git a/QuickLook/Helpers/AutoStartupHelper.cs b/QuickLook/Helpers/AutoStartupHelper.cs
index 504843b..588f8cc 100644
--- a/QuickLook/Helpers/AutoStartupHelper.cs
+++ b/QuickLook/Helpers/AutoStartupHelper.cs
@@ -17,7 +17,9 @@
using System;
using System.IO;
+using System.Runtime.InteropServices.ComTypes;
using QuickLook.Common.Helpers;
+using QuickLook.NativeMethods;
namespace QuickLook.Helpers
{
@@ -34,16 +36,15 @@ namespace QuickLook.Helpers
try
{
- File.Create(StartupFullPath).Close();
+ RemoveAutorunShortcut();
- var lnk = ShellLinkHelper.OpenShellLink(StartupFullPath);
+ var lnk = (IShellLinkW) new ShellLink();
- lnk.Path = App.AppFullPath;
- lnk.Arguments = "/autorun"; // silent
+ lnk.SetPath(App.AppFullPath);
+ lnk.SetArguments("/autorun"); // silent
lnk.SetIconLocation(App.AppFullPath, 0);
- lnk.WorkingDirectory = App.AppPath;
-
- lnk.Save(StartupFullPath);
+ lnk.SetWorkingDirectory(App.AppPath);
+ ((IPersistFile) lnk).Save(StartupFullPath, false);
}
catch (Exception e)
{
@@ -57,7 +58,15 @@ namespace QuickLook.Helpers
if (App.IsUWP)
return;
- File.Delete(StartupFullPath);
+ try
+ {
+ File.Delete(StartupFullPath);
+ }
+ catch (Exception e)
+ {
+ ProcessHelper.WriteLog(e.ToString());
+ TrayIconManager.ShowNotification("", "Failed to delete QuickLook startup shortcut.");
+ }
}
internal static bool IsAutorun()
diff --git a/QuickLook/Helpers/ShellLinkHelper.cs b/QuickLook/Helpers/ShellLinkHelper.cs
deleted file mode 100644
index 44b5c82..0000000
--- a/QuickLook/Helpers/ShellLinkHelper.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright © 2018 Paddy Xu
-//
-// This file is part of QuickLook program.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see .
-
-using System;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-using Shell32;
-
-namespace QuickLook.Helpers
-{
- public class ShellLinkHelper
- {
- public static ShellLinkObject OpenShellLink(string path)
- {
- if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA)
- return StartSTATask(() => OpenShellLink(path)).Result;
-
- var shl = new Shell();
- var dir = shl.NameSpace(Path.GetDirectoryName(path));
- var itm = dir.Items().Item(Path.GetFileName(path));
- var lnk = (ShellLinkObject) itm.GetLink;
- return lnk;
- }
-
- public static string GetTarget(string path)
- {
- if (Path.GetExtension(path).ToLower() != ".lnk")
- return path;
-
- try
- {
- return Thread.CurrentThread.GetApartmentState() != ApartmentState.STA
- ? StartSTATask(() => GetTarget(path)).Result
- : OpenShellLink(path).Target.Path;
- }
- catch (Exception)
- {
- // ignored
- }
-
- return path;
- }
-
- private static Task StartSTATask(Func func)
- {
- var tcs = new TaskCompletionSource();
- var thread = new Thread(() =>
- {
- try
- {
- tcs.SetResult(func());
- }
- catch (Exception e)
- {
- tcs.SetException(e);
- }
- });
- thread.SetApartmentState(ApartmentState.STA);
- thread.Start();
- return tcs.Task;
- }
- }
-}
\ No newline at end of file
diff --git a/QuickLook/NativeMethods/ShellLink.cs b/QuickLook/NativeMethods/ShellLink.cs
new file mode 100644
index 0000000..0c906b0
--- /dev/null
+++ b/QuickLook/NativeMethods/ShellLink.cs
@@ -0,0 +1,169 @@
+// Copyright © 2018 Paddy Xu
+//
+// This file is part of QuickLook program.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+using System;
+using System.Runtime.InteropServices;
+using System.Text;
+
+// ReSharper disable InconsistentNaming
+
+namespace QuickLook.NativeMethods
+{
+ [Flags]
+ internal enum SLGP_FLAGS
+ {
+ /// Retrieves the standard short (8.3 format) file name
+ SLGP_SHORTPATH = 0x1,
+ /// Retrieves the Universal Naming Convention (UNC) path name of the file
+ SLGP_UNCPRIORITY = 0x2,
+ ///
+ /// Retrieves the raw path name. A raw path is something that might not exist and may include environment
+ /// variables that need to be expanded
+ ///
+ SLGP_RAWPATH = 0x4
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ internal struct WIN32_FIND_DATAW
+ {
+ public uint dwFileAttributes;
+ public long ftCreationTime;
+ public long ftLastAccessTime;
+ public long ftLastWriteTime;
+ public uint nFileSizeHigh;
+ public uint nFileSizeLow;
+ public uint dwReserved0;
+ public uint dwReserved1;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
+ public string cFileName;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
+ public string cAlternateFileName;
+ }
+
+ [Flags]
+ internal enum SLR_FLAGS
+ {
+ ///
+ /// Do not display a dialog box if the link cannot be resolved. When SLR_NO_UI is set,
+ /// the high-order word of fFlags can be set to a time-out value that specifies the
+ /// maximum amount of time to be spent resolving the link. The function returns if the
+ /// link cannot be resolved within the time-out duration. If the high-order word is set
+ /// to zero, the time-out duration will be set to the default value of 3,000 milliseconds
+ /// (3 seconds). To specify a value, set the high word of fFlags to the desired time-out
+ /// duration, in milliseconds.
+ ///
+ SLR_NO_UI = 0x1,
+ /// Obsolete and no longer used
+ SLR_ANY_MATCH = 0x2,
+ ///
+ /// If the link object has changed, update its path and list of identifiers.
+ /// If SLR_UPDATE is set, you do not need to call IPersistFile::IsDirty to determine
+ /// whether or not the link object has changed.
+ ///
+ SLR_UPDATE = 0x4,
+ /// Do not update the link information
+ SLR_NOUPDATE = 0x8,
+ /// Do not execute the search heuristics
+ SLR_NOSEARCH = 0x10,
+ /// Do not use distributed link tracking
+ SLR_NOTRACK = 0x20,
+ ///
+ /// Disable distributed link tracking. By default, distributed link tracking tracks
+ /// removable media across multiple devices based on the volume name. It also uses the
+ /// Universal Naming Convention (UNC) path to track remote file systems whose drive letter
+ /// has changed. Setting SLR_NOLINKINFO disables both types of tracking.
+ ///
+ SLR_NOLINKINFO = 0x40,
+ /// Call the Microsoft Windows Installer
+ SLR_INVOKE_MSI = 0x80
+ }
+
+
+ /// The IShellLink interface allows Shell links to be created, modified, and resolved
+ [ComImport]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ [Guid("000214F9-0000-0000-C000-000000000046")]
+ internal interface IShellLinkW
+ {
+ /// Retrieves the path and file name of a Shell link object
+ void GetPath([Out] [MarshalAs(UnmanagedType.LPWStr)]
+ StringBuilder pszFile, int cchMaxPath, out WIN32_FIND_DATAW pfd, SLGP_FLAGS fFlags);
+
+ /// Retrieves the list of item identifiers for a Shell link object
+ void GetIDList(out IntPtr ppidl);
+
+ /// Sets the pointer to an item identifier list (PIDL) for a Shell link object.
+ void SetIDList(IntPtr pidl);
+
+ /// Retrieves the description string for a Shell link object
+ void GetDescription([Out] [MarshalAs(UnmanagedType.LPWStr)]
+ StringBuilder pszName, int cchMaxName);
+
+ /// Sets the description for a Shell link object. The description can be any application-defined string
+ void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
+
+ /// Retrieves the name of the working directory for a Shell link object
+ void GetWorkingDirectory([Out] [MarshalAs(UnmanagedType.LPWStr)]
+ StringBuilder pszDir, int cchMaxPath);
+
+ /// Sets the name of the working directory for a Shell link object
+ void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
+
+ /// Retrieves the command-line arguments associated with a Shell link object
+ void GetArguments([Out] [MarshalAs(UnmanagedType.LPWStr)]
+ StringBuilder pszArgs, int cchMaxPath);
+
+ /// Sets the command-line arguments for a Shell link object
+ void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
+
+ /// Retrieves the hot key for a Shell link object
+ void GetHotkey(out short pwHotkey);
+
+ /// Sets a hot key for a Shell link object
+ void SetHotkey(short wHotkey);
+
+ /// Retrieves the show command for a Shell link object
+ void GetShowCmd(out int piShowCmd);
+
+ /// Sets the show command for a Shell link object. The show command sets the initial show state of the window.
+ void SetShowCmd(int iShowCmd);
+
+ /// Retrieves the location (path and index) of the icon for a Shell link object
+ void GetIconLocation([Out] [MarshalAs(UnmanagedType.LPWStr)]
+ StringBuilder pszIconPath,
+ int cchIconPath, out int piIcon);
+
+ /// Sets the location (path and index) of the icon for a Shell link object
+ void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
+
+ /// Sets the relative path to the Shell link object
+ void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, int dwReserved);
+
+ /// Attempts to find the target of a Shell link, even if it has been moved or renamed
+ void Resolve(IntPtr hwnd, SLR_FLAGS fFlags);
+
+ /// Sets the path and file name of a Shell link object
+ void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
+ }
+
+ // CLSID_ShellLink from ShlGuid.h
+ [ComImport]
+ [Guid("00021401-0000-0000-C000-000000000046")]
+ public class ShellLink
+ {
+ }
+}
\ No newline at end of file
diff --git a/QuickLook/PipeServerManager.cs b/QuickLook/PipeServerManager.cs
index caf9f68..9970b0e 100644
--- a/QuickLook/PipeServerManager.cs
+++ b/QuickLook/PipeServerManager.cs
@@ -19,11 +19,13 @@ using System;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
+using System.Runtime.InteropServices.ComTypes;
using System.Security.Principal;
+using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
-using QuickLook.Helpers;
+using QuickLook.NativeMethods;
namespace QuickLook
{
@@ -123,7 +125,8 @@ namespace QuickLook
var wParam = msg.Substring(0, split);
var lParam = msg.Substring(split + 1, msg.Length - split - 1);
- lParam = ShellLinkHelper.GetTarget(lParam);
+ if (!string.IsNullOrEmpty(lParam))
+ lParam = ResolveShortcut(lParam);
switch (wParam)
{
@@ -168,5 +171,17 @@ namespace QuickLook
{
return _instance ?? (_instance = new PipeServerManager());
}
+
+ public static string ResolveShortcut(string filename)
+ {
+ if (Path.GetExtension(filename).ToLower() != ".lnk")
+ return filename;
+
+ var link = new ShellLink();
+ ((IPersistFile) link).Load(filename, 0);
+ var sb = new StringBuilder(260);
+ ((IShellLinkW) link).GetPath(sb, sb.Capacity, out _, 0);
+ return sb.ToString();
+ }
}
}
\ No newline at end of file
diff --git a/QuickLook/QuickLook.csproj b/QuickLook/QuickLook.csproj
index 5497c67..7bbd124 100644
--- a/QuickLook/QuickLook.csproj
+++ b/QuickLook/QuickLook.csproj
@@ -143,7 +143,7 @@
-
+
@@ -245,17 +245,6 @@
Always
-
-
- {50A7E9B0-70EF-11D1-B75A-00A0C90564FE}
- 1
- 0
- 0
- tlbimp
- False
- True
-
-
PreserveNewest