Interprocess Communications

I have been interested for a long time how to do so that the one instance was running only. I mean I have known in theory with the help of what it should be done, but I haven’t tried yet..Another very interesting thing is how to do as for instance I open an Excel spreadsheet and it does not open in another application, but the fact that is already open. This course enrages sometimes, but still technology is interesting.

The rustling in the Internet has brought to what is called Interprocess Communication (IPC) and there are many ways how to implement it, depending on the ultimate goal, whether you have only one instance, or as in Excel, or something else. Further study of the issue and gave birth to this article.

The theory

Windows OS provides opportunities for fellowship programs and use of shared data between applications. In the most general case, this results in a client-server circuit, with one application acts as a server and a client. To address the issue of what type of communication to choose, you can ask yourself the following questions to help in choosing:

  • o Whether the application will interact with other applications on the network or only on your computer.
  • Will the application interact with applications written for other operating systems.
  • Should the application itself to determine with whom to interact, or choose to place on the user.
  • Will there be cooperation on the principle of copy-paste from other applications orinteraction will be severely limited in action.
  • How critical is performance.
  • Will the laying of a console or user interface. Some methods require the interaction ofa graphical interface.

Windows supports the following mechanisms for data exchange:

  • Clipboard
  • COM
  • Data Copy
  • DDE
  • File mapping
  • Mailslots
  • Pipes
  • RPC
  • Windows Sockets
Clipboard

Acts as a common data store. When something is copied to the clipboard, the application puts data into one or more formats. Any other application can pick them out. For example pad, and the last Word.  Clipboard.

COM

This application support model OLE – compound documents. The basis of OLE is a component object model (COM). Application that uses this technology can interact with a lot of applications, even those that are yet to be written. With this model you can run other applications, for which data do you have.

Data Copy

The application can send a message with a marker WM_COPYDATA. This requires cooperation throughout between the sending and the receiving side, based on the Windows Messaging.  Data Copy.

DDE

Dynamic Data Exchange – can be presented as an extension of the mechanism of the clipboard. It can be used for network and local communication. Dynamic Data Exchange and Dynamic Data Exchange Management Library.  Dynamic Data Exchange и Dynamic Data Exchange Management Library.

File Mapping

Through this process, you can submit the file contents as a memory in the address segment of the process. The process can use a simple pointer to a file. If two applications are looking at one and the same file, you can modify the data by one application that another then gets an update. This is a very efficient mechanism that supports security at the OS level. Works locally and to provide synchronization between processes. File Mapping и Synchronization.

Mailslot

Provides a one-sided way of communication, there is a server and client messages go only from the client. But nothing prevents to make a server on the two sides. Supported by the communication network, and broadcast messages can be done, but no more than 400 bytes.  Mailslots.

Pipes

There are two types – anonymous pipes and named pipes. Anonymous pipes can communicate related processes. For full-duplex communication is required to create two channels. Named pipes can be used for network communication between unrelated processes.  Pipes.

RPC

Remote Process Call – allows you to remotely manage the application both locally and across the network. This method is compatible with the Open Software Foundation (OSF) Distributed Computing Environment (DCE) that makes it possible to exchange messages with other operating systems. Supports automatic data conversion for different platforms. Client and server are connected very weakly, but still show the high efficiency at work. Microsoft RPC Components

Windows Sockets

This is independent of the protocol data interface. You can exchange messages withany system that supports the implementation of this protocol. Windows Sockets 2.

Yes, being a freshman, I would not rack brains with all this zoo and slapped a code to create and delete a file in the root folder of the program. And would gain application which doesn’t work after the first emergency shutdown of the program! =D

The aim

On the local computer to be able to send the arguments a second instance of the program first. That is implementing any functional program that opens a document in one of his window. For example, it can be Excell, Notepad + +, WinAmp.

Reach the goal we will with named pipes and RPC. In a specific implementation, this will make the WCF Named Pipes and Mutex for RPC. Two methods for comparing the implementation. Looking ahead to say that I like WCF is much more. Easier to code and its smaller.

In pursuit of the goal, we will have two primary objectives:

  1. Determine whether there is already an instance of the program in memory;
  2. If you run a second instance, his arguments to pass in the first instance.

Preparation

In both implementations will be on two projects for a better separation of functionality. One WinForms, which will check and data processing. The second project in fact with the necessary functionality.

Mutex approach

The first method is based on the use of RPC. To create the solution we need some design and visual components (WinForm, WPF) and a class library.

To solve the problem number one will use a mutex.

When two or more threads simultaneously need to access a shared resource, the system needs a synchronization mechanism to ensure the use of the resource only one thread at a time. Mutex – primitive, which provides exclusive access to a shared resource to only one stream synchronization. if thread gets the semaphore, the second thread, wishes to obtain the semaphore, suspended until such time until the first thread releases the semaphore.

A named mutex in the system can be only one, and on this name, you can find it .Accordingly, immediately comes the idea that the existence check it in the system will tell us whether there is a system already running instance of the application.

Let’s start with a basic class that will create mutexes.

public class SingleInstanceTracker : Idisposable {
    private bool disposed;
    private Mutex singleInstanceMutex;
    private bool isFirstInstance;

    public SingleInstanceTracker(string name){
        if (string.IsNullOrEmpty(name))
            throw new ArgumentNullException("name", "name cannot be null or empty.");
        try {
            singleInstanceMutex = new Mutex(true, name, out isFirstInstance);
        }
       catch (Exception ex) {
           throw new SingleInstancingException("Failed to instantiate a new SingleInstanceTracker object", ex);
       }
    }

    ~SingleInstanceTracker() {
       Dispose(false);
    }

    protected virtual void Dispose(bool disposing) {
        if (!disposed) {
          if (disposing) {
            if (singleInstanceMutex != null) {
              singleInstanceMutex.Close();
              singleInstanceMutex = null;
            }
          }
         disposed = true;
       }
    }

    public void Dispose() {
        Dispose(true);
       GC.SuppressFinalize(this);
    }

    public bool IsFirstInstance {
        get { return isFirstInstance;  }
    }
}

Creating the mutex limited to one line.

singleInstanceMutex = new Mutex(true, name, out isFirstInstance);

The same line of code and tell us this is the only instance or not. Well, the first point of the program is made super-fast. But it does not have moved the problem to transfer data from one instance to another.

For data transfer we use a special namespace System.Runtime.Remoting.Channels.Ipc. It defines a class IpcServerChannel by means of which will go to data transfer.

The data transmitted over this channel to be inheriting from the class MarshalByRefObject, so they can remotely create, and to enable them to travel outside the application domain. Data must also be serializable. Yet it would be nice to define a delegate that will perform the methods in the first application, but run from second. Thus, the proxy class

internal class SingleInstanceProxy : MarshalByRefObject {
    private readonly ISingleInstanceEnforcer enforcer;

    public SingleInstanceProxy(ISingleInstanceEnforcer enforcer) {
        if (enforcer == null)
            throw new ArgumentNullException("enforcer", "enforcer cannot be null.");

       this.enforcer = enforcer;
    }

    public override object InitializeLifetimeService() {
       return null;
    }

    public ISingleInstanceEnforcer Enforcer {
       get { return enforcer; }
    }
}

public delegate ISingleInstanceEnforcer SingleInstanceEnforcerRetriever();

public interface ISingleInstanceEnforcer {
    void OnMessageReceived(MessageEventArgs e);
    void OnNewInstanceCreated(EventArgs e);
}

Create and register a channel is as follows:

Var ipcChannel = new IpcServerChannel(name);
ChannelServices.RegisterChannel(ipcChannel, false);

Where the name - the name of the channel.

The algorithm works with the channels, after creating the mutex will be:

If this is the first instance, it is necessary

  • create a channel
  • register a channel
  • register the proxy type as a known type
  • create a proxy and make a link to it through the address icp

If we have a second instance, then

  • create a channel
  • register a channel
    • obtain a proxy from the first instance
    • send data through a proxy
const string proxyObjectName = "WBRSingleInstanceProxy";
var proxyUri = "ipc://" + name + "/" + proxyObjectName;

if (isFirstInstance) {
    ipcChannel = new IpcServerChannel(name);
    ChannelServices.RegisterChannel(ipcChannel, false);

    RemotingConfiguration.RegisterWellKnownServiceType(typeof (SingleInstanceProxy), proxyObjectName,WellKnownObjectMode.Singleton);

    var enforcer = enforcerRetriever();

    if (enforcer == null)
       throw new InvalidOperationException("The method must return an ISingleInstanceEnforcer object.");

    proxy = new SingleInstanceProxy(enforcer);
    RemotingServices.Marshal(proxy, proxyObjectName);
}
else {
    ipcChannel = new IpcClientChannel();
    ChannelServices.RegisterChannel(ipcChannel, false);

    proxy = (SingleInstanceProxy) Activator.GetObject(typeof (SingleInstanceProxy), proxyUri);

    proxy.Enforcer.OnNewInstanceCreated(new EventArgs());
}
Transmission and message processing

Determine the uniqueness and originality of the program in memory will run at, so in Program.cs.

private static void Main(params string[] args) {
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    SingleInstanceTracker tracker = null;
    try {
       tracker = new SingleInstanceTracker("SingleInstanceSample", GetSingleInstanceEnforcer);
       if (tracker.IsFirstInstance)
          Application.Run((MainForm) tracker.Enforcer);
       else
          tracker.SendMessageToFirstInstance(args);
    }
    catch (SingleInstancingException ex) {
        MessageBox.Show("Could not create a SingleInstanceTracker object:\n" + ex.Message + "\nApplication will now terminate.");
        return;
    }
   finally {
        if (tracker != null)
            tracker.Dispose();
   }
}

private static ISingleInstanceEnforcer GetSingleInstanceEnforcer() {
     return new MainForm();
}

First, try to create a tracker to determine its uniqueness. If the process is alreadyrunning previously, passing the parameters of this process using the SendMessageToFirstInstance.

Processing of this message will occur at the application form (for simplicity). The form must implement the interface ISingleInstanceEnforcer.

void ISingleInstanceEnforcer.OnMessageReceived(MessageEventArgs e) {
    OnMessageReceivedInvoker invoker = delegate(MessageEventArgs eventArgs) {
        var msg = eventArgs.Message as string[];
        if (msg == null) return;
        listBox1.Items.Clear();
        listBox1.Items.AddRange(msg);
    };

    if (InvokeRequired)
         Invoke(invoker, e);
    else
         invoker(e);
}

In the delegate defined actions that must be take when receiving a message. In life, there will need to use a template “command manager”, so you can pretty handle different messages.

WCF approach

The second way we favor the use of the WCF service. It will be an indicator of the primary instance and the method for sending messages. We again need the visual design and WCF library.

WCF service wrapper can work so many things and can be applied to almost any situation when you have to organize the interaction between parts of a program or between programs. That’s what Windows Communication Service, and to think about it.

To work within a single machine will be used Binding NetNamedPipeBinding. Ideally suited for our task, as a named pipe can be a very easy and there is.

We start from a distance of some semblance of Command Manager. For simplicity, all the same it will be a static class. And yes, in this case, start with the second problem, data.

public static class ActionManager {
    public static Action<string[]> ItemsAction;
}

We now make the registration of this action on the main form. Or in a more complicated case in ViewModel.

public partial class Form1 : Form {
    public Form1() {
       InitializeComponent();
       ActionManager.ItemsAction = array => {
                          listBox1.Items.Clear();
                          listBox1.Items.AddRange(array);
                       };
    }
}

ТNow for the actual implementation of the WCF service. The project is already the default template Service1, it can be freely renamed or leave as is, without any damage. I renamed it SingleInstanceService.

The service so far there is only one method that will accept a string array.

[ServiceContract]
public interface ISingleInstanceService {
    [OperationContract]
    void SomeArgs(params string[] args);
}

public class SingleInstanceService : ISingleInstanceService {
    public void SomeArgs(params string[] args) {
         ActionManager.ItemsAction(args);
    }
}

That’s the whole service. There will be no more than a single line of code! In fact, we all built to the acceptance and processing of data. Now we must learn to pass them. This functionality will be placed in Program.cs.

First will have to specify a unique name for the channel. Then, create a host for WCFservice. We can say that setting the WCF service is a fully manual mode. When you create a service specify which class is the main functionality..

var address = new Uri("net.pipe://localhost/WBRSingleInstanceService");

var serviceHost = new ServiceHost(typeof (SingleInstanceService), address);

Next, specify the binding. It will be named pipes. Here you can specify the behavior of the binding, the maximum waiting time, buffer size and stuff like that.

var binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);

var localMbehave = new ServiceMetadataBehavior();

serviceHost.Description.Behaviors.Add(localMbehave);

The next step is to create the endpoints. At the beginning of the development will create two points: one service MEX, in order to be able to configure a service reference. Another would be the end point of the service. After setting up and in the final release MEX point can be removed.

serviceHost.AddServiceEndpoint(typeof (IMetadataExchange), MetadataExchangeBindings.CreateMexNamedPipeBinding(), "mex");
serviceHost.AddServiceEndpoint(typeof (ISingleInstanceService), binding, address);

serviceHost.Open();

Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());

serviceHost.Close();

After run the service and do not forget to close it after the end of the application. Now we must create a link to the service. Run the application without debug Ctrl-F5 and add a link to the service.

Trying to drive a service address, which we have indicated in the code and click “GO”. It should look something like in the picture.

Select the namespace for the service and finish the job with this dialog box. Done!

We can now solve the first problem, the uniqueness of the service. Just try to join him by creating client-side.

var client = new SingleInstanceServiceClient("NetNamedPipeBinding_ISingleInstanceService");
client.SomeArgs(args);

If this fails, then just complete the application, if not, then create a new host. If it is not carried out the operation will be an exception of type SomeArgsEndpointNotFoundException, which clearly indicates that the host is not running.

That’s all folks!

How to verify that everything works

In the first method, all checked OK by pressing a button on the form, then creates a process and there is an exchange of information.

In the second method is not a trick when you run into laminates debug. I guess the whole reason for this is correct but it is too lazy in this example. The main thing that it works, and check it out as follows. Go to the folder bin, where the application has already been collected. Do link to an executable file and the label in the properties of Target after the path to the file write anything you want.

Run the main file, then run through the same label and see that the main application to update the data.

Conclusion

In my opinion the second method is much simpler to create and operate. In an improved version of the second method can not pass a set of arguments from the command line and have formed their own team, which will handle the primary copy. It is also the service itself is richer, all typed and transparently, that comes and where sent.

For both methods is to write a good team manager, that there is no rigid bundles with fiber interface for instance

Source code of the first example, the second example.

Hard’n’heavy!

Tagged , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>