进程之间通讯的几种方法:
常用的方法有:
1.使用内存映射文件
2.通过共享内存DLL共享内存
3.使用SendMessage向另一进程发送WM_COPYDATA消息.
 

发送WM_COPYDATA消息

比起前两种的复杂实现来,WM_COPYDATA消息无疑是一种经济实惠的一中方法.

WM_COPYDATA消息的主要目的是允许在进程间传递只读数据。Windows在通过WM_COPYDATA消息传递期间,不提供继承同步方式。SDK文档推荐用户使用SendMessage函数,接受方在数据拷贝完成前不返回,这样发送方就不可能删除和修改数据:
这个函数的原型及其要用到的结构如下:
SendMessage(hwnd,WM_COPYDATA,wParam,lParam);
其中,WM_COPYDATA对应的十六进制数为0x004A
wParam设置为包含数据的窗口的句柄。lParam指向一个COPYDATASTRUCT的结构:
typedef struct tagCOPYDATASTRUCT{
DWORD dwData;//用户定义数据
DWORD cbData;//数据大小
PVOID lpData;//指向数据的指针
}COPYDATASTRUCT;
该结构用来定义用户数据。
具体过程如下:

const int WM_COPYDATA = 0x004A;

private void button1_Click(object sender, System.EventArgs e)
{
int WINDOW_HANDLER = FindWindow(null,@"接收方窗体");
if(WINDOW_HANDLER == 0)
{
}
else
{
byte[] sarr = System.Text.Encoding.Default.GetBytes(this.textBox1.Text);
int len = sarr.Length;
COPYDATASTRUCT cds;
cds.dwData = (IntPtr) 100;
cds.lpData = this.textBox1.Text;
cds.cbData = len + 1;
SendMessage(WINDOW_HANDLER, WM_COPYDATA, 0, ref cds);

}
}
}
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPStr)] public string lpData;
}

}

// 接收方

this.Text = "接收方窗体";

protected override void DefWndProc(ref System.Windows.Forms.Message m)
{
switch(m.Msg)
{
case WM_COPYDATA:
COPYDATASTRUCT mystr = new COPYDATASTRUCT();
Type mytype = mystr.GetType();
mystr =(COPYDATASTRUCT)m.GetLParam(mytype);
this.textBox1.Text =mystr.lpData;
break;
default:
base.DefWndProc(ref m);
break;
}
}
}
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPStr)] public string lpData;

}

共享内存

发消息实现的C#进程间的通讯,和使用共享内存的应用范围是不同的,共享内存适用于共享大量数据的情况。
本文章利用了前面的一篇.net 1.1 下实现的信号量的类,在.net 1.1 下实现,如果在.net 2.0 下实现的话就用不到我的那个信号量的类了,因为这个类在.net 2.0是提供的。

首先还是定义非托管调用,如下:

const int INVALID_HANDLE_VALUE = -1;
const int PAGE_READWRITE = 0x04;
  //共享内存
  [DllImport("Kernel32.dll",EntryPoint="CreateFileMapping")]
  private static extern IntPtr CreateFileMapping(IntPtr hFile, //HANDLE hFile,
   UInt32 lpAttributes,//LPSECURITY_ATTRIBUTES lpAttributes,  //0
   UInt32 flProtect,//DWORD flProtect
   UInt32 dwMaximumSizeHigh,//DWORD dwMaximumSizeHigh,
   UInt32 dwMaximumSizeLow,//DWORD dwMaximumSizeLow,
   string lpName//LPCTSTR lpName
   );

[DllImport("Kernel32.dll",EntryPoint="OpenFileMapping")]
  private static extern IntPtr OpenFileMapping(
   UInt32 dwDesiredAccess,//DWORD dwDesiredAccess,
   int bInheritHandle,//BOOL bInheritHandle,
   string lpName//LPCTSTR lpName
   );

const int FILE_MAP_ALL_ACCESS = 0x0002;
  const int FILE_MAP_WRITE = 0x0002;

[DllImport("Kernel32.dll",EntryPoint="MapViewOfFile")]
  private static extern IntPtr MapViewOfFile(
   IntPtr hFileMappingObject,//HANDLE hFileMappingObject,
   UInt32 dwDesiredAccess,//DWORD dwDesiredAccess
   UInt32 dwFileOffsetHight,//DWORD dwFileOffsetHigh,
   UInt32 dwFileOffsetLow,//DWORD dwFileOffsetLow,
   UInt32 dwNumberOfBytesToMap//SIZE_T dwNumberOfBytesToMap
   );

[DllImport("Kernel32.dll",EntryPoint="UnmapViewOfFile")]
  private static extern int UnmapViewOfFile(IntPtr lpBaseAddress);

[DllImport("Kernel32.dll",EntryPoint="CloseHandle")]
  private static extern int CloseHandle(IntPtr hObject);

然后分别在AB两个进程中定义如下两个信号量及相关变量;

  private Semaphore m_Write;  //可写的信号
  private Semaphore m_Read;  //可读的信号
  private IntPtr handle;     //文件句柄
  private IntPtr addr;       //共享内存地址
  uint mapLength;            //共享内存长
 
定义这两个信号量是为读写互斥用的。
在A进程中创建共享内存:

m_Write = new Semaphore(1,1,"WriteMap");
m_Read = new Semaphore(0,1,"ReadMap");
mapLength = 1024;
IntPtr hFile = new IntPtr(INVALID_HANDLE_VALUE);   
handle = CreateFileMapping(hFile,0,PAGE_READWRITE,0,mapLength,"shareMemory");
addr = MapViewOfFile(handle,FILE_MAP_ALL_ACCESS,0,0,0);

然后再向共享内存中写入数据:

m_Write.WaitOne();
byte[] sendStr = Encoding.Default.GetBytes(txtMsg.Text + '/0');
//如果要是超长的话,应另外处理,最好是分配足够的内存
if(sendStr.Length < mapLength)
      Copy(sendStr,addr);
m_Read.Release();

这是在一个单独的方法中实现的,可多次调用,但受信号量的控制。其中txtMsg是一个文本框控件,实际中可用任意字符串,加最后的'/0'是为了让在共享内存中的字符串有一个结束符,否则在内存中取出时是以'/0'为准的,就会出现取多的情况。
Copy方法的实现如下:

static unsafe void Copy(byte[] byteSrc,IntPtr dst)
  {
   fixed (byte* pSrc = byteSrc)
   {
    byte* pDst = (byte*)dst;
    byte* psrc = pSrc;
    for(int i=0;i<byteSrc.Length;i++)
    {
     *pDst = *psrc;
     pDst++;
     psrc ++;
    }
   }
  }
 

注意unsafe 关键字,在编译时一定要打开非安全代码开关。
最后不要忘了在A进程中关闭共享内存对象,以免内存泄露。

   UnmapViewOfFile(addr);
   CloseHandle(handle);

要在B进程中读取共享内存中的数据,首先要打开共享内存对象:

m_Write = Semaphore.OpenExisting("WriteMap");
m_Read = Semaphore.OpenExisting("ReadMap");
handle = OpenFileMapping(0x0002,0,"shareMemory");

读取共享内存中的数据:

   m_Read.WaitOne();
   string str = MapViewOfFile(handle,FILE_MAP_ALL_ACCESS,0,0,0);
   txtMsg.Text = str;
   m_Write.Release();

这里获取了字符串,如果要获取byte数组,请参考上面的Copy函数实现。

 
 
 
 
 
 

参考文章

c# 进程间同步实现 进程之间通讯的几种方法(转载)

C# 进程同步,通信的更多相关文章

  1. python记录_day31 进程同步和进程通信

    一.进程同步 1.同步锁(又叫互斥锁) 加锁的代码以后,同一时间内只能被一个进程执行 from multiprocessing import Process, Lock def fun(loc): l ...

  2. OS进程同步与通信

    信号量机制 信号量用于互斥 P(S) 临界区 V(S) ----- P(S) 临界区 V(S) 生产者消费者: typedef int semaphore //信号量值设置为1就是互斥量 semaph ...

  3. linux使用共享内存通信的进程同步退出问题

    两个甚至多个进程使用共享内存(shm)通信,总遇到同步问题.这里的“同步问题”不是说进程读写同步问题,这个用信号量就好了.这里的同步问题说的是同步退出问题,到底谁先退出,怎么知道对方退出了.举个例子: ...

  4. Linux 进程同步和通信

    为了同步进程所以需要进程通信 管道(有名:文件形式存在,无名:仅限于父子进程间通信) 消息队列 信号量 共享存储 套接字(可用于不同机器)

  5. python全栈开发day32-进程创建,进程同步,进程间的通信,进程池

    一.内容总结 1.进程创建 1) Process:两种创建一个新进程的方法: 1.实例化Process,通过args=(,)元组形式传参,2创建类继承Process,类初始化的时候传参数 2) p.j ...

  6. Python实现进程同步和通信

    转自:https://blog.csdn.net/u014556057/article/details/66974452

  7. linux应用程序开发-进程通信(IPC)

    IPC why: 1.数据传输 2.资源共享 目的: 3.通知事件 4.进程控制 发展: 1.UNIX进程间通信 2.基于SYStem V 3.POSIX 方式分类: 1.pipe(管道) FIFO( ...

  8. C# 多线程同步和线程通信

    多线程通信 1. 当线程之间有先后的依赖关系时,属于线程之间的通信问题.也就是后一个线程要等待别的一个或多个线程全部完成,才能开始下一步的工作.可以使用: WaitHandle Class WaitH ...

  9. Linux 进程通信之 ——信号和信号量总结

    如今最经常使用的进程间通信的方式有:信号,信号量,消息队列,共享内存.       所谓进程通信,就是不同进程之间进行一些"接触",这种接触有简单,也有复杂.机制不同,复杂度也不一 ...

随机推荐

  1. 为SSD编程(4)——高级功能和内部并行

    原文 http://codecapsule.com/2014/02/12/coding-for-ssds-part-4-advanced-functionalities-and-internal-pa ...

  2. vim-normal多行操作命令的使用

    命令行命令-<:normal>这个命令可以重复上一个操作.他其实就跟.命令的效果查不到.不同的是,他可以把.的效果,作用于你用可视模式下的多行.例如,如果你想在下面的文字里在每一行加一个; ...

  3. Spark RPC

    在Spark中,对于网络调用的底层封装(粘包拆包,编解码,链路管理等)都是在common/network-common包中实现的(详见[common/network-common]).在common/ ...

  4. CMDB学习之四 ——DEBUG模式

    定义一个debug,进行解析调试,到测试文件 配置文件,配置debug模式,定义环境变量, #!/usr/bin/env python # -*- coding:utf-8 -*- import os ...

  5. STM32上使用JSON

    一.STM32工程中添加JSON 最近在一网2串项目,串口和网口之间可能需要定义一下简单的通信协议,而通信协议上则需要去定义一下通信的数据格式,上次听剑锋说要用Json来定义,目前查了下资料具体如何去 ...

  6. RGB 颜色空间转 HSI 颜色空间的matlab程序实现

    RGB 颜色空间转 HSI 颜色空间的matlab程序实现 2014.10.20之前的内容有误,这里依据wikipedia更新了算法内容. 算法以wiki为准 https://en.wikipedia ...

  7. BZOJ 1108 POI2007 天然气管道Gaz

    题目大意:给定平面上的n个黑点和n个白点.一个黑点仅仅能和右下方的白点匹配.代价为曼哈顿距离,求最小权值完备匹配 STO OTZ STO OTZ STO OTZ ans=Σ(y黑-y白+x白-x黑) ...

  8. 36.intellij idea 如何一键清除所有断点

    转自:https://www.cnblogs.com/austinspark-jessylu/p/7799212.html 1.在idea左下方找到"View Breakpoints&quo ...

  9. IPod在Linux下的实战

    刚收到一个朋友送的Ipod,经过研究今天我为大家分享一点在Linux系统下使用的经验.Apple的iPod它炫目时尚,超薄还可以俘储大量歌曲,这使得iPod十分流行.但流行的同时也带来了一些问题, 在 ...

  10. 通过NFS、FTP、HTTP三种方法安装Redhat Linux (高清版)

          本节教程讲述了通过在Red Hat Linux服务器端假设NSF Server来进行Linux系统安装的过程,并详细介绍了如何制作网络启动盘的细节.演示直观,讲解通俗易懂,特别适合初学者学 ...