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

3.5  使用内存读写函数和内存映射文件通信

对于ReadProcessMemory()和WriteProcessMemory()函数的通信方法,在第1章已做介绍。并用它说明了C指针的意义,但有两点需要改进:①接收程序在接收数据时所用的指针代码值不需要事先给定;②内存大小是可以变化的。这里将对内存读写函数的通信方法做一点改进。

3.5.1  使用内存映射文件通信的方法

采用内存映射(File Mapping)机制可以将整个文件映射为进程虚拟地址空间的一部分来加以访问。这种方法和实例前面已做了详细介绍,这里不再重复。

3.5.2  使用内存读写函数实现进程间通信的方法

要使接收程序获得发送程序的数据指针,可以通过发送消息方法来进行,即通过消息把数据指针从发送程序传递到接收程序。也可以用第1章所介绍的方法:先获得发送程序中的被发送数据指针,然后把这个指针直接赋值给接收数据的程序。但这种方法在实际操作中较困难,使用起来不方便。要使用发送消息的方法来传递指针,就需要定义一个用户消息。可用如下的自定义消息来传递指针,即

const UINT wm_nMemMsg=RegisterWindowMessage("mem_data");

        

要通过内存来传递数据,还必须要在内存中申请一定的内存空间,这一点很重要。用变量定义的方法只能申请有限的固定的内存空间,例如,定义一个char变量只能在内存里申请到一个字节的内存空间,定义一个int 变量只能在内存里申请到4个字节的内存空间。如果要分配一块内存空间存放数据,可以调用GlobalAlloc()或者VirtualAllocEx()等来实现。

3.5.3  使用内存读写函数实现进程间通信的实例

自定义消息和内存读写函数(ReadProcessMemory()和WriteProcessMemory())相结合,利用它们各自的长处进行通信。自定义消息通信只能传递一个长整型数值,而内存读写函数却需要一个内存读写地址,并且缺少一个传递数据指针的方法。这样它们正好可以“合作”,来进行大批量的数据传递工作。    

要进行这种方式的通信,同样需要编写两个对话框程序,并且在这两个程序中分别定义一个相同的用于传递指针的消息wm_nMemMsg。这里借用前面所使用的发送数据对话框类CDataSendDlg和接收数据对话框类CDataRecvDlg。在CDataSendDlg中,用MFC ClassWizard工具或手动增加成员函数void CDataSendDlg::OnSendMem(),其源代码如下:

void CDataSendDlg::OnSendMem()

{

    UpdateData();                                   // 更新数据

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

    if(pWnd==NULL){

        AfxMessageBox("Unable to find DataRecv.");

        return;

    }

    // 获取进程号

    DWORD PID;

    GetWindowThreadProcessId(pWnd->m_hWnd, (DWORD*)&PID );

    HANDLE hProcess = OpenProcess (PROCESS_ALL_ACCESS,FALSE,PID);

    // 分配虚拟内存

    LPVOID lpBaseAddress;

    lpBaseAddress = VirtualAllocEx(hProcess, 0, BUFFER_SIZE,

                  MEM_COMMIT, PAGE_READWRITE);      

    char  data[BUFFER_SIZE];

    strcpy(data,m_strMem);

    // 把字符串写入hProcess进程的内存

    WriteProcessMemory(hProcess, lpBaseAddress, data, BUFFER_SIZE, NULL);

    // 发送基址给DataRecv进程

    pWnd->SendMessage(wm_nMemMsg,NULL,(LPARAM)lpBaseAddress);

    // 等待接收程序接收数据

    Sleep(100);

    // 释放虚拟内存

    VirtualFreeEx(hProcess,lpBaseAddress, 0, MEM_RELEASE);

}

从以上程序中可以看出如何使用WriteProcessMemory()和wm_nMemMsg消息来发送字符串m_strMem。这段程序中,首先,寻找接收数据的程序DataRecv的窗口指针pWnd和进程句柄hProcess,再用VirtualAllocEx()函数在这个进程中申请虚拟内存空间。然后,用WriteProcessMemory()把字符串m_strMem存放入虚拟内存,并且通过消息wm_nMemMsg把所申请的内存空间起始地址发送给数据接收程序。最后,当数据接收程序接收到数据后,用VirtualFreeEx()释放所申请的虚拟内存。

在数据接收程序的对话框类CDataRecvDlg中,需要定义wm_nMemMsg消息映射,它在消息映射表中的表示方法如下:

BEGIN_MESSAGE_MAP(CDataRecvDlg, CDialog)

    //{{AFX_MSG_MAP(CDataRecvDlg)

    ON_REGISTERED_MESSAGE(wm_nMemMsg,OnRegMemMsg)

    //}}AFX_MSG_MAP

END_MESSAGE_MAP()

在数据接收对话框类CDataRecvDlg中,用MFC ClassWizard工具或手动增加消息映射函数void CDataRecvDlg::OnRegMemMsg(),其定义如下:

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

{

    LPVOID lpBaseAddress=(LPVOID)lParam;

    // 把字符串写入hProcess进程的内存

    HANDLE hProcess=GetCurrentProcess();

    char data[BUFFER_SIZE];

    ReadProcessMemory(hProcess, lpBaseAddress, data,BUFFER_SIZE, NULL);

    m_strMem=data;

    // 更新数据

    UpdateData(FALSE);

}

查看所有评论(0)条】

最近评论



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