• winows 进程通信的实例详解


    发送端:
    新建一个基本对话框工程,添加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 ",int(lParam));
        // 更新数据.
        UpdateData(FALSE);
        return TRUE;
    }

    //使用用户注册消息的方式进行接收
    LRESULT CDataRecvDlg::OnRegReceiveMsg(WPARAM wParam,LPARAM lParam)
    {
        m_strRegMsg.Format("%d ",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剪贴板 进行数据接收时,需要点击按纽才能接收到数据,其他方式会自动接收数据.

  • 相关阅读:
    5月26号
    5.17 Quartz笔记
    5.23Java各种对象(PO,BO,VO,DTO,POJO,DAO,Entity,JavaBean,JavaBeans)的区分
    5.23@Comfiguration的解释
    5月20号
    5.20
    java与C++不同之处(java不支持特性)
    递归算法之回溯
    0119
    linux打包及备份指令
  • 原文地址:https://www.cnblogs.com/JczmDeveloper/p/3527307.html
Copyright © 2020-2023  润新知