Hack Forums
[.NET] [C#/VB] Simple instance merger class - Printable Version

+- Hack Forums (https://hackforums.net)
+-- Forum: Tech (https://hackforums.net/forumdisplay.php?fid=444)
+--- Forum: Coding (https://hackforums.net/forumdisplay.php?fid=151)
+---- Forum: Software Development (https://hackforums.net/forumdisplay.php?fid=118)
+---- Thread: [.NET] [C#/VB] Simple instance merger class (/showthread.php?tid=5062053)

Pages: Pages 1 2


[C#/VB] Simple instance merger class - BahNahNah - Nov 18, 2015

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.


* - DisguiserNET - Nov 18, 2015

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?


* - BahNahNah - Nov 18, 2015

(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).


* - stratex - Nov 18, 2015

(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.


* - Only3 - Nov 18, 2015

this can easy done with process class and Environment.GetCommandLineArgs


* - Washi - Nov 18, 2015

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/bb546102%28v=vs.110%29.aspx


* - BahNahNah - Nov 18, 2015

(Nov 18, 2015 09:41 AM)TheUnknownProgrammer 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/bb546102%28v=vs.110%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?


* - Only3 - Nov 18, 2015

Code
if (Args.Length < 2) {
    Process.Start(new ProcessStartInfo(Application.ExecutablePath, "1"));
} else if (Args(1) == "1") {
// New Instance
}



* - BahNahNah - Nov 18, 2015

(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?


* - Tedd - Nov 18, 2015

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



* - BahNahNah - Nov 18, 2015

(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.


* - Only3 - Nov 19, 2015

(Nov 18, 2015 04:17 PM)BahNahNah Wrote:  This would not work. Did you even try it?

This work. Did you even try it?


* - BahNahNah - Nov 19, 2015

(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.


* - Only3 - Nov 19, 2015

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


* - BahNahNah - Nov 19, 2015

(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)