• 0

[C#] Interprocess Communication


Question

Basically, I need some way to share something (a full object if I can get away with it) between two applications on the same system. I've done the Google search, and found these:

1. Remoting -- I've found it extremely unreliable with objects that need to persist for more than a few minutes (yes I'm aware that you can respond to a callback to keep an object alive. That part is very reliable -- it reliably doesn't work). Also very slow for large objects

2. Shared Memory -- Doing this in C# requires a lot of de/serialization, which makes it incredibly slow and memory-intensive when large objects are involved; solving that would require rewriting my stuff in C++.

3. ".shared" sections -- ditto on the rewriting, and it's a security problem anyway

4. Named Pipes -- Better for passing bits of information around, not so good for sharing something more concrete

5. WM_COPYDATA -- ditto

Okay, so does anyone know of a reliable, fast way to share something cross-process in C#? I'll rewrite for C++ if I absolutely have to, but that's a rather drastic step I'd rather not take.

Basically what I'm looking for here is something similar to a COM server setup, but without the COM. Or maybe with the COM, if that's achievable through some .NET CCW magic.

Link to comment
Share on other sites

12 answers to this question

Recommended Posts

  • 0

Actually, anything that travels outside your local heap will suffer of serialization. Whether you do it manually or some component does it (remoting, Indigo, etc)

Link to comment
Share on other sites

  • 0

I had good success with Remoting using binary formatter and TCPChannel.

The application used singleton activated objects. With one process hosted by IIS

and the other process a Windows Application using the Server version of the Garbage Collector.

I have passed upto 1 MB objects back and forth in my application.

I don't see any perf degradation. Serialization impact was negligible.

Link to comment
Share on other sites

  • 0

well then set up a webservice on the machines then! The webservices talk to each other, the object is serialized, sent to the other server, it is unserialized, and wham! You're in business

Link to comment
Share on other sites

  • 0

I've always used WM_COPYDATA. I can't see any point in creating a web service to exchange data on the same machine.

Link to comment
Share on other sites

  • 0
I have passed upto 1 MB objects back and forth in my application.

I don't see any perf degradation. Serialization impact was negligible.

I'm thinking larger than that. And it's not just the size of the object that poses a problem, but what it contains. The object I'm looking to share cross-process contains a few hundred smaller objects, each of which contains 10-15 even smaller objects. The whole thing is about 5MB (when serialized) which is not such a problem. But the object could theoretically be several times larger, and because so many objects need to be created in memory when the whole thing is deserialized, there's a very noticeable lag.

Link to comment
Share on other sites

  • 0
is deserialized, there's a very noticeable lag.

In my case, GC was having a bigger impact than serialization itself.

That is until I simplified the datastructure to a struct with an array of strings.

In addition, Using the server version of the GC instead of the default made a huge impact.

Link to comment
Share on other sites

  • 0

Sockets is always a good way to do IPC. This also allows you to stay more flexible in case the two processes ever need to reside on different machines/platforms/architectures.

Link to comment
Share on other sites

  • 0
Sockets is always a good way to do IPC. This also allows you to stay more flexible in case the two processes ever need to reside on different machines/platforms/architectures.

I took a brief look into that, but never really gave it serious thought. Maybe I'll revisit it. This, of course, would require solving the serialization lag problem I'm having. That's actually solvable by having each smaller object simply keep a byte array representation of itself handy and deserializing on demand. Doable, but would require adding synchronization code (the code in question is user data-oriented, and has been stable -- and bug free -- for about six months, so I'm loathe to change it in any way unless it's absolutely necessary, or I can't find another way around this problem).

One question for you though... sockets are a network thing, so would the information have to go out over the network (even a phantom network) and come back in order to make this work? If so, is the speed that IPC is going to work dependent on the network? If that's the case, it wouldn't be a solution for computers without broadband, and even on a system with broadband, the utility of sockets for my particular application would be questionable due to the amount of data involved.

Link to comment
Share on other sites

  • 0
In my case, GC was having a bigger impact than serialization itself.

That is until I simplified the datastructure to a struct with an array of strings.

In addition, Using the server version of the GC instead of the default made a huge impact.

Yeah, I could see how that might be a problem. Though in my case, GC is not causing any lag problems. My dev system has 1GB of RAM and without intervention, even the largest (30MB serialized) object bumps app memory usage up to only about 100MB.

Link to comment
Share on other sites

  • 0
One question for you though... sockets are a network thing, so would the information have to go out over the network (even a phantom network) and come back in order to make this work?

They wouldnt have to go over any network. The only overhead you would have is the TCP stack which is very fast. The delay in object synchronization would be minimal.

Link to comment
Share on other sites

  • 0

There is a intact sample from www.csdn.net(the Most popular website for developer in China)

app1:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;

public class Form1 : System.Windows.Forms.Form {
 private System.Windows.Forms.Button button1;
 private System.Windows.Forms.TextBox textBox1;

 private System.ComponentModel.Container components = null;

 [STAThread]
 static void Main() {
  Application.Run(new Form1());
 }

 public Form1()
 {
  InitializeComponent();
 }
 protected override void Dispose( bool disposing )
 {
  if( disposing )
  {
   if(components != null)
   {
    components.Dispose();
   }
  }
  base.Dispose( disposing );
 }

 #region Windows 窗体设计器生成的代码
 private void InitializeComponent()
 {
  this.button1 = new System.Windows.Forms.Button();
  this.textBox1 = new System.Windows.Forms.TextBox();
  this.SuspendLayout();
  // 
  // button1
  // 
  this.button1.Location = new System.Drawing.Point(32, 24);
  this.button1.Name = "button1";
  this.button1.TabIndex = 0;
  this.button1.Text = "button1";
  this.button1.Click += new System.EventHandler(this.button1_Click);
  // 
  // textBox1
  // 
  this.textBox1.Location = new System.Drawing.Point(32, 64);
  this.textBox1.Name = "textBox1";
  this.textBox1.TabIndex = 1;
  this.textBox1.Text = "textBox1";
  // 
  // Form1
  // 
  this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
  this.ClientSize = new System.Drawing.Size(292, 266);
  this.Controls.Add(this.textBox1);
  this.Controls.Add(this.button1);
  this.Name = "Form1";
  this.Text = "Form1";  
  this.ResumeLayout(false);

 }
 #endregion

 private void button1_Click(object sender, System.EventArgs e) {
  MessageBox.Show("This is button1 click!");
 }
}

app2

using System;
using System.Text;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Runtime.InteropServices; 

public class TestForm1 : System.Windows.Forms.Form {
 private System.Windows.Forms.Button button1;
 private System.Windows.Forms.Button button2;

 private System.ComponentModel.Container components = null;

 [STAThread]
 static void Main() {
  Application.Run(new TestForm1());
 }

 public TestForm1()
 {
  InitializeComponent();
 }
 protected override void Dispose( bool disposing )
 {
  if( disposing )
  {
   if(components != null)
   {
    components.Dispose();
   }
  }
  base.Dispose( disposing );
 }

 #region Windows 窗体设计器生成的代码
 private void InitializeComponent()
 {
  this.button1 = new System.Windows.Forms.Button();
  this.button2 = new System.Windows.Forms.Button();
  this.SuspendLayout();
  // 
  // button1
  // 
  this.button1.Location = new System.Drawing.Point(32, 24);
  this.button1.Name = "button1";
  this.button1.TabIndex = 0;
  this.button1.Text = "button1";
  this.button1.Click += new System.EventHandler(this.button1_Click);
  // 
  // button2
  // 
  this.button2.Location = new System.Drawing.Point(32, 64);
  this.button2.Name = "button2";
  this.button2.TabIndex = 0;
  this.button2.Text = "button2";
  this.button2.Click += new System.EventHandler(this.button2_Click);
  // 
  // TestForm1
  // 
  this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
  this.ClientSize = new System.Drawing.Size(292, 266);
  this.Controls.Add(this.button1);
  this.Controls.Add(this.button2);  
  this.Name = "TestForm1";
  this.Text = "TestForm1";  
  this.ResumeLayout(false);

 }
 #endregion

 private void button1_Click(object sender, System.EventArgs e) {
  IntPtr hwnd_win;   
  IntPtr hwnd_button;

  hwnd_win = FindWindow("WindowsForms10.Window.8.app3","Form1");
  hwnd_button = FindWindowEx(hwnd_win ,new IntPtr(0) ,"WindowsForms10.BUTTON.app3","button1");  

  const int BM_CLICK = 0x00F5;
  Message msg = Message.Create(hwnd_button ,BM_CLICK ,new IntPtr(0),new IntPtr(0));
  PostMessage(msg.HWnd ,msg.Msg ,msg.WParam ,msg.LParam); 
 }
 private void button2_Click(object sender, System.EventArgs e) {
  const int WM_CHAR = 0x0102;
  IntPtr hwnd_win;
  IntPtr hwnd_textbox;

  hwnd_win = FindWindow("WindowsForms10.Window.8.app3","Form1");   
  hwnd_textbox = FindWindowEx(hwnd_win ,new IntPtr(0) ,"WindowsForms10.EDIT.app3","textBox1");     
  
  string strtext = "测试aaa";
  UnicodeEncoding encode = new UnicodeEncoding();
  char[] chars = encode.GetChars(encode.GetBytes(strtext));
  Message msg;
  foreach (char c in chars ) {
   msg = Message.Create(hwnd_textbox ,WM_CHAR ,new IntPtr(c),new IntPtr(0));
   PostMessage(msg.HWnd ,msg.Msg ,msg.WParam ,msg.LParam); 
  }
 }

 [DllImport("user32.dll")]
 public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

 [DllImport("user32.dll")]
 public static extern IntPtr FindWindowEx(IntPtr hwndParent,IntPtr hwndChildAfter,string lpszClass,string lpszWindow);

 [DllImport("user32.dll",CharSet=CharSet.Unicode)]  
 public static extern IntPtr PostMessage(IntPtr hwnd,int wMsg,IntPtr wParam,IntPtr lParam);
}

These might can help you.

Link to comment
Share on other sites

  • 0

Thanks for that. But no, that's not a help. Windows messaging is not what I'm looking for, for two reasons: First, a Windows message can't contain an object; it's just a number. If this were C++, I could pass a pointer, but it's C#, so that doesn't help. And second, this needs to work even when one (or both) applications do not have a window to post messages to.

Thanks anyway though.

Link to comment
Share on other sites

This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.