环境:VS2005 C# WinForm注:我的方法仅适用于同一系统内的进程,并且相关进程都是您自己编写的C#程序。
网上关于C#进程间通信的资料:WM_COPYDATA、共享内存、管道、消息队列、SOCKET...
其中WM_COPYDATA是最简单的,但它受制于窗口。当窗口不处在顶层时,WM_COPYDATA就可能失效。共享内存是较为基础的一种办法,但要用好它需要一些技巧。另外小弟对进程间消息传递的及时性非常看重,希望一个进程发出消息后,目标进程能够立即做出反应。但是进程边界决定了这是不可能的,因为发送消息的进程不可能直接调用目标进程里的函数。归根结底,目标进程得自己通过循环来查看外面是否有属于自己的消息。WM_COPYDATA是通过窗口消息循环来获取,其它几种方法则是在内部通过一个while循环来获取信息。因为要避免这个while循环影响到UI线程,所以必需另开线程。在了解了进程间通迅一些基础原理后,小弟总结出自己的方法。其原理是:以共享内存为基础,发送方将消息码(代表了消息含义)及消息相关数据,以及接收进程的标识(进程ID或主窗口Text)都放到共享内存中。接收方则循环检查共享内存中有无属于自己的消息数据,若有则取出处理。处理完后接收方将共享内存数据清空。
理论上需要对共享内存的写操作进行同步,不过目前没提供同步代码(小弟工程中不需要,所以懒得弄了...)
首先是共享内存操作类,用于进程间数据传递。可根据需要对其进行修改以附合您要求,比如其中结构体定义。    public static class ProcessMessaging
    {
        static ShareMem Data = new ShareMem();        /// <summary>
        /// 获取共享内存(MyData结构)
        /// </summary>
        /// <returns></returns>
        public static MyData GetShareMem()
        {
            int MemSize = Marshal.SizeOf(typeof(MyData));            if (Data.Init("MyData", MemSize) != 0)
            {
                return new MyData(-1);
            }            byte[] temp = new byte[MemSize];            try
            {
                Data.Read(ref temp, 0, temp.Length);
                MyData stuc = (MyData)Tools.BytesToStuct(temp, typeof(MyData));
                return stuc;
            }
            catch (Exception)
            {
                return new MyData(-1);
            }
        }//end fun        /// <summary>
        /// 设置共享内存(MyData结构)
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static bool SetShareMem(MyData data)
        {
            int MemSize = Marshal.SizeOf(typeof(MyData));            if (Data.Init("MyData", MemSize) != 0)//"MyData"共享内存名称,您起别的名字也可以
            {
                return false;
            }            try
            {
                byte[] b = Tools.StructToBytes(data);
                Data.Write(b, 0, b.Length);
            }
            catch (Exception)
            {
                return false;
            }
            return true;
        }//end fun
    }//end class    public class ShareMem
    {
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, IntPtr lParam);        [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr CreateFileMapping(int hFile, IntPtr lpAttributes, uint flProtect, uint dwMaxSizeHi, uint dwMaxSizeLow, string lpName);        [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr OpenFileMapping(int dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, string lpName);        [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr MapViewOfFile(IntPtr hFileMapping, uint dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, uint dwNumberOfBytesToMap);        [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
        public static extern bool UnmapViewOfFile(IntPtr pvBaseAddress);        [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
        public static extern bool CloseHandle(IntPtr handle);        [DllImport("kernel32", EntryPoint = "GetLastError")]
        public static extern int GetLastError();        const int ERROR_ALREADY_EXISTS = 183;        const int FILE_MAP_COPY = 0x0001;
        const int FILE_MAP_WRITE = 0x0002;
        const int FILE_MAP_READ = 0x0004;
        const int FILE_MAP_ALL_ACCESS = 0x0002 | 0x0004;        const int PAGE_READONLY = 0x02;
        const int PAGE_READWRITE = 0x04;
        const int PAGE_WRITECOPY = 0x08;
        const int PAGE_EXECUTE = 0x10;
        const int PAGE_EXECUTE_READ = 0x20;
        const int PAGE_EXECUTE_READWRITE = 0x40;        const int SEC_COMMIT = 0x8000000;
        const int SEC_IMAGE = 0x1000000;
        const int SEC_NOCACHE = 0x10000000;
        const int SEC_RESERVE = 0x4000000;        const int INVALID_HANDLE_VALUE = -1;        IntPtr m_hSharedMemoryFile = IntPtr.Zero;
        IntPtr m_pwData = IntPtr.Zero;
        bool m_bAlreadyExist = false;
        bool m_bInit = false;
        long m_MemSize = 0;        public ShareMem()
        {
        }        ~ShareMem()
        {
            Close();
        }        /// <summary>
        /// 初始化共享内存
        /// </summary>
        /// <param name="strName">共享内存名称</param>
        /// <param name="lngSize">共享内存大小</param>
        /// <returns></returns>
        public int Init(string strName, long lngSize)
        {
            if (lngSize <= 0 || lngSize > 0x00800000) lngSize = 0x00800000;
            m_MemSize = lngSize;
            if (strName.Length > 0)
            {
                //创建内存共享体(INVALID_HANDLE_VALUE)
                m_hSharedMemoryFile = CreateFileMapping(INVALID_HANDLE_VALUE, IntPtr.Zero, (uint)PAGE_READWRITE, 0, (uint)lngSize, strName);
                if (m_hSharedMemoryFile == IntPtr.Zero)
                {
                    m_bAlreadyExist = false;
                    m_bInit = false;
                    return 2; //创建共享体失败
                }
                else
                {
                    if (GetLastError() == ERROR_ALREADY_EXISTS)  //已经创建
                    {
                        m_bAlreadyExist = true;
                    }
                    else                                         //新创建
                    {
                        m_bAlreadyExist = false;
                    }
                }
                //---------------------------------------
                //创建内存映射
                m_pwData = MapViewOfFile(m_hSharedMemoryFile, FILE_MAP_WRITE, 0, 0, (uint)lngSize);
                if (m_pwData == IntPtr.Zero)
                {
                    m_bInit = false;
                    CloseHandle(m_hSharedMemoryFile);
                    return 3; //创建内存映射失败
                }
                else
                {
                    m_bInit = true;
                    if (m_bAlreadyExist == false)
                    {
                        //初始化
                        MyData data = new MyData(-1);
                        byte[] bd = Tools.StructToBytes(data);
                        Marshal.Copy(m_pwData, bd, 0, bd.Length);
                    }
                }
                //----------------------------------------
            }
            else
            {
                return 1; //参数错误     
            }            return 0;     //创建成功
        }//end fun        /// <summary>
        /// 关闭共享内存
        /// </summary>
        public void Close()
        {
            if (m_bInit)
            {
                UnmapViewOfFile(m_pwData);
                CloseHandle(m_hSharedMemoryFile);
            }
        }        /// <summary>
        /// 读数据
        /// </summary>
        /// <param name="bytData">数据</param>
        /// <param name="lngAddr">起始地址</param>
        /// <param name="lngSize">个数</param>
        /// <returns></returns>
        public int Read(ref byte[] bytData, int lngAddr, int lngSize)
        {
            if (lngAddr + lngSize > m_MemSize) return 2; //超出数据区
            if (m_bInit)
            {
                Marshal.Copy(m_pwData, bytData, lngAddr, lngSize);
            }
            else
            {
                return 1; //共享内存未初始化
            }
            return 0;     //读成功
        }        /// <summary>
        /// 写数据
        /// </summary>
        /// <param name="bytData">数据</param>
        /// <param name="lngAddr">起始地址</param>
        /// <param name="lngSize">数据长度</param>
        /// <returns></returns>
        public int Write(byte[] bytData, int lngAddr, int lngSize)
        {
            if (lngAddr + lngSize > m_MemSize) return 2; //超出数据区
            if (m_bInit)
            {
                Marshal.Copy(bytData, lngAddr, m_pwData, lngSize);
            }
            else
            {
                return 1; //共享内存未初始化
            }
            return 0;     //写成功
        }
    }//end class--下面继续

解决方案 »

  1.   


        //根据需要扩展该结构体
        [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
        public struct MyData
        {
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)]
            public char[] c0;
            public int l0;        public int i0;
            public int i1;
            public int i2;
            public int i3;
            public int i4;
            public int i5;        //placeholder:该参数我用不着,可C#规定必需有,所以起个这名字
            public MyData(int placeholder)
            {
                c0 = new char[1024];
                l0 = 0;     
                i0 = 0;
                i1 = 0;
                i2 = 0;
                i3 = 0;
                i4 = 0;
                i5 = 0;
            }//end fun        /// <summary>
            /// 进程间通信,进程ID,-2表示所有进程
            /// </summary>
            public int ProcessID
            {
                get
                { return i4; }
                set
                {                i4 = value;
                }
            }        /// <summary>
            /// 进程间通信,消息码
            /// </summary>
            public int InfoCode
            {
                get
                { return i5; }
                set
                { i5 = value; }
            }        /// <summary>
            /// 示例字符串参数
            /// </summary>
            public string Url
            {
                get
                {
                    if (l0 > 0)
                    { return new string(c0, 0, l0); }
                    else
                    {
                        return "";
                    }
                }
                set
                {
                    if (value != null)
                    {
                        value.CopyTo(0, c0, 0, value.Length);
                        l0 = value.Length;
                    }
                }
            }        /// <summary>
            /// 示例矩形参数
            /// </summary>
            public Rectangle WindowPosition
            {
                get
                { return new Rectangle(i0, i1, i2, i3); }
                set
                {
                    i0 = value.X;
                    i1 = value.Y;
                    i2 = value.Width;
                    i3 = value.Height;
                }
            }
        }//end struct
        public static class Tools
        {
            //序列化结构体复制入byte数组
            public static byte[] StructToBytes(object structObj)
            {
                //得到结构体的大小
                int size = Marshal.SizeOf(structObj);
                //创建byte数组
                byte[] bytes = new byte[size];
                //分配结构体大小的内存空间
                IntPtr structPtr = Marshal.AllocHGlobal(size);
                //将结构体拷到分配好的内存空间
                Marshal.StructureToPtr(structObj, structPtr, false);
                //从内存空间拷到byte数组
                Marshal.Copy(structPtr, bytes, 0, size);
                //释放内存空间
                Marshal.FreeHGlobal(structPtr);
                //返回byte数组
                return bytes;
            }        //byte数组复制入序列化结构体,注意在返回结果前加上强制转换
            public static object BytesToStuct(byte[] bytes, Type type)
            {
                //得到结构体的大小
                int size = Marshal.SizeOf(type);
                //byte数组长度小于结构体的大小
                if (size > bytes.Length)
                {
                    //返回空
                    return null;
                }
                //分配结构体大小的内存空间
                IntPtr structPtr = Marshal.AllocHGlobal(size);
                //将byte数组拷到分配好的内存空间
                Marshal.Copy(bytes, 0, structPtr, size);
                //将内存空间转换为目标结构体
                object obj = Marshal.PtrToStructure(structPtr, type);
                //释放内存空间
                Marshal.FreeHGlobal(structPtr);
                //返回结构体
                return obj;
            }//end fun
        }//end class
    如果要向一个进程发送消息:                    MyData data = ProcessMessaging.GetShareMem();//您new一个也行
                        data.InfoCode = ...;//消息码
                        data.ProcessID = ...;//接收进程ID
                        ...其它数据
                        ProcessMessaging.SetShareMem(data);接下来说下接收方,以下代码都位于主窗口CPP中:       int ProcessID = 0;
           System.Timers.Timer time = new System.Timers.Timer(10);//实例化Timer类,设置间隔时间为10毫秒;       下面4行代码在构造函数中添加:
           ProcessID = Process.GetCurrentProcess().Id;
           time.Elapsed += new System.Timers.ElapsedEventHandler(theout);//到达时间的时候执行事件; 
           time.AutoReset = true;//设置是执行一次(false)还是一直执行(true); 
           time.Enabled = false;//是否执行System.Timers.Timer.Elapsed事件;
           //load事件中启动time
            public void theout(object source, System.Timers.ElapsedEventArgs e)
            {
                ProcessMessageHandler pmh = new ProcessMessageHandler(ProcessMessage);
                this.Invoke(pmh);
            }//end fun        public delegate void ProcessMessageHandler();        public void ProcessMessage()
            {
                MyData data = ProcessMessaging.GetShareMem();
                if (data.ProcessID == ProcessID)
                {
                    switch (InfoCode)
                    {
                       ...处理
                    }
                }
              ...清空data
              ProcessMessaging.SetShareMem(data);
            } 
      最后,欢迎大家做出修改补充!
      

  2.   

    辛苦了!很强大!
    .NET4.0提供了操作内存映射文件的直接支持。换vs2010吧,这样你这不必那么辛苦的PInvoke了。
      

  3.   

    注意一下:使用定时器来代替while,省下自己去开线程,还能调整时间间隔,一举三得。不可以用VS工具栏中的定时器控件来代替System.Timers.Timer
      

  4.   

    class ProcessMessaging
    貌似代码没有贴全,楼主能否再提供以下,非常感谢
      

  5.   

    注:我的方法仅适用于同一系统内的进程,并且相关进程都是您自己编写的C#程序。
    这句话是什么意思?一个解决方案下有两个工程,产生两个进程。如果就是这两个进程通信,那么,楼主的这个类class ProcessMessaging应该放在哪里呢?我试了一下,好像不行啊?求帮助……