利用共享内存实现进程之间的通讯

进程之间数据的共享可以用共用内存实现,在Win32中,进程之间共享内存使用的事映射文件。虚拟内存系统具有把实际内存映射到页文件或者交换文件的能力。用户可以把内存映射到任何的映射文件中,包括系统内存页。而利用系统内存页可以实现快捷的内存共享。

利用共有内存实现进程之间的数据共享共有两步:

一.    使用CreateFileMapping函数创建内存映射文件。此函数需要文件句柄,对于大多数的内存共享应用程序,建此文件句柄设置为0xFFFFFFFF即可。这样的句柄指向系统内存页文件。

二.    映射文件文件创建成功以后,以其返回的句柄作为参数,调用MapViewOfFile函数为内存映射文件对象创建视,MapViewOfFile函数将返回指向文件的视指针。可以利用此视指针对内存映射文件进行操作,内存的读写简化到了就像普通变量的操作。

 

第一个例子:

下面是最简单的例子:

//MemoryWriter.cpp

#include "windows.h"

#include "iostream.h"

 

class student

{

public:

         long ID;

         char name[20];

};

 

void main()

{

         HANDLE hMemShare;

         student stu;

     int stu_num = 30;

         student *lpstu;

         stu.ID = 99041232;

         strcpy(stu.name,"SecBug");

         hMemShare = CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE,

0,sizeof(student),"TestMemShare");

         if(hMemShare == NULL)

         {

                   cout<<"Failed to Alloocate"<<endl;

                   return;

         }

         lpstu = (student *)MapViewOfFile(hMemShare, FILE_MAP_WRITE,0,0,sizeof(student));

         if(lpstu == NULL)

         {

                   cout<<"Failed to Map"<<endl;

                   return; 

         }

         *lpstu = stu;

         while(1){}

         UnmapViewOfFile(lpstu);

}

 

//MemoryReader.cpp

#include "windows.h"

#include "iostream.h"

class student

{

public:

          long ID;

          char name[20];

};

 

void main()

{

          HANDLE hMemShare;

          student stu;

          student *lpstu;

          stu.ID = 0;

          strcpy(stu.name ,"tst");

          hMemShare = OpenFileMapping(FILE_MAP_READ,FALSE,"TestMemShare");

          if(hMemShare == NULL)

          {

                     cout<<"File Created Failed"<<endl;

                     return;

          }

 

          lpstu = (student *)MapViewOfFile(hMemShare, FILE_MAP_READ,0,0,sizeof(student));

          if(lpstu == NULL)

          {

                     cout<<"Failed to Map"<<endl;

                     return;

          }

          stu = *lpstu;

          cout<<stu.ID<<endl;

          cout<<stu.name<<endl;

          UnmapViewOfFile(lpstu);

}

 

第二个例子:

a. InfoSender项目:

1. 基于CDialog的应用程序。项目名称InfoSender

2. InfoSenderDlg.h中,增加下面带边框语句(用户自定义消息):

#define WM_INFORMATIONSENT    WM_USER + 101

class CInfoSenderDlg : public CDialog

{

// Construction

public:

         ……

3. 如下图设计界面:

  

         OK按钮的Caption改为“Send Message” Cancel按钮的Caption改为“Quit”

         双击Send Message按钮,注释掉CDialog::OnOK();

         增加一下成员变量:

 

 

4. CInfoSenderDlg::OnInitDialog()中增加以下代码:

         // TODO: Add extra initialization here

         m_nBufferSize = 4096;

         m_hMap = CreateFileMapping(INVALID_HANDLE_VALUE,

                                                                    NULL,

                                                                    PAGE_READWRITE,

                                                                    0,

                                                                    m_nBufferSize,

                                                                    "pat.memshare");      // 指定映射对象名称为pat.memshare

         ASSERT(m_hMap != NULL);

         //上面 INVALID_HANDLE_VALUE通知系统不要在硬盘上创建文件映射对象,而是转而创建其物理存储器由系统页文件

// paging file)支持的文件映射对象。

 

         m_lpvViewOfFile = MapViewOfFile(m_hMap,

                                                                    FILE_MAP_WRITE,

                                                                    0,

                                                                    0,

                                                                    m_nBufferSize);

         ASSERT(m_lpvViewOfFile != NULL);

 

5. CInfoSenderDlg::OnOK()中增加如下代码

         char tempStr[4096];

         char* separator = "|";

         // we can cast a CString object to be an LPCTSTR. The LPCTSTR type conversion operator returns a pointer to a

// read-only C-style null-terminated string from a CString object.

         strcpy(tempStr, (LPCTSTR)m_Name);

         strcat(tempStr, separator);

         strcat(tempStr, (LPCTSTR)m_IDNumber);

         strcat(tempStr, separator);

         strcat(tempStr, (LPCTSTR)m_Phone);

         strcat(tempStr, separator);

         strcat(tempStr, (LPCTSTR)m_Resume);

         memcpy(m_lpvViewOfFile, tempStr, strlen(tempStr));

         CWnd* pWnd = FindWindow(NULL, "InfoReceiver"); // 找到TitleInfoReceiver的窗口指针

         pWnd->PostMessage(WM_INFORMATIONSENT);  // TitleInfoReceiver的窗口发送自定义消息

// WM_INFORMATIONSENT

6. CInfoSenderDlg::OnCancel() 中增加语句:

         // TODO: Add extra cleanup here

         UnmapViewOfFile(m_lpvViewOfFile);

         CloseHandle(m_hMap);

        

 

InfoReceiver项目

1. 基于CDialog的应用程序。项目名称InfoReceiver

2. InfoReceiverDlg.h中,增加下面带下划线语句(用户自定义消息):

#define WM_INFORMATIONSENT WM_USER + 101        //必须和InfoSender中的一致

class CInfoReceiverDlg : public CDialog

{

// Construction

public:

         CInfoReceiverDlg(CWnd* pParent = NULL);    

……

3. OK按钮的Caption改为Receive Message界面设计和InfoSender完全一样。

4. InfoReceiverDlg.h中,增加下面带下划线语句(用户自定义消息):

         ……

         // Generated message map functions

         //{{AFX_MSG(CInfoReceiverDlg)

         virtual BOOL OnInitDialog();

         afx_msg void OnSysCommand(UINT nID, LPARAM lParam);

         afx_msg void OnPaint();

         afx_msg HCURSOR OnQueryDragIcon();

         virtual void OnOK();

         virtual void OnCancel();

         //}}AFX_MSG

         afx_msg LRESULT OnInformationSent(WPARAM wParam, LPARAM lParam);

         DECLARE_MESSAGE_MAP()

         ……

注意添加OnInformationSent的位置,不能在//{{AFX_MSG(CInfoReceiverDlg)//}}AFX_MSG之间,因为此而者之间是自动生成的消息响应函数,如果加在其间,当有新的系统消息响应函数加入时,VC会重新生成一次,从而将我们想加入的OnInformationSent清除掉。

5. InfoReceiverDlg.cpp中增加下面带下划线的语句:

BEGIN_MESSAGE_MAP(CInfoReceiverDlg, CDialog)

         //{{AFX_MSG_MAP(CInfoReceiverDlg)

         ON_WM_SYSCOMMAND()

         ON_WM_PAINT()

         ON_WM_QUERYDRAGICON()

         //}}AFX_MSG_MAP

         ON_MESSAGE(WM_INFORMATIONSENT, OnInformationSent) 

// 设定自定义消息 WM_INFORMATIONSENT的处理函数

END_MESSAGE_MAP()

         也要注意ON_MESSAGE加入的位置。理由和4中提及的一样。

6. InfoReceiverDlg.cpp中增加下面成员函数:

LRESULT CInfoReceiverDlg::OnInformationSent(WPARAM wParam, LPARAM lParam)

{

         OnOK();    // 直接调用OnOK

         return 0L;

}

 

7. CInfoReceiverDlg::OnInitDialog()中增加如下代码

// TODO: Add extra initialization here

         m_hMap = OpenFileMapping(FILE_MAP_READ, FALSE, "pat.memshare");

         ASSERT(m_hMap != NULL);

 

         m_lpvViewOfFile = MapViewOfFile(m_hMap, FILE_MAP_READ, 0, 0, 4096);

         ASSERT(m_lpvViewOfFile != NULL);

 

8. CInfoReceiverDlg::OnOK()改为一下代码:

         char* separator;

         char* another;

         char temp[4096];

         memset(temp, 0, 4096);

         separator = strchr((const char *)m_lpvViewOfFile, '|');

         memcpy(temp, m_lpvViewOfFile, (int)(separator - (char*)m_lpvViewOfFile));

         m_Name = temp;

        

         memset(temp, 0, 4096);

         another = strchr(separator + 1, '|');

         memcpy(temp, separator + 1, (int)(another - separator - 1));

         m_IDNumber = temp;

 

         memset(temp, 0, 4096);

         separator = strchr(another + 1, '|');

         memcpy(temp, another + 1, (int)(separator - another - 1));

         m_Phone = temp;

 

         memset(temp, 0, 4096);

         memcpy(temp, separator + 1, strlen(separator) - 1);

         m_Resume = temp;

 

         UpdateData(FALSE);

 

9. CInfoReceiverDlg::OnCancel() 中增加如下语句:

         // TODO: Add extra cleanup here

         UnmapViewOfFile(m_lpvViewOfFile);

         CloseHandle(m_hMap);

         ……

 

说明:

1. 不使用自定义的消息时,当在InfoSender填写相关数据后,点击Send Message按钮;启动InfoReceiver,点击Receive Message按钮,即可接收到InfoSender发过来的数据;

2. 使用自定义的消息是,启动InfoSenderInfoReceiver。当在InfoSender填写相关数据后,点击Send Message按钮,InfoReceiver即收到InfoSender发过来的数据。

下面是运行情况:

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值