进程间通信

来源:互联网 发布:开通58端口有什么用 编辑:程序博客网 时间:2024/05/17 04:38
通过自定义消息:
局限:发送的数据只能是长整型。
#define WM_COMM      WM_USER+100
CWnd *pWnd=CWnd::FindWindow(NULL,_T("DataRecv查找DataRecv进程.")); //
pWnd->SendMessage(WM_COMM,NULL,(LPARAM)uMsg);// 发送.
 
const UINT wm_nRegMsg=RegisterWindowMessage("reg_data");
CWnd *pWnd=CWnd::FindWindow(NULL,_T("DataRecv")); // 查找DataRecv进程.
pWnd->SendMessage(wm_nRegMsg,NULL,(LPARAM)uMsg);// 发送.
 
接受函数里
#define WM_COMM      WM_USER+100
ON_MESSAGE(WM_COMM,OnUserReceiveMsg)
const UINT wm_nRegMsg=RegisterWindowMessage("reg_data");
ON_REGISTERED_MESSAGE(wm_nRegMsg,OnRegReceiveMsg)
void CDataRecvDlg::OnUserReceiveMsg(WPARAM wParam,LPARAM lParam)
{
         m_strUserMsg.Format("%d/n",int(lParam));
…………………………..
}
 
使用WM_COPYDATA消息:
局限:WM_COPYDATA不能发送HDC、HBITMAP之类的东西。
发送方:
CWnd *pWnd=CWnd::FindWindow(NULL,_T("DataRecv")); // 查找DataRecv进程
       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);// 发送.
接收方:
ON_WM_COPYDATA()
afx_msg BOOL OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct);
BOOL CDataRecvDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
{
       m_strCopyData=(LPSTR)pCopyDataStruct->lpData;
……………..
}
 
使用内存读写函数:
#define BUFFER_SIZE 0x100          // 用内存地址通信时分配的最大内存.
const UINT wm_nMemMsg=RegisterWindowMessage("mem_data");
void  OnSendMem() {
       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);
}
 
接收方:
afx_msg void OnRegMemMsg(WPARAM wParam,LPARAM lParam);
void OnRegMemMsg(WPARAM wParam,LPARAM lParam){
       LPVOID lpBaseAddress=(LPVOID)lParam;
       HANDLE hProcess=GetCurrentProcess();
       char data[BUFFER_SIZE];
       ReadProcessMemory(hProcess, lpBaseAddress, data,BUFFER_SIZE, NULL);
}
 
 
使用内存映射文件:
A和进程B之间共享如下一个struct:
 struct m_MapView_Struct{
 char m_c;
 int m_iMapView;
 char m_pszMapView[MAX_BUFFER_SIZE];
 char m_pszMapView2[MAX_BUFFER_SIZE];
 }* m_pSMapView;
 
进程A中:
m_hMapObject=CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,
PAGE_READWRITE, 0, 0x1000, _TEXT("shared_memory"));
f(!m_hMapObject){
 AfxMessageBox("Unable to create shared memory file.");
 return FALSE;
}
// Map view of file into our address space. m_pSMapView=(m_MapView_Struct *)MapViewOfFile
 (m_hMapObject,FILE_MAP_WRITE, 0, 0,0);// FILE_MAP_ALL_ACCESS
if(m_pSMapView==NULL){
 AfxMessageBox("Unable to map shared memory file.");
 return FALSE;
}
m_pSMapView->m_iMapView = 13628;
m_pSMapView->m_c = '*';
lstrcpy(m_pSMapView->m_pszMapView, "c++");
lstrcpy(m_pSMapView->m_pszMapView2, "stl wlt atl");
UnmapViewOfFile(…);  
 
进程B中:
// Open memory mapped file.
m_hMapObject=OpenFileMapping(FILE_MAP_READ,FALSE,_TEXT("shared_memory"));//
if(!m_hMapObject){
 AfxMessageBox("Can't open shared memory file,please run 'Send' first.");
 SendMessage(WM_CLOSE);
 return FALSE;
}
// Get pointer to shared data.
m_pSMapView=(m_MapView_Struct *)MapViewOfFile (m_hMapObject,FILE_MAP_READ, 0, 0,0);
if(m_pSMapView==NULL)                // FILE_MAP_ALL_ACCESS
 AfxMessageBox("Can't map view of shared memory file.");
m_strText.Format("%d,%s,%s,%c",m_pSMapView->m_iMapView, m_pSMapView->m_pszMapView
,m_pSMapView->m_pszMapView2 ,m_pSMapView->m_c);
UnmapViewOfFile(…);
 
 
使用DLL进行通信:
// DllObj.h:头文件.
#ifndef _DLLOBJ_H__INCLUDED
#define _DLLOBJ_H__INCLUDED
#include <afxmt.h>
 
#ifdef __cplusplus
#define __DLLCOM__ extern "C" __declspec (dllexport)
#else
#define __DLLCOM__ __declspec (dllexport)
#endif
 
__DLLCOM__ LPSTR GetValueString();
__DLLCOM__ void SetValueString(LPCSTR str);
 
#endif
 
; dllcom.def : Declares the module parameters for the DLL.
 
LIBRARY      "dllcom"
DESCRIPTION 'dllcom Windows Dynamic Link Library'
 
EXPORTS
    ; Explicit exports can go here
 
 
dllcom.cpp
#pragma data_seg("SHARED")
char m_strString[256]=TEXT("");
volatile bool bInCriticalSection=FALSE;
#pragma data_seg()
 
#pragma comment(linker,"/SECTION:SHARED,RWS")
 
CCriticalSection cs;
 
// 从内存中读取字符串.
__DLLCOM__ LPSTR GetValueString()
{
         while(bInCriticalSection) // 等待.
                   Sleep(1);
 
         return m_strString;
}
 
// 把字符串存储到共享内存中.
__DLLCOM__ void SetValueString(LPCSTR str)
{
         while(bInCriticalSection) // 等待.
                   Sleep(1);
         cs.Lock();
         bInCriticalSection = TRUE;
         strcpy(m_strString,str);
         bInCriticalSection = FALSE;
         cs.Unlock();
}
 
 
 
使用剪切板进行通信:
//打开系统剪贴板.
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();
 
接收方:
// 打开系统剪贴板.
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();
 
 
 
 
 
 
一下方法既可以用于本地系统上进程间通信,也适用于远程不同系统上进程间通信。
 
使用命名管道进行进程间通信:
命名管道最适合两个进程间的消息传递,如果进程不知道这个管道名就不能取走数据。一方接收到数据之后可以立即通知另一方。
// MyPipe.h: 定义CMyPipe.
#ifndef _MYPIPE_H__INCLUDED
#define _MYPIPE_H__INCLUDED
class CMyPipe
{
public:
         CMyPipe();
         virtual ~CMyPipe();
public:
         static UINT ServerReadProc(LPVOID lpVoid);
         void ServerCreateNamedPipe(CString strReply);
         void ClientSend(CString strRequest);
         int ClientCreateFile();
         void ServerClose();
         void ClienClose();
         CString GetReply()   { return m_strReply;}
    CString GetRequest() { return m_strRequest;}
private:
         CWinThread *m_pThread;
         CString m_strReply;
         CString m_strRequest;
         HANDLE m_hPipe;
};
#endif
 
// MyPipe.cpp: 实现CMyPipe.
#include "stdafx.h"
#include "MyPipe.h"
CMyPipe::CMyPipe()
{m_pThread=NULL;}
CMyPipe::~CMyPipe()
{
         if(m_pThread){
                   if(TerminateThread(m_pThread->m_hThread,0))
                   {
                            if(m_pThread)
                                     delete m_pThread;
                            m_pThread = NULL;
                   }
         }
}
int CMyPipe::ClientCreateFile()
{
         LPCSTR szPipeName=TEXT("////.//pipe//ssnp//");
         if (WaitNamedPipe( szPipeName, NMPWAIT_WAIT_FOREVER)==FALSE ){
                   AfxMessageBox(_T("No existing Pipe can use now"));
                   TRACE("No existing Pipe can use now. Error: %d/n",GetLastError());
                   return 0;
         }
         m_hPipe=CreateFile(szPipeName,
         GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ| FILE_SHARE_WRITE,NULL, OPEN_EXISTING,
        FILE_ATTRIBUTE_ARCHIVE|FILE_FLAG_WRITE_THROUGH, NULL);// FILE_FLAG_WRITE_THROUGH 设定阻塞.
         // 检查并判别命名管道文件是否被打开,如果没有被打开,终止程序.
         if (m_hPipe == INVALID_HANDLE_VALUE){
                   TRACE("Unable to create a named pipe. Error: %d/n",GetLastError());
                   return 0;
         }
         return 1;
}
//---------------------------------------------------------------------------
// 用于客户程序的函数.
void CMyPipe::ClientSend(CString strRequest)
{
         m_strRequest=strRequest;
         char toSendtxt[80];
                   // 反复发送消息直到程序终止.
                   while(1)
                   {
                            TRACE("Sending.../n");
                            DWORD dwNumBytesWritten,dwNumBytesRead;
                            strcpy(toSendtxt,m_strRequest);
                            // 向管道写入消息.
                   if (!WriteFile(m_hPipe,toSendtxt,(DWORD)sizeof(toSendtxt),&dwNumBytesWritten,(LPOVERLAPPED) NULL)){// 如果向命名管道写入时出现错误,终止程序.
                                     TRACE("Unable to write to named pipe. Error: %d/n",GetLastError());
                                     CloseHandle(m_hPipe);
                            }
                            else{ //如果向管道写入消息成功,则执行下面代码
                                     ReadFile(m_hPipe,toSendtxt, (DWORD)sizeof(toSendtxt),
                                               &dwNumBytesRead,(LPOVERLAPPED) NULL);
                                     m_strReply=toSendtxt;
                                     break;
                            }
                            // 在再次发送消息前等待.
                            Sleep(4800);
                   }
}
//---------------------------------------------------------------------------
// 用于服务程序的函数.
void CMyPipe::ServerCreateNamedPipe(CString strReply) {
         m_strReply=strReply;
         LPCSTR szPipeName=TEXT("////.//pipe//ssnp//");
         // 为接收消息创建命名管道.
         m_hPipe=CreateNamedPipe(szPipeName,
                   PIPE_ACCESS_DUPLEX|FILE_FLAG_WRITE_THROUGH,
                   // 阻塞模式.
                   PIPE_WAIT|PIPE_TYPE_BYTE,PIPE_UNLIMITED_INSTANCES,       128,128,NULL,NULL);
         // 检查是否命名管道被创建.
         if (m_hPipe == INVALID_HANDLE_VALUE){
                   TRACE("Unable to create a named pipe./n");return;
         }
         m_pThread=AfxBeginThread(ServerReadProc, this); // 启动线程.
}
//---------------------------------------------------------------------------
UINT CMyPipe::ServerReadProc(LPVOID lpVoid)
{
         DWORD dwNumBytesRead,dwNumBytesWrite;
         char toDisptxt[80];
         // 允许客户连接命名管道,如果不成功,终止.
         TRACE("Waiting for connection... /n");
         CMyPipe *Parent= (CMyPipe*)lpVoid;
         if(!ConnectNamedPipe(Parent->m_hPipe, (LPOVERLAPPED) NULL)){
                   TRACE("Unable to connect a named pipe. Error: %d/n",GetLastError());
                   CloseHandle(Parent->m_hPipe);
                   return 1;
         }
         // 反复检查消息直到程序终止.
         while(1)
         {
                   // 读取消息并检查读取数据是否成功.
                   if (!ReadFile(Parent->m_hPipe, toDisptxt,sizeof(toDisptxt),&dwNumBytesRead, (LPOVERLAPPED) NULL))         {
                            TRACE("Unable to read from named pipe. Error: %d/n" ,GetLastError());
                            CloseHandle(Parent->m_hPipe);
                            //return 1;
                   }
                   else{//如果ReadFile成功,则执行下面代码
                            // 保存接收的字符串.
                            Parent->m_strRequest=toDisptxt;
                            strcpy(toDisptxt,Parent->m_strReply);
                            // 写回一个字符串.
                            WriteFile(Parent->m_hPipe, toDisptxt,sizeof(toDisptxt),
                                   &dwNumBytesWrite, (LPOVERLAPPED) NULL);
                   }
         }
         return 0;
}
void CMyPipe::ServerClose()
{
         DisconnectNamedPipe(m_hPipe);
         CloseHandle(m_hPipe);
         return;
}
void CMyPipe::ClienClose()
{
         //CloseFile();
         return;
}
 
使用邮槽进行进程间通信:
邮槽适合一个进程向多个进程广播消息,其存储的数据可以任何形式,但大小不能超过64K。
当邮槽的所有句柄都关闭后,该邮槽及其中的数据就被删除。邮槽通信是单向UDP发送数据,所以发送前没有建立一个可靠的连接。的,客户端只能写,服务器端只能读。使用
// MyMailSlots.h: 定义CMyMailSlots.
#ifndef _MYMAILSLOTS_H__INCLUDED
#define _MYMAILSLOTS_H__INCLUDED
class CMyMailSlots
{
public:
         CMyMailSlots();
         virtual ~CMyMailSlots();
public:
         static UINT ServerReadProc(LPVOID lpVoid);
         void ServerCreateMailslot();
         void ClientCreateFile();
         void ClientSend(CString strRequest);
//    CString GetReply() { return m_strReply;}
    CString GetRequest() { return m_strRequest;}
private:
//       CString m_strReply;
         CString m_strRequest;
         HANDLE m_hSMS_Slot;
         CWinThread *m_pThread;
};
#endif
// MyMailSlots.cpp: 实现CMyMailSlots.
#include "stdafx.h"
#include "MyMailSlots.h"
CMyMailSlots::CMyMailSlots()
{
         m_pThread = NULL;
}
CMyMailSlots::~CMyMailSlots()
{
         if(m_pThread){
                   if(TerminateThread(m_pThread->m_hThread,0)){
                            if(m_pThread)
                                     delete m_pThread;
                            m_pThread = NULL;
                   }
         }
}
void CMyMailSlots::ClientCreateFile()
{
    LPCSTR szMailslotName= TEXT("////.//mailslot//sms");
         // 为发送消息创建mailslot文件句柄.
         m_hSMS_Slot=CreateFile(szMailslotName,
                   GENERIC_READ|GENERIC_WRITE,
                   FILE_SHARE_READ| FILE_SHARE_WRITE,NULL, OPEN_EXISTING,
        FILE_ATTRIBUTE_ARCHIVE|FILE_FLAG_WRITE_THROUGH,
                   // FILE_FLAG_WRITE_THROUGH 设定阻塞.
                   NULL);
         // 检查mailslot文件是否打开,如果如果没有打开,终止程序.
         if (m_hSMS_Slot == INVALID_HANDLE_VALUE)
                   TRACE("Unable to create mailslot. Error: %d/n", GetLastError());
}
// 用于客户程序的函数.
void CMyMailSlots::ClientSend(CString strRequest)
{
         DWORD bufferLen=100;
         BOOL bStatus;
         DWORD dwNumBytesWritten;
         m_strRequest=strRequest;
         char toSendTxt[100];
         // 生成发送的字符串.
         strcpy(toSendTxt, strRequest);
         TRACE("Sending.../n");
         // mailslot写入信息.
         bStatus=WriteFile(m_hSMS_Slot,toSendTxt, (DWORD) sizeof(toSendTxt),&dwNumBytesWritten, (LPOVERLAPPED) NULL);
         if (!bStatus){
                   TRACE("Unable to write to mailslot. Error: %d/n",GetLastError());
        CloseHandle(m_hSMS_Slot);
         }
}
// 用于服务程序的函数.
void CMyMailSlots::ServerCreateMailslot()
{
    LPCSTR szMailslotName= TEXT("////.//mailslot//sms");
         // 为接收消息创建mailslot.
         m_hSMS_Slot=CreateMailslot(szMailslotName,0,0,(LPSECURITY_ATTRIBUTES) NULL);
         // 检查mailslot是否被创建
         if (m_hSMS_Slot == INVALID_HANDLE_VALUE){
                   TRACE("Unable to create mailslot. Error: %d/n",GetLastError());
                   return;
         }
         m_pThread=AfxBeginThread(ServerReadProc,this); // 启动线程.
}
UINT CMyMailSlots::ServerReadProc(LPVOID lpVoid)
{
         DWORD dwNextSize;
         DWORD dwMsgs;
         DWORD dwNumBytesRead;
         BOOL bStatus;
         char toDisptxt[100];
         CMyMailSlots* Parent=(CMyMailSlots*)lpVoid;
         // 反复检查消息直到程序终止.
         while(1){
                   bStatus=GetMailslotInfo(Parent->m_hSMS_Slot,(LPDWORD) NULL, &dwNextSize, &dwMsgs,
                            (LPDWORD) NULL);
                   if (!bStatus){
                            TRACE("Unable to get status. Error:%d/n",GetLastError());
                            CloseHandle(Parent->m_hSMS_Slot);
                            return 1;
                   }
                   TRACE("%d/n",dwNextSize);
                   // 如果有消息,获取它.
                   if (dwMsgs&&dwNextSize!=-1){
                            // 读取消息并检查读取是否成功.
                            if (!ReadFile(Parent->m_hSMS_Slot, toDisptxt, dwNextSize,
                                     &dwNumBytesRead, (LPOVERLAPPED) NULL)){
                                     TRACE("Unable to read from mailslot. Error: %d/n",GetLastError());
                                     CloseHandle(Parent->m_hSMS_Slot);
                                     return 1;
                            }
                            else{
                                     Parent->m_strRequest=toDisptxt; // 保存消息.
                            }
                   }
                   else
                            Sleep(500); // 每秒钟两次检查新消息.
         }
         return 0;
}


From: http://blog.csdn.net/boyplayee/archive/2007/03/09/1525079.aspx
原创粉丝点击