Home Upgrade Search Memberlist Extras Hacker Tools Award Goals Help Wiki Contact

.NET 

[C#/VB] Simple instance merger class

Download: GIST

Simple code that passes the commandline arguments to an existing version of the application (if it exists).

Gif:
Spoiler (Click to View)

Example code:
Code
public static void Main(string[] args)
{
    SingleInstance.Create(OnNewInstance); //Setting up single instance of the current program

    Console.WriteLine("First instance created");
    Console.ReadLine();
}

private static void OnNewInstance(string path, string[] args)
{
    Console.WriteLine("New instance created. Path: {0}", path);
    for(int i =0; i < args.Length;i++)
        Console.WriteLine("Arg {0}: {1}", i, args[i]);
}

VB:
Code
Sub Main()
    SingleInstance.Create(AddressOf OnNewInstance)

    Console.WriteLine("First instance created")
    Console.ReadLine()
End Sub

Private Sub OnNewInstance(ByVal path As String, ByVal args As String())
    Console.WriteLine("New instance created. Path: {0}", path)
    For i = 0 To args.Length - 1
        Console.WriteLine("Args {0}: {1}", i, args(i))
    Next
End Sub

Todo:
-Find a better way to store port.
Lotta blood to let, peace to make, give a fuk about a check
thats a cool idea, but i can't think of a way for me to use it. mind telling me, what you made it for?
(Nov 18, 2015 02:52 AM)DisguiserNET Wrote:  thats a cool idea, but i can't think of a way for me to use it. mind telling me, what you made it for?

Associating a file type to your application (just passes the location of the associated file to the existing instance).
WebLaunched programs (like magnet links for torrents).
Lotta blood to let, peace to make, give a fuk about a check
(Nov 18, 2015 02:52 AM)DisguiserNET Wrote:  thats a cool idea, but i can't think of a way for me to use it. mind telling me, what you made it for?

This could probably be used for something like a web browser where instead of opening a new instance, it would open a new tab.
this can easy done with process class and Environment.GetCommandLineArgs
Interesting concept, although why would you use sockets instead of pipes? Wouldn't that be easier as it takes away the need for a port?

https://msdn.microsoft.com/en-us/library...10%29.aspx
https://github.com/Washi1337

"I'll tell you this UDP joke, and I don't care if you will get it or not."
(Nov 18, 2015 09:41 AM)Washi Wrote:  Interesting concept, although why would you use sockets instead of pipes? Wouldn't that be easier as it takes away the need for a port?

https://msdn.microsoft.com/en-us/library...10%29.aspx

I thought pipelines where .net 4?
I try to make my programs .Net 2.0 when it is possible, so its more compatible with other peoples projects.

(Nov 18, 2015 08:37 AM)Only3 Wrote:  this can easy done with process class and Environment.GetCommandLineArgs

Example?
Lotta blood to let, peace to make, give a fuk about a check
Code
if (Args.Length < 2) {
    Process.Start(new ProcessStartInfo(Application.ExecutablePath, "1"));
} else if (Args(1) == "1") {
// New Instance
}
(Nov 18, 2015 04:08 PM)Only3 Wrote:  
Code
if (Args.Length < 2) {
    Process.Start(new ProcessStartInfo(Application.ExecutablePath, "1"));
} else if (Args(1) == "1") {
// New Instance
}

This would not work. Did you even try it?
Lotta blood to let, peace to make, give a fuk about a check
Ported to vb. I really like this, useful as fuck.

SingleInstance.vb:
Code
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
''' uid=2388291
'''
''' Ported to VB by Tedd
''' </summary>

Public Class SingleInstance
    Public Delegate Sub MergeInstanceCallback(ByVal path As String, ByVal args As String())

    Private applicationMutex As Mutex = Nothing
    Private InstanceKey As String
    Private PortSave As RegistryKey = Nothing
    Private InstanceSocket As Socket = Nothing
    Private SocketBuffer As Byte()
    Private SenderEndpoint As EndPoint = New IPEndPoint(IPAddress.Loopback, 0)
    Private MergeInstance As MergeInstanceCallback

    Public Sub Create(ByVal callback As MergeInstanceCallback)
        Create(callback, 1048576)
    End Sub
    Public 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 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 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 Function GetCurrentInstancePort() As Integer
        Try
            applicationMutex = Mutex.OpenExisting(InstanceKey)
            If PortSave Is Nothing Then Return 0
            Return DirectCast(PortSave.GetValue(InstanceKey, 0), Integer)
        Catch ex As Exception
            Return 0
        End Try
    End Function
    Private 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


Module1.vb:
Code
Module Module1
    Dim SingleInst As SingleInstance

    Sub Main()
        SingleInst = New SingleInstance
        SingleInst.Create(AddressOf OnNewInstance)

        Console.WriteLine("First instance created")
        Console.ReadLine()
    End Sub

    Private Sub OnNewInstance(ByVal path As String, ByVal args As String())
        Console.WriteLine("New instance created. Path: {0}", path)
        For i = 0 To args.Length - 1
            Console.WriteLine("Args {0}: {1}", i, args(i))
        Next
    End Sub

End Module
[Image: 86251a37e635a21aea7eb7e014b0d820.gif]
(Nov 18, 2015 08:11 PM)Tedd Wrote:  Ported to vb. I really like this, useful as fuck.

SingleInstance.vb:
-code-


Module1.vb:
-code-

Thanks ;)
I modified it slightly to make it static and added it to the GIST.
Lotta blood to let, peace to make, give a fuk about a check
(Nov 18, 2015 04:17 PM)BahNahNah Wrote:  This would not work. Did you even try it?

This work. Did you even try it?
(Nov 19, 2015 03:56 AM)Only3 Wrote:  This work. Did you even try it?

But it never checks if there is already another process running.
Lotta blood to let, peace to make, give a fuk about a check
bahna open ur brain its easy to do it
also this way u not creating new files all in memory
tip use the power of the args to pass the info
(Nov 19, 2015 04:14 AM)Only3 Wrote:  bahna open ur brain its easy to do it
also this way u not creating new files all in memory
tip use the power of the args to pass the info

I tried it.

Spoiler (Click to View)
Lotta blood to let, peace to make, give a fuk about a check


Possibly Related Threads...
Thread / Author Replies Views Last Post
[C] by lockheadApr 22, 2021 07:10 AM 0 147 Apr 22, 2021 07:10 AM
Last Post: lockhead
[.NET] by sh@rpJul 5, 2020 07:05 AM 212 22,352 Jul 5, 2020 07:05 AM
Last Post: sh@rp
[Python] by Meelo XOMay 11, 2019 05:52 AM 0 121 May 11, 2019 05:52 AM
Last Post: Meelo XO