Skip to content

Instantly share code, notes, and snippets.

@pigeonhands
Last active December 14, 2016 05:17
Show Gist options
  • Select an option

  • Save pigeonhands/387f6bae7dcbe62ba46c to your computer and use it in GitHub Desktop.

Select an option

Save pigeonhands/387f6bae7dcbe62ba46c to your computer and use it in GitHub Desktop.
using Microsoft.Win32;
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Text;
using System.Threading;
/// <summary>
/// Application instance merger
/// Made by BahNahNah
/// </summary>
public static class SingleInstance
{
public delegate void MergeInstanceCallback(string path, string[] args);
private static Mutex applicationMutex = null;
private static string InstanceKey;
private static RegistryKey PortSave = null;
private static Socket InstanceSocket = null;
private static byte[] SocketBuffer;
private static EndPoint SenderEndpoint = new IPEndPoint(IPAddress.Loopback, 0);
private static MergeInstanceCallback MergeInstance;
public static void Create(MergeInstanceCallback callback)
{
Create(callback, 1048576);
}
public static void Create(MergeInstanceCallback callback, int bufferSize)
{
if (callback == null)
return;
MergeInstance = callback;
InstanceKey = Assembly.GetEntryAssembly().GetType().GUID.ToString();
PortSave = Registry.CurrentUser.OpenSubKey(@"AppEvents\Instances", true);
if (PortSave == null)
PortSave = Registry.CurrentUser.CreateSubKey(@"AppEvents\Instances");
if (InstanceKey == string.Empty)
throw new Exception("Invalid InstanceKey");
SocketBuffer = new byte[bufferSize];
int instancePort = GetCurrentInstancePort();
if (instancePort == 0)
CreateNewInstance();
else
MergeInstances(instancePort);
}
private static void CreateNewInstance()
{
if (applicationMutex != null)
applicationMutex.ReleaseMutex();
applicationMutex = new Mutex(true, InstanceKey);
InstanceSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
InstanceSocket.Bind(SenderEndpoint);
PortSave.SetValue(InstanceKey, ((IPEndPoint)InstanceSocket.LocalEndPoint).Port);
InstanceSocket.BeginReceiveFrom(SocketBuffer, 0, SocketBuffer.Length, SocketFlags.None, ref SenderEndpoint, DataReceived, null);
}
private static void MergeInstances(int port)
{
InstanceSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
string[] args = Environment.GetCommandLineArgs();
using (MemoryStream ms = new MemoryStream())
using (BinaryWriter bw = new BinaryWriter(ms))
{
bw.Write(args.Length);
for (int i = 0; i < args.Length; i++)
bw.Write(args[i]);
InstanceSocket.SendTo(ms.ToArray(), new IPEndPoint(IPAddress.Loopback, port));
}
Environment.Exit(0);
}
private static int GetCurrentInstancePort()
{
try
{
applicationMutex = Mutex.OpenExisting(InstanceKey);
if (PortSave == null)
return 0;
return (int)PortSave.GetValue(InstanceKey, 0);
}
catch
{
return 0;
}
}
private static void DataReceived(IAsyncResult AR)
{
int bytesRead = InstanceSocket.EndReceive(AR);
if (bytesRead == 0)
{
InstanceSocket.BeginReceiveFrom(SocketBuffer, 0, SocketBuffer.Length, SocketFlags.None, ref SenderEndpoint, DataReceived, null);
return;
}
byte[] data = new byte[bytesRead];
Buffer.BlockCopy(SocketBuffer, 0, data, 0, data.Length);
string path = string.Empty;
string[] args = null;
using (MemoryStream ms = new MemoryStream(data))
using (BinaryReader br = new BinaryReader(ms))
{
args = new string[br.ReadInt32() - 1];
path = br.ReadString();
for (int i = 0; i < args.Length; i++)
args[i] = br.ReadString();
}
MergeInstance(path, args);
InstanceSocket.BeginReceiveFrom(SocketBuffer, 0, SocketBuffer.Length, SocketFlags.None, ref SenderEndpoint, DataReceived, null);
}
}
Imports System.Threading
Imports Microsoft.Win32
Imports System.Net.Sockets
Imports System.Net
Imports System.Reflection
Imports System.IO
''' <summary>
''' Application instance merger
''' Made by BahNahNah
'''
''' Ported to VB by Tedd
''' </summary>
Public Class SingleInstance
Public Delegate Sub MergeInstanceCallback(ByVal path As String, ByVal args As String())
Private Shared applicationMutex As Mutex = Nothing
Private Shared InstanceKey As String
Private Shared PortSave As RegistryKey = Nothing
Private Shared InstanceSocket As Socket = Nothing
Private Shared SocketBuffer As Byte()
Private Shared SenderEndpoint As EndPoint = New IPEndPoint(IPAddress.Loopback, 0)
Private Shared MergeInstance As MergeInstanceCallback
Public Shared Sub Create(ByVal callback As MergeInstanceCallback)
Create(callback, 1048576)
End Sub
Public Shared Sub Create(ByVal callback As MergeInstanceCallback, ByVal bufferSize As Integer)
If callback = Nothing Then Return
MergeInstance = callback
InstanceKey = Assembly.GetEntryAssembly().GetType().GUID.ToString()
PortSave = Registry.CurrentUser.OpenSubKey("AppEvents\Instances", True)
If PortSave Is Nothing Then PortSave = Registry.CurrentUser.CreateSubKey("AppEvents\Instances")
If InstanceKey = Nothing Then Throw New Exception("Invalid InstanceKey")
ReDim SocketBuffer(bufferSize)
Dim instancePort As Integer = GetCurrentInstancePort()
If instancePort = 0 Then
CreateNewInstance()
Else
MergeInstances(instancePort)
End If
End Sub
Private Shared Sub CreateNewInstance()
If Not applicationMutex Is Nothing Then applicationMutex.ReleaseMutex()
applicationMutex = New Mutex(True, InstanceKey)
InstanceSocket = New Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)
InstanceSocket.Bind(SenderEndpoint)
PortSave.SetValue(InstanceKey, DirectCast(InstanceSocket.LocalEndPoint, IPEndPoint).Port)
InstanceSocket.BeginReceiveFrom(SocketBuffer, 0, SocketBuffer.Length, SocketFlags.None, SenderEndpoint, AddressOf DataReceived, Nothing)
End Sub
Private Shared Sub MergeInstances(ByVal port As Integer)
InstanceSocket = New Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)
Dim args As String() = Environment.GetCommandLineArgs()
Using ms As MemoryStream = New MemoryStream()
Using bw As BinaryWriter = New BinaryWriter(ms)
bw.Write(args.Length)
For i = 0 To args.Length - 1
bw.Write(args(i))
Next
InstanceSocket.SendTo(ms.ToArray, New IPEndPoint(IPAddress.Loopback, port))
End Using
End Using
Environment.Exit(0)
End Sub
Private Shared Function GetCurrentInstancePort() As Integer
Try
applicationMutex = Mutex.OpenExisting(InstanceKey)
If PortSave Is Nothing Then Return 0
Return DirectCast(PortSave.GetValue(InstanceKey, 0), Integer)
Catch
Return 0
End Try
End Function
Private Shared Sub DataReceived(ByVal AR As IAsyncResult)
Dim bytesRead As Integer = InstanceSocket.EndReceive(AR)
If bytesRead = 0 Then
InstanceSocket.BeginReceiveFrom(SocketBuffer, 0, SocketBuffer.Length, SocketFlags.None, SenderEndpoint, AddressOf DataReceived, Nothing)
Return
End If
Dim data(bytesRead) As Byte
Buffer.BlockCopy(SocketBuffer, 0, data, 0, data.Length)
Dim path As String = Nothing
Dim args() As String = Nothing
Using ms As MemoryStream = New MemoryStream(data)
Using br As BinaryReader = New BinaryReader(ms)
ReDim args(br.ReadInt32() - 1)
path = br.ReadString()
For i = 0 To args.Length - 1
args(i) = br.ReadString
Next
End Using
End Using
MergeInstance(path, args)
InstanceSocket.BeginReceiveFrom(SocketBuffer, 0, SocketBuffer.Length, SocketFlags.None, SenderEndpoint, AddressOf DataReceived, Nothing)
End Sub
End Class
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment