Chinaunix首页 | 论坛 | 博客
  • 博客访问: 544646
  • 博文数量: 252
  • 博客积分: 6057
  • 博客等级: 准将
  • 技术积分: 1635
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-21 10:17
文章分类

全部博文(252)

文章存档

2013年(1)

2012年(1)

2011年(32)

2010年(212)

2009年(6)

分类: WINDOWS

2010-08-23 10:40:53

(用户自定义消息,用户注册消息,windows剪贴板,WM_COPY, 内存映射,对目标进程的内存)


发送端:
新建一个基本对话框工程,添加6个文本框控件,并且关联控件变量(CString类型):
 m_strCopyData, m_strFileMap, m_strMem, m_strRegMsg, m_strUserMsg, m_strClipBoard

然后在 CPP 文件里面,做如下定义:

#define BUFFER_SIZE  0x100          // 用内存地址通信时分配的最大内存.
#define WM_COMM      WM_USER+100
const UINT wm_nRegMsg=RegisterWindowMessage("reg_data");
const UINT wm_nMemMsg=RegisterWindowMessage("mem_data");

添加6个按钮,在里面写入代码

//使用 WM_COPY 方式进行发送
void CDataSendDlg::OnSendCopydata()
{
    UpdateData();  //更新数据.
    CWnd *pWnd=CWnd::FindWindow(NULL,_T("DataRecv")); // 查找DataRecv进程.
    if(pWnd==NULL){
        AfxMessageBox(TEXT("Unable to find DataRecv."));
        return;
    }

    COPYDATASTRUCT cpd; // 给COPYDATASTRUCT结构赋值.
    cpd.dwData = 0;
    cpd.cbData = m_strCopyData.GetLength();
    cpd.lpData = (void*)m_strCopyData.GetBuffer(cpd.cbData);
    pWnd->SendMessage(WM_COPYDATA,NULL,(LPARAM)&cpd);// 发送.
}

//使用用户自定义消息的方式进行发送
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);// 发送.
}

//使用对目标进程内存的访问方式进行发送
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);
}

//使用内存映射的方式进行发送
void CDataSendDlg::OnSendFilemap()
{
    UpdateData();  // 更新数据.

    // 创建内存映像对象.
    HANDLE hMapping;  
    LPSTR lpData;  
    hMapping=CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,
                          PAGE_READWRITE,0,BUFFER_SIZE,"MYSHARE");  
    if(hMapping==NULL)  
    {  
        AfxMessageBox("CreateFileMapping() failed.");
        return;
    }

    // 将文件的视图映射到一个进程的地址空间上,返回LPVOID类型的内存指针.
    lpData=(LPSTR)MapViewOfFile(hMapping,FILE_MAP_ALL_ACCESS,0,0,0);  
    if(lpData==NULL)  
    {  
        AfxMessageBox("MapViewOfFile() failed.");
        return;
    }

    // 给这段映像内存写数据.
    sprintf(lpData,m_strFileMap);  
   
    // 释放映像内存.
    UnmapViewOfFile(lpData);  
}

//使用windows剪贴板的方式进行发送
void CDataSendDlg::OnSendClipboard()
{
    UpdateData();                    // 更新数据.
    CString strData=m_strClipBoard;  // 获得数据.

    // 打开系统剪贴板.
    if (!OpenClipboard()) return;

    // 使用之前,清空系统剪贴板.
    EmptyClipboard();

    // 分配一内存,大小等于要拷贝的字符串的大小,返回的内存控制句柄.
    HGLOBAL hClipboardData;
    hClipboardData = GlobalAlloc(GMEM_DDESHARE, strData.GetLength()+1);
   
    // 内存控制句柄加锁,返回值为指向那内存控制句柄所在的特定数据格式的指针.
    char * pchData;
    pchData = (char*)GlobalLock(hClipboardData);
   
    // 将本地变量的值赋给全局内存.
    strcpy(pchData, LPCSTR(strData));
   
    // 给加锁的全局内存控制句柄解锁.
    GlobalUnlock(hClipboardData);
   
    // 通过全局内存句柄将要拷贝的数据放到剪贴板上.
    SetClipboardData(CF_TEXT,hClipboardData);
   
    // 使用完后关闭剪贴板.
    CloseClipboard();
}

至此,完成发送端


接收端:
新建一个基本对话框工程( DataRecv )
添加6个文本框控件,并且关联控件变量(CString类型):
m_strCopyData,m_strFileMap,m_strMem,m_strUserMsg,m_strRegMsg,m_strClipBoard

然后在 CPP 文件里面,做如下定义:

#define BUFFER_SIZE  0x100        // 用内存地址通信时分配的最大内存.
#define WM_COMM      WM_USER+100
const UINT wm_nRegMsg=RegisterWindowMessage("reg_data");
const UINT wm_nMemMsg=RegisterWindowMessage("mem_data");

添加两个按钮,并写入代码:

//控件 ID 为 IDC_RECV_CLIPBOARD 将取得的值赋给 m_strFileMap
//使用windows剪贴板的方式进行接收
void CDataRecvDlg::OnBnClickedRecvClipboard()
{
    // TODO: 在此添加控件通知处理程序代码
    // 打开系统剪贴板.
    if (!OpenClipboard()) return;

    // 判断剪贴板上的数据是否是指定的数据格式.
    if (IsClipboardFormatAvailable(CF_TEXT)|| IsClipboardFormatAvailable(CF_OEMTEXT))
    {
        // 从剪贴板上获得数据.
        HANDLE hClipboardData = GetClipboardData(CF_TEXT);
   
        // 通过给内存句柄加锁,获得指向指定格式数据的指针.
        char *pchData = (char*)GlobalLock(hClipboardData);
   
        // 本地变量获得数据.
        m_strClipBoard = pchData;
   
        // 给内存句柄解锁.
        GlobalUnlock(hClipboardData);
    }
    else
    {
        AfxMessageBox("There is no text (ANSI) data on the Clipboard.");
    }
   
    // 使用完后关闭剪贴板.
    CloseClipboard();

    // 更新数据.
    UpdateData(FALSE);
}

//控件 ID 为 IDC_RECV_FILEMAP, 将取得的值赋给 m_strClipBoard
//使用内存映射的方式进行接收
void CDataRecvDlg::OnBnClickedRecvFilemap()
{
    // TODO: 在此添加控件通知处理程序代码
    // 创建内存映像对象.
    HANDLE hMapping;
    LPSTR lpData;
    hMapping=CreateFileMapping((HANDLE)0xFFFFFFFF,
                      NULL,PAGE_READWRITE,0,0x100,"MYSHARE");
    if(hMapping==NULL)
    {
        AfxMessageBox("CreateFileMapping() failed.");
        return;
    }

    // 将文件的视图映射到一个进程的地址空间上,返回LPVOID类型的内存指针.
    lpData=(LPSTR)MapViewOfFile(hMapping,FILE_MAP_ALL_ACCESS,0,0,0);
    if(lpData==NULL)
    {
        AfxMessageBox("MapViewOfFile() failed.");
        return;
    }
   
    // 给这段映像内存的数据赋给本地变量.
    m_strFileMap.Format("%s",lpData);

    // 释放映像内存.
    UnmapViewOfFile(lpData);
   
    // 更新数据.
    UpdateData(FALSE);
}

然后在 DataRecvDlg.cpp 中添加消息映射
BEGIN_MESSAGE_MAP(CDataRecvDlg, CDialog)
    //}}AFX_MSG_MAP
    ON_BN_CLICKED(IDC_RECV_CLIPBOARD, OnBnClickedRecvClipboard)
    ON_BN_CLICKED(IDC_RECV_FILEMAP, OnBnClickedRecvFilemap)
    ON_WM_COPYDATA()
    ON_MESSAGE(WM_COMM,OnUserReceiveMsg)
    ON_REGISTERED_MESSAGE(wm_nRegMsg,OnRegReceiveMsg)
    ON_REGISTERED_MESSAGE(wm_nMemMsg,OnRegMemMsg)
END_MESSAGE_MAP()

在 DataRecvDlg.h 中添加响应消息
afx_msg BOOL OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct);
afx_msg LRESULT OnUserReceiveMsg(WPARAM wParam,LPARAM lParam);
afx_msg LRESULT OnRegReceiveMsg(WPARAM wParam,LPARAM lParam);
afx_msg LRESULT OnRegMemMsg(WPARAM wParam,LPARAM lParam);

最后在 DataRecvDlg.cpp 中补全消息相应函数

//使用 WM_COPY 方式进行接收
BOOL CDataRecvDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
{
    m_strCopyData=(LPSTR)pCopyDataStruct->lpData;

    // 获得实际长度的字符串.
    m_strCopyData=m_strCopyData.Left(pCopyDataStruct->cbData);

    // 更新数据.
    UpdateData(FALSE);
    return CDialog::OnCopyData(pWnd, pCopyDataStruct);
}

//使用用户自定义消息的方式进行接收
LRESULT CDataRecvDlg::OnUserReceiveMsg(WPARAM wParam,LPARAM lParam)
{
    m_strUserMsg.Format("%d\n",int(lParam));
    // 更新数据.
    UpdateData(FALSE);
    return TRUE;
}

//使用用户注册消息的方式进行接收
LRESULT CDataRecvDlg::OnRegReceiveMsg(WPARAM wParam,LPARAM lParam)
{
    m_strRegMsg.Format("%d\n",int(lParam));
    // 更新数据.
    UpdateData(FALSE);
    return TRUE;
}

//使用对目标进程内存的访问方式进行接收
LRESULT 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);

    return TRUE;
}

至此,完成接收端

需要注意的是,接收端必须先运行,用户自定义消息、注册消息只能发送长整型的数据,其他方式可以发送字符串数据.使用 内存映射windows剪贴板 进行数据接收时,需要点击按纽才能接收到数据,其他方式会自动接收数据. 发表于 @ 2007年09月05日 23:52:00



Window下使用内存映射文件共享数据的例子源代码本地下载:
文件:Window下使用内存映射文件共享数据的例子 .rar
大小:72KB
下载:下载



阅读(999) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-08-23 11:15:17

Windows 下的进程间通讯及数据共享 http://blog.codingnow.com/2005/10/interprocess_communications.html Windows 下有很多方法实现进程间通讯,比如用 socket,管道(Pipe),信箱(Mailslot),等等。但最基本最直接的还是使用内存共享。其他方法最终还是会绕道这里。 可想而知,如果物理内存只有一份,让这份内存在不同的进程中,映射到各自的虚拟地址空间上,每个进程都可以读取同一份数据,是一种最高效的数据交换方法。下面我们就讨论如何实现它。 共享内存在 Windows 中是用 FileMapping 实现的。我们可以用 CreateFileMapping 创建一个内存文件映射对象, CreateFileMapping 这个 API 将创建一个内核对象,用于映射文件到内存。这里,我们并不需要一个实际的文件,所以,就不需要调用 CreateFile 创建一个文件, hFile 这个参数可以填写 INVALID_HANDLE_VALUE 。但是,文件长度是需要填的。Windows 支

chinaunix网友2010-08-23 11:12:30

内存映射文件实例 http://blog.163.com/liuruigong_lrg/blog/static/2737030620106270353770/ #include "stdafx.h" #include class CReadDataMap { public: CReadDataMap(CString& fname); virtual ~CReadDataMap(); public: //这些都不能被外部改 HANDLE m_hFile; HANDLE m_hFileMap; int m_Size; char* m_pMem; int m_Pos; //读到文件中的位置 public: bool ReadNextString(CString& Word2); bool ReadNextWord(WORD* pInt); bool ReadNextByte(BYTE* c); bool ReadBytes(B