• 进程间通信


    环境: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 

     

    //根据需要扩展该结构体   
    [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);
      }  
    
    本人声明: 个人主页:沐海(http://www.cnblogs.com/mahaisong) 以上文章都是经过本人设计实践和阅读其他文档得出。如果需要探讨或指教可以留言或加我QQ!欢迎交流!
  • 相关阅读:
    用python将博客园的文章爬取到本地
    2016.7.9
    2016.7.8
    2016.7.7
    2016.7.5
    2016.7.4
    2016.7.3
    2016.7.2
    2016.6.28
    2016.6.27
  • 原文地址:https://www.cnblogs.com/mahaisong/p/2247785.html
Copyright © 2020-2023  润新知