I made single instance app, but my problem is, I don't know how to get the first opened FormMain instance and update the form TextBox! Could you help me?
static void Main(string[] args)
{
bool result;
Mutex mutex = new System.Threading.Mutex(true, "unique_name", out result);
if (!result)
{
**/*
CALL OPENED FORM INSTANCE AND UPDATE TEXTBOX
*/**
return;
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(true);
Application.Run(new FormMain(args));
GC.KeepAlive(mutex);
}
You can use named pipeline interprocess communication like that:
Usings
using System;
using System.IO.Pipes;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;
Static variables
static public bool AllowApplicationMultipleInstances { get; private set; } = true;
static private Mutex ApplicationMutex;
static private NamedPipeServerStream IPCServer;
Application unique identifier
static public string GetGUID()
{
object[] attributes = Assembly.GetExecutingAssembly()
.GetCustomAttributes(typeof(GuidAttribute), false);
return ( (GuidAttribute)attributes[0] ).ToString();
}
Check only one instance and init the server
static private bool CheckApplicationOnlyOneInstance(AsyncCallback duplicated)
{
AllowApplicationMultipleInstances = false;
string guid = GetGUID();
ApplicationMutex = new Mutex(true, guid, out bool created);
if ( created )
CreateIPCServer(duplicated);
else
{
var client = new NamedPipeClientStream(".", guid, PipeDirection.InOut);
client.Connect();
new BinaryFormatter().Serialize(client, "BringToFront");
client.Close();
}
return created;
}
Create the server
static private void CreateIPCServer(AsyncCallback duplicated)
{
IPCServer = new NamedPipeServerStream(GetGUID(),
PipeDirection.InOut,
1,
PipeTransmissionMode.Message,
PipeOptions.Asynchronous);
IPCServer.BeginWaitForConnection(duplicated, IPCServer);
}
Anwser to a request
static private void IPCRequest(IAsyncResult ar)
{
var server = ar.AsyncState as NamedPipeServerStream;
server.EndWaitForConnection(ar);
var command = new BinaryFormatter().Deserialize(server) as string;
if ( command == "BringToFront" )
{
Console.WriteLine(command);
//MainForm.Instance.SyncUI(() => MainForm.Instance.MenuShowHide_Click(null, null));
}
server.Close();
CreateIPCServer(IPCRequest);
}
Test
static private void Test()
{
if ( !SystemManager.CheckApplicationOnlyOneInstance(IPCRequest) )
return;
Console.ReadKey();
}
Usage
You can create as string commands as needed.
For example it allows to pass command line arguments from a process just started to the actual running process.
Also you can improve this simple behavior to have a more complex system, to use a classes framework instead of string commands.
For your application you should be able to use:
static public FormMain MainForm;
static void Main(string[] args)
{
if ( !SystemManager.CheckApplicationOnlyOneInstance(IPCRequest) )
return;
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(true);
MainForm = new FormMain(args);
Application.Run(MainForm);
}
If you modify a WinForm control you must to synchronize with the main UI thread:
How do I update the GUI from another thread?
How to access a WinForms control from another thread i.e. synchronize with the GUI thread?
Some links
Full Duplex Asynchronous Read/Write with Named Pipes (CodeProject)
Inter Process Communication (C# Vault)
WCF Comparison with Web Services and .NET Remoting (CodeProject)
Socket Programming In C# (C-SharpCorner)