fixed #280: Reverted single instance codes

This commit is contained in:
Jaex 2014-09-13 14:52:12 +03:00
parent f469e0cc87
commit f5ce4fcf49
6 changed files with 215 additions and 101 deletions

View file

@ -314,6 +314,8 @@
<Compile Include="Printer\PrintTextHelper.cs" />
<Compile Include="Helpers\RegistryHelpers.cs" />
<Compile Include="SettingsHelper.cs" />
<Compile Include="SingleInstanceApplication\ApplicationInstanceManager.cs" />
<Compile Include="SingleInstanceApplication\InstanceProxy.cs" />
<Compile Include="DebugHelper.cs" />
<Compile Include="UpdateChecker\UpdateCheckerLabel.cs">
<SubType>UserControl</SubType>

View file

@ -0,0 +1,122 @@
#region License Information (GPL v3)
/*
ShareX - A program that allows you to take screenshots and share any file type
Copyright (C) 2007-2014 ShareX Developers
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 2
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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Optionally you can also view the license at <http://www.gnu.org/licenses/>.
*/
#endregion License Information (GPL v3)
using System;
using System.Diagnostics;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Ipc;
using System.Threading;
using System.Windows.Forms;
namespace SingleInstanceApplication
{
public static class ApplicationInstanceManager
{
[DebuggerStepThrough]
public static bool CreateSingleInstance(string name, EventHandler<InstanceCallbackEventArgs> callback, string[] args)
{
string eventName = string.Format("{0}-{1}", Environment.MachineName, name);
InstanceProxy.IsFirstInstance = false;
InstanceProxy.CommandLineArgs = args;
try
{
using (EventWaitHandle eventWaitHandle = EventWaitHandle.OpenExisting(eventName))
{
UpdateRemoteObject(name);
if (eventWaitHandle != null) eventWaitHandle.Set();
}
Environment.Exit(0);
}
catch
{
InstanceProxy.IsFirstInstance = true;
using (EventWaitHandle eventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset, eventName))
{
ThreadPool.RegisterWaitForSingleObject(eventWaitHandle, WaitOrTimerCallback, callback, Timeout.Infinite, false);
}
RegisterRemoteType(name);
}
return InstanceProxy.IsFirstInstance;
}
public static bool CreateSingleInstance(EventHandler<InstanceCallbackEventArgs> callback, string[] args)
{
try
{
return CreateSingleInstance(Application.ProductName, callback, args);
}
catch
{
}
return true;
}
private static void UpdateRemoteObject(string uri)
{
IpcClientChannel clientChannel = new IpcClientChannel();
ChannelServices.RegisterChannel(clientChannel, true);
InstanceProxy proxy = Activator.GetObject(typeof(InstanceProxy), string.Format("ipc://{0}{1}/{1}", Environment.MachineName, uri)) as InstanceProxy;
if (proxy != null)
{
proxy.SetCommandLineArgs(InstanceProxy.IsFirstInstance, InstanceProxy.CommandLineArgs);
}
ChannelServices.UnregisterChannel(clientChannel);
}
private static void RegisterRemoteType(string uri)
{
IpcServerChannel serverChannel = new IpcServerChannel(Environment.MachineName + uri);
ChannelServices.RegisterChannel(serverChannel, true);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(InstanceProxy), uri, WellKnownObjectMode.Singleton);
Process process = Process.GetCurrentProcess();
process.Exited += delegate
{
ChannelServices.UnregisterChannel(serverChannel);
};
}
private static void WaitOrTimerCallback(object state, bool timedOut)
{
EventHandler<InstanceCallbackEventArgs> callback = state as EventHandler<InstanceCallbackEventArgs>;
if (callback == null) return;
callback(state, new InstanceCallbackEventArgs(InstanceProxy.IsFirstInstance, InstanceProxy.CommandLineArgs));
}
}
}

View file

@ -1,4 +1,4 @@
#region License Information (GPL v3)
#region License Information (GPL v3)
/*
ShareX - A program that allows you to take screenshots and share any file type
@ -23,27 +23,36 @@
#endregion License Information (GPL v3)
using Microsoft.VisualBasic.ApplicationServices;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Security.Permissions;
namespace ShareX
namespace SingleInstanceApplication
{
internal class ShareXApplicationBase : WindowsFormsApplicationBase
[Serializable]
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
internal class InstanceProxy : MarshalByRefObject
{
public ShareXApplicationBase(bool isSingleInstance)
{
IsSingleInstance = isSingleInstance;
EnableVisualStyles = true;
}
public static bool IsFirstInstance { get; internal set; }
public new Form MainForm
public static string[] CommandLineArgs { get; internal set; }
public void SetCommandLineArgs(bool isFirstInstance, string[] commandLineArgs)
{
get { return base.MainForm; }
set { base.MainForm = value; }
IsFirstInstance = isFirstInstance;
CommandLineArgs = commandLineArgs;
}
}
public class InstanceCallbackEventArgs : EventArgs
{
internal InstanceCallbackEventArgs(bool isFirstInstance, string[] commandLineArgs)
{
IsFirstInstance = isFirstInstance;
CommandLineArgs = commandLineArgs;
}
public bool IsFirstInstance { get; private set; }
public string[] CommandLineArgs { get; private set; }
}
}

View file

@ -41,7 +41,7 @@ namespace ShareX
{
public partial class MainForm : HotkeyForm
{
public ManualResetEvent ReadyWaitHandle { get; private set; }
public bool IsReady { get; private set; }
private bool forceClose;
private UploadInfoManager uim;
@ -49,7 +49,6 @@ public partial class MainForm : HotkeyForm
public MainForm()
{
ReadyWaitHandle = new ManualResetEvent(false);
InitControls();
HandleCreated += MainForm_HandleCreated;
}
@ -63,7 +62,7 @@ private void MainForm_HandleCreated(object sender, EventArgs e)
AutoCheckUpdate();
#endif
ReadyWaitHandle.Set();
IsReady = true;
DebugHelper.WriteLine("Startup time: {0} ms", Program.StartTimer.ElapsedMilliseconds);
@ -678,7 +677,7 @@ private void MainForm_Resize(object sender, EventArgs e)
private void MainForm_LocationChanged(object sender, EventArgs e)
{
if (ReadyWaitHandle.WaitOne(0) && WindowState == FormWindowState.Normal)
if (IsReady && WindowState == FormWindowState.Normal)
{
Program.Settings.MainFormPosition = Location;
}
@ -686,7 +685,7 @@ private void MainForm_LocationChanged(object sender, EventArgs e)
private void MainForm_SizeChanged(object sender, EventArgs e)
{
if (ReadyWaitHandle.WaitOne(0) && WindowState == FormWindowState.Normal)
if (IsReady && WindowState == FormWindowState.Normal)
{
Program.Settings.MainFormSize = Size;
}

View file

@ -24,16 +24,14 @@
#endregion License Information (GPL v3)
using HelpersLib;
using Microsoft.VisualBasic.ApplicationServices;
using SingleInstanceApplication;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using UploadersLib;
@ -231,6 +229,7 @@ public static string Title
}
public static string[] Arguments { get; private set; }
public static bool IsMultiInstance { get; private set; }
public static bool IsPortable { get; private set; }
public static bool IsSilentRun { get; private set; }
public static bool IsSandbox { get; private set; }
@ -249,8 +248,6 @@ public static string Title
public static HotkeyManager HotkeyManager { get; set; }
public static WatchFolderManager WatchFolderManager { get; set; }
private static ShareXApplicationBase applicationBase;
[STAThread]
private static void Main(string[] args)
{
@ -263,24 +260,15 @@ private static void Main(string[] args)
if (CheckAdminTasks()) return; // If ShareX opened just for be able to execute task as Admin
bool forceMultiInstance = CLIHelper.CheckArgs(Arguments, "multi", "m");
IsMultiInstance = CLIHelper.CheckArgs(Arguments, "multi", "m");
Application.SetCompatibleTextRenderingDefault(false);
applicationBase = new ShareXApplicationBase(!forceMultiInstance);
applicationBase.Startup += StartupHandler;
applicationBase.StartupNextInstance += StartupNextInstanceHandler;
applicationBase.Shutdown += ShutdownHandler;
try
if (IsMultiInstance || ApplicationInstanceManager.CreateSingleInstance(SingleInstanceCallback, Arguments))
{
applicationBase.Run(Arguments);
}
catch (CantStartSingleInstanceException)
{
MessageBox.Show("Couldn't launch the application.");
Run();
}
}
private static void StartupHandler(object sender, StartupEventArgs e)
private static void Run()
{
string appGuid = ((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), false).GetValue(0)).Value.ToString();
@ -308,6 +296,9 @@ private static void StartupHandler(object sender, StartupEventArgs e)
}
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
DebugHelper.WriteLine("{0} started", Title);
DebugHelper.WriteLine("Operating system: " + Environment.OSVersion.VersionString);
DebugHelper.WriteLine("Command line: " + Environment.CommandLine);
@ -326,75 +317,24 @@ private static void StartupHandler(object sender, StartupEventArgs e)
DebugHelper.WriteLine("MainForm init started");
MainForm = new MainForm();
applicationBase.MainForm = MainForm;
DebugHelper.WriteLine("MainForm init finished");
if (Settings == null)
{
SettingsResetEvent.WaitOne();
}
Application.Run(MainForm);
if (WatchFolderManager != null) WatchFolderManager.Dispose();
SaveSettings();
BackupSettings();
DebugHelper.WriteLine("ShareX closing");
DebugHelper.Logger.SaveLog(LogsFilePath);
}
}
private static void StartupNextInstanceHandler(object sender, StartupNextInstanceEventArgs e)
{
e.BringToForeground = false;
string[] args = e.CommandLine.ToArray();
if (MainForm.ReadyWaitHandle.WaitOne(0))
{
DoStartupNextInstance(args);
}
else
{
TaskEx.Run(() => WaitFormLoad(args));
}
}
private static void WaitFormLoad(string[] args)
{
try
{
if (MainForm.ReadyWaitHandle.WaitOne(5000))
{
MainForm.InvokeSafe(() => DoStartupNextInstance(args));
}
}
catch { }
}
private static void DoStartupNextInstance(string[] args)
{
if (args == null || args.Length == 0)
{
if (MainForm.niTray != null && MainForm.niTray.Visible)
{
// Workaround for Windows startup tray icon bug
MainForm.niTray.Visible = false;
MainForm.niTray.Visible = true;
}
MainForm.ShowActivate();
}
else if (MainForm.Visible)
{
MainForm.ShowActivate();
}
MainForm.UseCommandLineArgs(args);
}
private static void ShutdownHandler(object sender, EventArgs e)
{
if (WatchFolderManager != null) WatchFolderManager.Dispose();
SaveSettings();
BackupSettings();
DebugHelper.WriteLine("ShareX closing");
DebugHelper.Logger.SaveLog(LogsFilePath);
}
public static void LoadSettings()
{
LoadProgramSettings();
@ -500,7 +440,7 @@ private static void Application_ThreadException(object sender, ThreadExceptionEv
OnError(e.Exception);
}
private static void CurrentDomain_UnhandledException(object sender, System.UnhandledExceptionEventArgs e)
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
OnError((Exception)e.ExceptionObject);
}
@ -513,6 +453,49 @@ private static void OnError(Exception e)
}
}
private static void SingleInstanceCallback(object sender, InstanceCallbackEventArgs args)
{
if (WaitFormLoad(5000))
{
Action d = () =>
{
if (args.CommandLineArgs == null || args.CommandLineArgs.Length < 1)
{
if (MainForm.niTray != null && MainForm.niTray.Visible)
{
// Workaround for Windows startup tray icon bug
MainForm.niTray.Visible = false;
MainForm.niTray.Visible = true;
}
MainForm.ShowActivate();
}
else if (MainForm.Visible)
{
MainForm.ShowActivate();
}
MainForm.UseCommandLineArgs(args.CommandLineArgs);
};
MainForm.InvokeSafe(d);
}
}
private static bool WaitFormLoad(int wait)
{
Stopwatch timer = Stopwatch.StartNew();
while (timer.ElapsedMilliseconds < wait)
{
if (MainForm != null && MainForm.IsReady) return true;
Thread.Sleep(10);
}
return false;
}
public static void ConfigureUploadersConfigWatcher()
{
if (Program.Settings.DetectUploaderConfigFileChanges && uploaderConfigWatcher == null)

View file

@ -228,7 +228,6 @@
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="ShareXApplicationBase.cs" />
<Compile Include="TaskHelpers.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />