Opening a "Known File Type" into Running Instance of Custom App - .Net

Opening a known file type into running instance of custom app - .NET

What you want to do is inherit a class from WindowsFormsApplicationBase, setting the protected IsSingleInstance property to true:

// This should all be refactored to make it less tightly-coupled, obviously.
class MyWindowsApplicationBase : WindowsFormsApplicationBase
{
internal MyWindowsApplicationBase() : base()
{
// This is a single instance application.
this.IsSingleInstance = true;

// Set to the instance of your form to run.
this.MainForm = new MyForm();
}
}

The Main method of your app then looks like this:

// This should all be refactored to make it less tightly-coupled, obviously.
public static void Main(string args[])
{
// Process the args.
<process args here>

// Create the application base.
MyWindowsApplicationBase appBase = new MyWindowsApplicationBase();

// <1> Set the StartupNextInstance event handler.
appBase.StartupNextInstance = <event handler code>;

// Show the main form of the app.
appBase.Run(args);
}

Note the section marked <1>. You set this up with an event handler for the StartupNextInstanceEvent. This event is fired when the next instance of your app is fired when you have a single instance application (which you specified in the constructor of MyWindowsApplicationBase). The event handler will pass an EventArgs-derived class which will have the command line arguments which you can then process in the running instance of your app.

Then, all you have to do is set the file associations normally for the file types you want your app to process, and you are set.

Open file in the currently running instance of my program?

If you look at what is registered for for .cs file in registry you will see that it is not the Visual Studio. For Express edition e.g. the registered application is 'VCSExpress.exe' and the studio is running in in 'WDExpress.exe'. In advanced versions I think the studio runs as 'devenv.exe'. The interesting point is that there are two applications: your UI application and a kind of launcher application. I don't know how VS does it, but I could imagine this way: launcher communicates with UI by any kind of interprocess communication e.g. named pipes. (See here) Maybe try this:

  • Launcher application (your file extension is registered with it) tries to open a pipe to UI application as client.
  • If it fails, it starts a new instance of UI application and passes file name as parameter. UI application start server side of named pipe
  • If pipe is opened successful i.e. there is already running a UI instance, launcher sends file name to existing UI process via pipe.
  • Launcher exits after passing the job to UI

How do I maximize an application first instance when trying to start a new one

This isn't the way you want to handle multiple instances of the application. The accepted practice is to just switch to the running instance of the application.

That being said, you can easily create a class that derives from WindowsFormsApplicationBase (in the Microsoft.VisualBasic namespace). This answer outlines how you would do it, and indicate that you want a single instance, as well as how to handle what happens when you try and run a new instance:

Opening a "known file type" into running instance of custom app - .NET

Pass commands to .NET GUI from external editor

Yes, this is the same as having a single instance of an application responding to the launch of an associated file type.

See Opening a "known file type" into running instance of custom app - .NET or search here for WindowsFormsApplicationBase which is what handles the wiring up of instances for you.

How do I automate the opening of a file from Windows Explorer programmatically

You probably know, that associating a double click with LAUNCHING an application is relatively easy. If not, here is a good SO answer.

The problem is, you don't want to LAUNCH a new application, rather raise an event in an existing one. Well, I don't know if there is a direct way for that, but you could write a small console executable, associate THAT with the file type, and in that application fire off a call to your main one (I'm thinking WCF Named Pipes would be the easiest to use), and at startup of your main application start listening to the pipe. If a message comes in (containing the path of the file, most likely), raise the internal Open event of your application, with whatever information passed as parameter.

Hope this helps.

How to update a WinForms control of a running application when another instance of this executable program is launched?

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

PipeStream

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)

Socket Programming in C# (GeeksForGeeks)

Simple Client-server Interactions using C# (CodeProject)



Related Topics



Leave a reply



Submit