What’s the best Way for 2 Processes to Communicate in .Net?

While trawling the internet the other day, I came across this question, and thought it might be something that others might like to know.  The question was:

What’s the best (or maybe not the best — just good) way for two processes in the same machine to communicate, using .NET?

Actually the two processes in the app I’m working on aren’t even two different programs; they’re just two instances of the same EXE. I wanted to do something like a singleton app, but have it per user (meaning a Terminal Server or Citrix or App-V server with multiple users should be able to launch their own single copy of the app). If another instance is run by the same user, it should just delegate the task to the already running instance, then exit. Only one instance per user of the program should be running. So far I’ve done (thanks to StackOverflow) the part that detects whether an instance of the app is already running, using Mutex. But I need the second app instance to be able to send data to the first app instance.

I’m leaning towards using named pipes and WCF’s NetNamedPipeBinding for this, but if you have better ideas I’ll really appreciate it. Thanks 🙂

IPC is what I’ve used in the past for this. And it is supprisingly easy. .Net remoting is a good option but unfortunately it is a restricted option becasue you can’t for example use it on the CF.

Below is a copy of the class I use to perform Inter-process Communication, you can use it in conjuction with a MutEx if you wish, but it isnt necessary. As long as the “pMappedMemoryName” and “pNamedEventName” are the same in both processes, it should work just fine. I tried to make it as event driven as possible.

The class looks a little like this:

  public class IpcService {
    private IServiceContext mContext;
    const int maxLength = 1024;
    private Thread listenerThread;
    private readonly string mMappedMemoryName;
    private readonly string mNamedEventName;
    public event EventHandler IpcEvent;
    private readonly bool mPersistantListener;

    public IpcService(bool pPersistantListener)
      : this(pPersistantListener, "IpcData", "IpcSystemEvent") {
      ;
    }

    public IpcService(bool pPersistantListener, string pMappedMemoryName, string pNamedEventName) {
      mPersistantListener = pPersistantListener;
      mMappedMemoryName = pMappedMemoryName;
      mNamedEventName = pNamedEventName;
    }

    public void Init(IServiceContext pContext) {
      mContext = pContext;
      listenerThread = new Thread(new ThreadStart(listenUsingNamedEventsAndMemoryMappedFiles));
      listenerThread.IsBackground = !mPersistantListener;
      listenerThread.Start();
    }

    private void listenUsingNamedEventsAndMemoryMappedFiles() {
      IntPtr hWnd = EventsManagement.CreateEvent(true, false, mNamedEventName);
      while (listenerThread != null) {
        if (Event.WAITOBJECT == EventsManagement.WaitForSingleObject(hWnd, 1000)) {
          string data = Peek();
          EventsManagement.ResetEvent(hWnd);
          EventHandler handler = IpcEvent;
          if (handler != null) handler(this, new TextualEventArgs(data));
        }
      }
      EventsManagement.SetEvent(hWnd);
      Thread.Sleep(500);
      HandleManagement.CloseHandle(hWnd);
    }

    public void Poke(string format, params object[] args) {
      Poke(string.Format(format, args));
    }

    public void Poke(string somedata) {
      using (MemoryMappedFileStream fs = new MemoryMappedFileStream(mMappedMemoryName, maxLength, MemoryProtection.PageReadWrite)) {
        fs.MapViewToProcessMemory(0, maxLength);
        fs.Write(Encoding.ASCII.GetBytes(somedata + "\0"), 0, somedata.Length + 1);
      }
      IntPtr hWnd = EventsManagement.CreateEvent(true, false, mNamedEventName);
      EventsManagement.SetEvent(hWnd);
      Thread.Sleep(500);
      HandleManagement.CloseHandle(hWnd);
    }

    public string Peek() {
      byte[] buffer;
      using (MemoryMappedFileStream fs = new MemoryMappedFileStream(mMappedMemoryName, maxLength, MemoryProtection.PageReadWrite)) {
        fs.MapViewToProcessMemory(0, maxLength);
        buffer = new byte[maxLength];
        fs.Read(buffer, 0, buffer.Length);
      }
      string readdata = Encoding.ASCII.GetString(buffer, 0, buffer.Length);
      return readdata.Substring(0, readdata.IndexOf('\0'));
    }

    private bool mDisposed = false;

    public void Dispose() {
      if (!mDisposed) {
        mDisposed = true;
        if (listenerThread != null) {
          listenerThread.Abort();
          listenerThread = null;
        }
      }
    }

    ~IpcService() {
      Dispose();
    }

  }

Simply use the Poke method to write data, and the Peek method to read it, although I designed it to automatically fire an event when new data is available. In this way you can simply subscribe to the IpcEvent event and not have to worry about expensive and constant polls.  Enjoy.

Gloves

So I got my bike fixed today – After the big bang recently eliminated my front wheel. The guy at the bike store was really cool. So after he informed be that the correct pressure was 50 psi, he fixed my wheel, checked the pressure of the rear wheel and sold me a pair of these bad boys:

Simple Solution to Illegal Cross-thread Calls in C#

If the thread call is “illegal” (i.e. the call affects controls that were not created in the thread it is being called from) then you need to create a delegate so that even if the decision / preparation for the change is not done in the control-creating thread, any resultant modification of them will be. Basically, this is a long winded way of saying you can’t (and shouldn’t) access controls on a form from a thread that didn’t create the control in the first place.

.Net version older than 2.0 (1.0 and 1.1) would actually allow this to happen, but cross-threaded operations should always be dealt with cautiously and properly. The technical solution to the problem is to create a delegate function, and pass the delegate function to the Invoke() method on the control, which allows code to execute as if it was being executed from the control’s parent thread, but if you need to do this a lot, all the extra functions and delegates can make the code unreadable, if a lot of it is going on. Fortunately there are 2 “cheats” to the problem. The first is to use the ThreadStart delegate (System.Threading namespace), since its already setup as a simple delegate with one parameter. The second, is to use anonymous delegates, which is something I have covered in the past.

if (label1.InvokeRequired) {
  label1.Invoke(
    new ThreadStart(delegate {
      label1.Text = "some text changed from some thread";
    }));
} else {
  label1.Text = "some text changed from the form's thread";
}

Now, the more curious and perceptive of you are asking, why not just use control.Invoke() everytime you change a value? Well, the truth is you could. But calling control.Invoke() has a great deal more overhead than not calling it. However, when you avoid calling control.Invoke() and access UI objects directly from the UI thread, you’re writing incorrect code that could cause stability problems in your application.

The problem is that a “window” object in the underlying Windowing API in Win32, as represented by the HWND handle, has thread-affinity. It must be directly accessed only from the thread that created it. If it’s not, the results are unpredictable and can cause subtle, intermittent bugs.

By all means skip control.Invoke() if you’ve only got one thread. However, if you need to affect a UI object from a worker thread, you absolutely must use control.Invoke() to transition back to the UI thread before making that call or you’re in for a world of pain.

Moving the Default PostgreSQL Data Directory (Windows)

PostgreSQL for Windows installs the PGDATA directory by default into “C:\<Program Files>\PostgreSQL\some version\data”.  While is usually ok for development and even some production environments, it can be somewhat limited given the typically large amount of disk activity on (what is normally) the system volume.

This step-by-step post aims to explain the fastest way to change the default PGDATA directory to another location.

Step 1:

Close all application that are currently connected to your database, then go to Windows Services Management and stop the PostgreSQL service.  Naturally, the fastest way to get to Windows Services Management is by right clicking on my computer -> manage, and then click on the services node in the computer management tree:

Once the Postgres service is stopped, leave computer the Computer Management Console open (we’ll need it again in a second).

Step 2:

Copy the “C:\<Program Files>\PostgreSQL\some version\data” directory to the new location.  In my own attempts, moves do not seem to work, but the redundant disk usage should be pretty minimal and at least you will have an old backup in the default location if something goes wrong.

Step 3 (Very Important):

Rick click on the new “data” directory, and click properties, and select the security tab.  Give the local Postgres user (or for advanced users the user account Postgres uses) and give full permission on that direct and all child objects (sometimes you need to reset the child permission inheritance).  Click ok on the properties window.

Step 4:

Open regedit.exe by clicking on the start button and typing “rededit” in either the search box, or start->run box (depending on whether your using Vista or XP) and navigate to the “HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\pgsql-some version” branch. Double click on “ImagePath” and change the directory after the “–D” option to your new location. If the path to your new location contains spaces, you should then enclose it with quotes.

Step 5:

Close regedit and go back to Computer Management and restart the Postgres service. Close Computer management.

After  completeing these steps, and assuming something hasn’t gone wrong, you should now have Postgres running from the new location.

(Reference: http://wiki.postgresql.org/wiki/Change_the_default_PGDATA_directory_on_Windows)