在好例子网,分享、交流、成长!
您当前所在位置:首页C# 开发实例C#网络编程 → C# 不同进程间通讯实例源码下载(SendMessage方式)

C# 不同进程间通讯实例源码下载(SendMessage方式)

C#网络编程

下载此实例
  • 开发语言:C#
  • 实例大小:0.05M
  • 下载次数:200
  • 浏览次数:3429
  • 发布时间:2013-09-14
  • 实例类别:C#网络编程
  • 发 布 人:crazycode
  • 文件格式:.rar
  • 所需积分:2
 相关标签: 进程 实例 C# 通讯

实例介绍

【实例简介】

在.NET中基于Windows消息的IPC实现
一、什么是IPC
IPC(Inter process Communication)就是“进程间通讯”。我们都知道,在windows系统中,各个应用程序(进程)之间常常需要交换、传递数据,这就要解决进程间的数据通信问题。在最初的16位Windows3.x系统中,所有Windows应用程序共享单一地址,任何进程都能够对这一共享地址空间的数据进行读写操作。
随着Windwos98、Windows NT、Windows2000等32位的操作系统的出现,每个进程都有自己的地址空间,一个Windows进程不能存取另一个进程的私有数据,也就是说,虽然两个进程可以用具有相同值的指针寻址,但所读写的只是它们各自的数据,这样就减少了进程之间的相互干扰。
二、如何实现IPC
那么在windows当前系统下,如何实现进程通讯呢?其实有很多方法,如:
1、    剪贴板Clipboard
2、    DDE(动态数据交换)
3、    内存映像
4、    消息管道
5、    邮件槽
6、    Socket
7、    RPC
8、    串行/并行通信(Serial/Parallel Communication)
9、    COM/DCOM
10、Windows消息
三、基于Windows消息的IPC
现在让我们进入今天我们要讲的主题:“基于Windows消息的IPC实现”。
在这里,我假定大家对Windows消息机制都有很好的理解,所以我就不在这上面费太多的墨水了。我们直接看看Windows消息是怎么样实现进程间通讯的。我们首先看看Windows的消息常数:
WM_COPYDATA=0x004A//  当一个应用程序传递数据给另一个应用程序时发送此消息。
这就是我们要的。下面我们来看看如何利用它来实现IPC。
让我们先看看几个API函数,没有它们,我们没有办法将数据发送出去。
1、 PostMessage 
函数功能:该函数将一个消息放入(寄送)到与指定窗口创建的线程相联系消息队列里,不等待线程处理消息就返回。消息队列里的消息通过调用GetMessage和PeekMessage取得。
函数原型:B00L PostMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam);
参数
hWnd:其窗口程序接收消息的窗口的句柄。可取有特定含义的两个值:
HWND.BROADCAST:消息被寄送到系统的所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口和弹出式窗口。消息不被寄送到子窗口。
NULL:此函数的操作和调用参数dwThread设置为当前线程的标识符PostThreadMessage函数一样。
Msg:指定被寄送的消息。
wParam:指定附加的消息特定的信息。
IParam:指定附加的消息特定的信息。
返回值:如果函数调用成功,返回非零值:如果函数调用失败,返回值是零。若想获得更多的错误信息,请调用GetLastError函数。
2、 SendMessage 
函数功能:该函数将指定的消息发送到一个或多个窗口。此函数为指定的窗口调用窗口程序,直到窗口程序处理完消息再返回。而函数PostMessage不同,将一个消息寄送到一个线程的消息队列后立即返回。
函数原型:LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam);
参数:
hWnd:其窗口程序将接收消息的窗口的句柄。如果此参数为HWND_BROADCAST,则消息将被发送到系统中所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口和弹出式窗口,但消息不被发送到子窗口。
Msg:指定被发送的消息。
wParam:指定附加的消息指定信息。
IParam:指定附加的消息指定信息。
返回值:返回值指定消息处理的结果,依赖于所发送的消息。
3、 RegisterWindowMessage
函数功能:RegisterWindowMessage函数定义一个新的窗口消息,该消息保证在整个系统范围内是唯一的。调用SendMessage或PostMessage函数时可以使用该函数返回的消息值。
函数原型:UINT RegisterWindowMessage(lpsz)
参数:
lpsz指向一个以NULL结束的字符串,该字符串指定待登记的消息。
返回值:若成功地登记了消息,返回值是一个消息标识符。该标识符值的范围在0XC000到0XFFFF之间,否则,返回值为0。
我们现在在C#中声明这些API函数:
        [DllImport("user32")]
        
internal static extern int RegisterWindowMessage(string lpString);
        [DllImport(
"user32")]
        
internal static extern int PostMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
        [DllImport(
"user32")]
        
internal static extern int PostMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
        [DllImport(
"user32")]
        
internal static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, ref COPYDATASTRUCT lParam);
然后定义一些我们需要的常数:
                internal const int WM_COPYDATA = 0x004A//当一个应用程序传递数据给另一个应用程序时发送此消息
        internal const int WM_DESTROY = 0x0002//窗体被销毁
        internal const int WM_CREATE = 0x0001//应用程序创建一个窗口
        internal const int WM_QUERYENDSESSION = 0x0011//当用户选择结束对话框或程序自己调用ExitWindows函数
        internal static readonly IntPtr HWND_BROADCAST = new IntPtr(0xFFFF);
我们还需要一个传送数据的结构:
    ///<summary>
    
///发送WM_COPYDATA消息的数据结构
  
///</summary>

    internal struct COPYDATASTRUCT
    
{
        
///<summary>
        
///用户自定义数据
        
///</summary>

        internal IntPtr dwData;
        
///<summary>
        
///数据长度
        
///</summary>

        internal int cbData;
        
///<summary>
        
///数据首地址指针
        
///</summary>

        internal IntPtr lpData;
    }

现在我们来看看具体如何实现:
1、 我们首先创建一个类,让它从Form类继承,因为我们需要一个窗体,然后对它的消息进行处理:

 

internal class WinMsg : Form

{

        
private string _messageString;

        
private List<IntPtr> _windowList;

        
private int _message;

        
private int _intHandler;

        
private bool _isConnected;

}

 

2、 然后定义构造函数,在构造函数里注册一个消息通道值,并发出一个广播通知其它在这个通道的窗口。
        internal WinMsg(string messageString)
        
{
            _messageString 
= messageString;
            _isConnected 
= false;
            _intHandler 
= Handle.ToInt32();
            _windowList 
= new List<IntPtr>();
            _message 
= Win32.RegisterWindowMessage(_messageString);//注册一个消息通道
            int errCode = Win32.PostMessage(Win32.HWND_BROADCAST, _message, Win32.CONNECTION, _intHandler);//向此通道内所有的窗口广播自己的句柄
            if (errCode == 0)
            
{
                
throw new Win32Exception(errCode);//发生错误,抛出异常
            }

            
else
            
{
                _isConnected 
= true;
            }

        }
3、 重写基类的WndProc函数,处理接收到的消息:
        protected override void WndProc(ref Message m)
        
{
            
if (m.Msg == _message)//接收到广播消息,进行处理
            {
                
int LParam = m.LParam.ToInt32();
                
int WParam = m.WParam.ToInt32();
                
if (LParam != 0 && LParam != _intHandler)
                
{
                    
if (WParam == Win32.DISCONNECTION)
                    
{
                        _windowList.Remove(m.WParam);
//将对方窗口的句柄从列表中删除
                    }

                    
else
                    
{
                        
if (WParam==Win32.CONNECTION)
                        
{
                            Win32.PostMessage(m.LParam, _message, Win32.REVERSION, _intHandler);
                        }

                        _windowList.Add(m.LParam);
//将对方窗口的句柄存入列表中
                    }

                }

                
return;
            }

            
switch (m.Msg)
            
{
                
case Win32.WM_COPYDATA://接收到其它窗口发送过来的数据
                    {
                        COPYDATASTRUCT data 
= new COPYDATASTRUCT();
                        data 
= (COPYDATASTRUCT)m.GetLParam(data.GetType());
                        
byte[] message = new byte[data.cbData];
                        Marshal.Copy(data.lpData, message, 
0, data.cbData);//从非托管内存中将数据复制到我们的byte数组中。
                        Anyzler(m.WParam, message);//在这里处理接收到的数据。
                    }

                    
break;
                
case Win32.WM_DESTROY:
                
case Win32.WM_QUERYENDSESSION://窗口被关闭,向其它窗口广播通知从队列中删除自己
                    Win32.PostMessage(Win32.HWND_BROADCAST, _message, Win32.DISCONNECTION, _intHandler);
                    
base.WndProc(ref m);//调用基类的消息处理函数。
                    break;
                
default:
                    
base.WndProc(ref m); //调用基类的消息处理函数。
                    break;
            }

        }
4、 定义发送消息的函数:
        internal void Send(byte[] message)
        
{
            
if (_isConnected)
            
{
                
int length = message.Length;
                IntPtr ptr 
= Marshal.AllocHGlobal(length);//申请一块非托管内存
                Marshal.Copy(message, 0, ptr, length);//将要发送的数据封送到非托管内存
                COPYDATASTRUCT data = new COPYDATASTRUCT();
                data.dwData 
= IntPtr.Zero;//这里可以随意定义。
                data.cbData = length;//传递要发送的数据的长度
                data.lpData = ptr;//传递要发送的数据的地址指针
                
//向其它所有窗口发送数据,这里不能发广播消息。必须一个一个发送。
                foreach (IntPtr window in _windowList)
                
{
                    Win32.SendMessage(window, Win32.WM_COPYDATA, 
this.Handle, ref data);
                }

                Marshal.FreeHGlobal(ptr);
//释放这块非托管内存,这行一定要写上,不然会内存泄漏。
            }

        }
好了,主要代码就是这些了!

【实例截图】

【核心代码】


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

namespace WindowsApplication3
{
    public partial class Form1 : Form
    {
        MyWindowsMessage msgData;
        public Form1()
        {
            InitializeComponent();
        }

        protected override void OnLoad(EventArgs e)
        {
            msgData = new MyWindowsMessage("testProject");
            msgData.Parent = this;
            msgData.StartMessage();
        }

         private void button1_Click(object sender, EventArgs e)
        {
            msgData.SendMessage(Encoding.Default.GetBytes(textBox1.Text));
            //for (int i = 0; i < 1000; i  )
            //{
            //    msgData.SendMessage(Encoding.Default.GetBytes(i.ToString()));
            //}
        }
        class MyWindowsMessage : WindowsMessage
        {

            private Form1 _parent;

            public Form1 Parent
            {
                get { return _parent; }
                set { _parent = value; }
            }

            public MyWindowsMessage()
                : base()
            {
            }

            public MyWindowsMessage(string channelName)
                : base(channelName)
            {

            }
            public override void Anyzler(IntPtr target, byte[] message)
            {
                _parent.listBox1.Items.Add( Encoding.Default.GetString(message));
            }
        }

    }


}


标签: 进程 实例 C# 通讯

网友评论

发表评论

(您的评论需要经过审核才能显示)

查看所有0条评论>>

小贴士

感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。

  • 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
  • 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
  • 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
  • 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。

关于好例子网

本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明

;
报警