首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

3.3  使用自定义消息通信

Windows程序与其他类型程序的区别就是使用消息,例如键盘或鼠标消息等,在DOS系统下的程序没有定义消息。在Windows操作系统中,消息不但可以用于进程内的通信,也可以用于进程间的通信。这里重点介绍进程间的消息通信。

3.3.1  通过自定义消息实现进程间通信的方法

消息分为两种,即系统消息和用户(程序设计者)自定义消息。系统消息定义从0到0x3FF,可以使用0x400到0x7FFF定义自己的消息。Windows把0x400定义为WM_USER。如果想定义自己的一个消息,可以在WM_USER上加上一个值。

还有一种自定义窗口消息的方法是用RegisterWindowsMessage()函数来注册这个消息。与在WM_USER上加上某个数相比,它的好处是不必考虑所表示的消息标识符是否超出工程的允许范围。

要想用消息实现进程间通信,则需要在这两个程序中定义或注册相同的消息,才能保证数据通信顺利进行。用户自定义消息的方法如下:

l           

#define WM_COMM      WM_USER+100

const UINT wm_nRegMsg=RegisterWindowMessage("reg_data");

有了这两种定义的消息后,可以用如下的方法来发送消息。

pWnd->SendMessage(WM_COMM,NULL,(LPARAM)uMsg);

pWnd->SendMessage(wm_nRegMsg,NULL,(LPARAM)uMsg);

其中pWnd为接收这个消息的窗口句柄,uMsg为要通过消息发送的数据,是长整型。这两个消息的发送可以分别在一个发送函数里实现,其具体的做法见以后的实例。通过实验可知,这两种自定义消息的发送效果是一样的。

在接收消息的程序中,除与发送消息的程序需要定义相同的消息外,还需要定义相应的消息映射和消息映射函数,消息的映射方法如下:

ON_MESSAGE(WM_COMM,OnUserReceiveMsg)

ON_REGISTERED_MESSAGE(wm_nRegMsg,OnRegReceiveMsg)

与以上消息映射对应的函数定义如下:

void CDataRecvDlg::OnUserReceiveMsg(WPARAM wParam,LPARAM lParam)

{

    // 增加用户自定义程序代码

}

//--------------------------------------------------------------------

void CDataRecvDlg::OnRegReceiveMsg(WPARAM wParam,LPARAM lParam)

{

// 增加用户自定义程序代码

}

其中OnUserReceiveMsg()函数为WM_COMM消息的映射函数,OnRegReceiveMsg()函数为wm_nRegMsg消息的映射函数。可以看出,这两种消息的映射函数形式是一样的。

3.3.2  通过自定义消息实现进程间通信的实例

为说明以自定义消息实现进程之间的通信,作者用VC++ 编写了这样的程序。有两个对话框程序,其中一个为发送程序,另一个为接收程序。在这两个程序中分别定义了两个消息WM_COMM和wm_nRegMsg,在CDataSendDlg类中增加了用于发送数据的两个函数,即void CDataSendDlg::OnSendUsermsg()和void CDataSendDlg::OnSendRegmsg()。它们的源代码如下:

void CDataSendDlg::OnSendUsermsg()

{

    UpdateData();                                   // 更新数据

    CWnd *pWnd=CWnd::FindWindow(NULL,_T("DataRecv"));   // 查找DataRecv进程

    if(pWnd==NULL){

        AfxMessageBox(TEXT("Unable to find DataRecv."));

        return;

    }

    UINT uMsg;

    uMsg=atoi(m_strUserMsg);

    pWnd->SendMessage(WM_COMM,NULL,(LPARAM)uMsg);   // 发送.

}

//--------------------------------------------------------------------

void CDataSendDlg::OnSendRegmsg()

{

    UpdateData();                                   // 更新数据

    CWnd *pWnd=CWnd::FindWindow(NULL,_T("DataRecv"));   // 查找DataRecv进程

    if(pWnd==NULL){

        AfxMessageBox("Unable to find DataRecv.");

        return;

    }

    UINT uMsg;

    uMsg=atoi(m_strRegMsg);

    pWnd->SendMessage(wm_nRegMsg,NULL,(LPARAM)uMsg); // 发送

}

在接收数据的程序中要做三件事:①定义自定义消息;②定义消息映射表;③定义消息映射函数。自定义消息的方法如前面所述。在CDataRecvDlg类中增加了两个用于接收数据的函数,即void CDataRecvDlg::OnUserReceiveMsg()和void CDataRecvDlg:: OnRegReceiveMsg()。消息映射表如下:

BEGIN_MESSAGE_MAP(CDataRecvDlg, CDialog)

    //{{AFX_MSG_MAP(CDataRecvDlg)

    ON_MESSAGE(WM_COMM,OnUserReceiveMsg)

    ON_REGISTERED_MESSAGE(wm_nRegMsg,OnRegReceiveMsg)

    //}}AFX_MSG_MAP

END_MESSAGE_MAP()

消息映射表中的映射函数名的格式是一样的。其实它们可以用同一个函数,为了说明方便,这里把它们的名字取为不一样。接收数据程序中的消息映射函数的源代码如下:

void CDataRecvDlg::OnUserReceiveMsg(WPARAM wParam,LPARAM lParam)

{

    m_strUserMsg.Format("%d\n",int(lParam));

    UpdateData(FALSE);   // 更新数据

}

//--------------------------------------------------------------------

void CDataRecvDlg::OnRegReceiveMsg(WPARAM wParam,LPARAM lParam)

{

    m_strRegMsg.Format("%d\n",int(lParam));

    UpdateData(FALSE);   // 更新数据

}

从上面的实例中可以看出,以自定义消息来进行进程之间的通信存在一定的局限性,即所发送的数据只能是长整型,而对于字符串,则不能进行通信。要进行字符串或大批量的数据的传输,则需要采用其他的通信方法。

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论