Use NamedPipe, instead of second instance, to invoke preview from command line

This commit is contained in:
Paddy Xu
2017-06-09 21:13:21 +03:00
committed by Emanuel Alves
parent ef9b854939
commit 9a0b4f23fe
4 changed files with 128 additions and 103 deletions

View File

@@ -1,10 +1,10 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Windows;
using QuickLook.Helpers;
using System.Windows.Threading;
namespace QuickLook
{
@@ -16,9 +16,9 @@ namespace QuickLook
public static readonly bool Is64Bit = Environment.Is64BitProcess;
public static readonly string AppFullPath = Assembly.GetExecutingAssembly().Location;
public static readonly string AppPath = Path.GetDirectoryName(AppFullPath);
public static bool RunningAsViewer;
private static bool _duplicated;
private bool _isFirstInstance;
private Mutex _isRunning;
protected override void OnStartup(StartupEventArgs e)
{
@@ -27,7 +27,7 @@ namespace QuickLook
MessageBox.Show(((Exception) args.ExceptionObject).Message + Environment.NewLine +
((Exception) args.ExceptionObject).StackTrace);
Current.Shutdown();
Shutdown();
};
base.OnStartup(e);
@@ -35,65 +35,60 @@ namespace QuickLook
private void Application_Startup(object sender, StartupEventArgs e)
{
if (e.Args.Any())
if (Directory.Exists(e.Args.First()) || File.Exists(e.Args.First()))
RunAsViewer(e);
EnsureFirstInstance();
if (!_isFirstInstance)
{
// second instance: preview this file
if (e.Args.Any() && (Directory.Exists(e.Args.First()) || File.Exists(e.Args.First())))
RemoteCallShowPreview(e);
// second instance: duplicate
else
RunAsListener(e);
else
RunAsListener(e);
}
MessageBox.Show("QuickLook is already running in the background.");
private void RunAsViewer(StartupEventArgs e)
{
RunningAsViewer = true;
var runningPid = PidHelper.GetRunningInstance();
if (runningPid != -1)
{
Process.GetProcessById(runningPid).Kill();
Current.Shutdown();
Shutdown();
return;
}
PidHelper.WritePid();
RunListener(e);
ViewWindowManager.GetInstance().InvokeViewer(e.Args.First());
// second instance: run and preview this file
if (e.Args.Any() && (Directory.Exists(e.Args.First()) || File.Exists(e.Args.First())))
RemoteCallShowPreview(e);
}
private void RunAsListener(StartupEventArgs e)
private void RemoteCallShowPreview(StartupEventArgs e)
{
RunningAsViewer = false;
if (PidHelper.GetRunningInstance() != -1)
{
_duplicated = true;
MessageBox.Show("QuickLook is already running in the background.");
Current.Shutdown();
return;
}
PidHelper.WritePid();
PipeServerManager.SendMessage(e.Args.First());
}
private void RunListener(StartupEventArgs e)
{
TrayIconManager.GetInstance();
if (!e.Args.Contains("/autorun"))
TrayIconManager.GetInstance().ShowNotification("", "QuickLook is running in the background.");
PluginManager.GetInstance();
BackgroundListener.GetInstance();
PipeServerManager.GetInstance().MessageReceived +=
(msg, ea) => Dispatcher.BeginInvoke(
new Action(() => ViewWindowManager.GetInstance().InvokeViewer(msg as string)),
DispatcherPriority.ApplicationIdle);
}
private void App_OnExit(object sender, ExitEventArgs e)
{
TrayIconManager.GetInstance().Dispose();
BackgroundListener.GetInstance().Dispose();
if (_isFirstInstance)
{
PipeServerManager.GetInstance().Dispose();
TrayIconManager.GetInstance().Dispose();
BackgroundListener.GetInstance().Dispose();
}
}
if (!_duplicated)
PidHelper.DeletePid();
private void EnsureFirstInstance()
{
_isRunning = new Mutex(true, "QuickLook.App.Mutex", out _isFirstInstance);
}
}
}

View File

@@ -1,59 +0,0 @@
using System.Diagnostics;
using System.IO;
namespace QuickLook.Helpers
{
internal static class PidHelper
{
private static FileStream _pidLocker;
private static readonly string PidListener =
Path.Combine(Path.GetTempPath(), "QuickLook.App.Listener.D6EC3F8DDF6B.pid");
private static readonly string PidViewer =
Path.Combine(Path.GetTempPath(), "QuickLook.App.Viewer.A6FA53E93515.pid");
internal static int GetRunningInstance()
{
var pid = App.RunningAsViewer ? PidViewer : PidListener;
if (!File.Exists(pid))
return -1;
var ppid = -1;
using (var file = File.Open(pid, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var sr = new StreamReader(file))
{
int.TryParse(sr.ReadToEnd(), out ppid);
}
try
{
Process.GetProcessById(ppid);
}
catch
{
return -1;
}
return ppid;
}
internal static void WritePid()
{
var pidFile = App.RunningAsViewer ? PidViewer : PidListener;
File.WriteAllText(pidFile, Process.GetCurrentProcess().Id.ToString());
_pidLocker = File.Open(pidFile, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read);
}
internal static void DeletePid()
{
_pidLocker?.Close();
_pidLocker = null;
File.Delete(App.RunningAsViewer ? PidViewer : PidListener);
}
}
}

View File

@@ -0,0 +1,89 @@
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Threading.Tasks;
namespace QuickLook
{
internal class PipeServerManager : IDisposable
{
private const string PipeName = "QuickLook.App.Pipe";
private const string PipeCloseMessage = "QuickLook.App.Pipe.QuitSingal";
private static PipeServerManager _instance;
private NamedPipeServerStream _server;
public PipeServerManager()
{
_server = new NamedPipeServerStream(PipeName, PipeDirection.In);
new Task(() =>
{
using (var reader = new StreamReader(_server))
{
while (true)
{
Debug.WriteLine("PipeManager: WaitForConnection");
_server.WaitForConnection();
var msg = reader.ReadLine();
Debug.WriteLine($"PipeManager: {msg}");
if (msg == PipeCloseMessage)
return;
// dispatch message
MessageReceived?.Invoke(msg, new EventArgs());
_server.Disconnect();
}
}
}).Start();
}
public void Dispose()
{
GC.SuppressFinalize(this);
if (_server != null)
SendMessage(PipeCloseMessage);
_server?.Dispose();
_server = null;
}
public event EventHandler MessageReceived;
public static void SendMessage(string msg)
{
try
{
using (var client = new NamedPipeClientStream(".", PipeName, PipeDirection.Out))
{
client.Connect();
using (var writer = new StreamWriter(client))
{
writer.WriteLine(msg);
writer.Flush();
}
}
}
catch (Exception e)
{
Debug.WriteLine(e.ToString());
}
}
~PipeServerManager()
{
Dispose();
}
public static PipeServerManager GetInstance()
{
return _instance ?? (_instance = new PipeServerManager());
}
}
}

View File

@@ -134,7 +134,7 @@
<Compile Include="Helpers\FileHelper.cs" />
<Compile Include="Helpers\ProcessHelper.cs" />
<Compile Include="MainWindowNoTransparent.cs" />
<Compile Include="Helpers\PidHelper.cs" />
<Compile Include="PipeServerManager.cs" />
<Compile Include="PluginManager.cs" />
<Compile Include="Plugin\InfoPanel\DpiHelpers.cs" />
<Compile Include="Plugin\InfoPanel\Extensions.cs" />