mirror of
https://github.com/ShareX/ShareX.git
synced 2024-07-04 22:21:23 +12:00
The problem is that multiple context menu selections spawn multiple .exe (invoked). Each invoked .exe sets the InstanceProxy variables in the running .exe and tells it to start a thread to process. But, there is no waiting, so the InstanceProxy variables get clobbered before they can get used. This fix uses a semaphore to control the invoked .exe. There is only one entry allowed forcing invoked .exe to wait until any other invoked .exe is finished running and releases the semaphore.
130 lines
4.6 KiB
C#
130 lines
4.6 KiB
C#
#region License Information (GPL v3)
|
|
|
|
/*
|
|
ShareX - A program that allows you to take screenshots and share any file type
|
|
Copyright (c) 2007-2016 ShareX Team
|
|
|
|
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;
|
|
|
|
namespace SingleInstanceApplication
|
|
{
|
|
public static class ApplicationInstanceManager
|
|
{
|
|
private static Semaphore semaphore;
|
|
|
|
[DebuggerStepThrough]
|
|
public static bool CreateSingleInstance(string name, EventHandler<InstanceCallbackEventArgs> callback, string[] args)
|
|
{
|
|
string eventName = string.Format("{0}-{1}", Environment.MachineName, name);
|
|
string semaphoreName = string.Format("{0}{1}", eventName, "Semaphore");
|
|
|
|
InstanceProxy.IsFirstInstance = false;
|
|
InstanceProxy.CommandLineArgs = args;
|
|
|
|
try
|
|
{
|
|
using (EventWaitHandle eventWaitHandle = EventWaitHandle.OpenExisting(eventName))
|
|
{
|
|
semaphore = Semaphore.OpenExisting(semaphoreName);
|
|
semaphore.WaitOne();
|
|
UpdateRemoteObject(name);
|
|
|
|
if (eventWaitHandle != null) eventWaitHandle.Set();
|
|
|
|
semaphore.Release();
|
|
}
|
|
|
|
Environment.Exit(0);
|
|
}
|
|
catch
|
|
{
|
|
InstanceProxy.IsFirstInstance = true;
|
|
|
|
using (EventWaitHandle eventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset, eventName))
|
|
{
|
|
semaphore = new Semaphore(1, 1, semaphoreName);
|
|
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("ShareX", 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);
|
|
semaphore.Close();
|
|
};
|
|
}
|
|
|
|
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));
|
|
}
|
|
}
|
|
} |