匿名通道,我这里是同步方式,至于异步,好像与OVERLAPPED有关,这里就不多叙述了,我自己也还不是很明白
说下流程
首先在父进程里面创建一个管道,CreatePipe,这个函数第一,二个参数都是传出句柄,用于对管道的读出和写入句柄,第三个参数是安全性描述符,这里就省去了,使用默认的,第四个参数是你要为这个缓冲区分配多少字节的内存,
由于匿名管道只可以实现进程内部,或者父子进程之间的通信。另外你往管道里面些数据,如果两次写入,而为读出,那么管道里将是第一次写入数据,第二次写入作废,读是“破坏性”地去读,也就是你这次读出了数据,瑕疵这数据就不见了,当缓冲去里面没有数据的时候,去读的话,如果没有采用OVERLAPPED技术的话,那么处理机将会处于忙等状态,直到有数据写入时候才会返回,否则会一直处于假死的状态,这中同步方式通信,必然是低效的
对于父,子进程中的读管道操作都是一样的,因为两者都是调用ReadFile与WriteFile,ReadFile,第一个参数是读句柄,后面的参数是要写数据的大小,缓冲区大小,实际读大小,是否用OVERLAPPED技术,如果不用,最后一个参数设置为0
WriteFile第一个参数也是写句柄,发送大小,发送缓冲区,实际发送大小,是否采用OVERLAPPED技术,不用就设置为NULL
那么父进程的句柄如何传递给子进程呢,通过创建进程时候,指定子进程的标准输入输出以及错误句柄,然后子进程通过 hRead = GetStdHandle(STD_INPUT_HANDLE);
std_output_handle,std_error_handle来把进程句柄进行传递,创建子进程时候,是否继承父进程打开的句柄,设置为true,否则子进程无法拿到句柄
这里在说明自己犯的一个错误,我在获得写句柄的时候GetStdHandle穿进去参数用STD_INPUT_HANDLE来给写入句柄,这是错误的,然后写文件的时候就出错了,然后用GetLastError来获得进程的错误信息,发现返回5,意思是访问拒绝,粗心啊,找了半天这个错误
好了贴个图
然后贴上自己代码
父进程中代码
// 剪贴板通信Dlg.cpp : 实现文件
//
#include "stdafx.h"
#include "剪贴板通信.h"
#include "剪贴板通信Dlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// 对话框数据
enum { IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()
// C剪贴板通信Dlg 对话框
C剪贴板通信Dlg::C剪贴板通信Dlg(CWnd* pParent /*=NULL*/)
: CDialog(C剪贴板通信Dlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void C剪贴板通信Dlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(C剪贴板通信Dlg, CDialog)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
ON_BN_CLICKED(IDC_SENDMESSAGE, &C剪贴板通信Dlg::OnBnClickedSendmessage)
ON_BN_CLICKED(IDC_RECVMESSAGE, &C剪贴板通信Dlg::OnBnClickedRecvmessage)
ON_WM_CLOSE()
ON_BN_CLICKED(IDC_CREATE, &C剪贴板通信Dlg::OnBnClickedCreate)
END_MESSAGE_MAP()
// C剪贴板通信Dlg 消息处理程序
BOOL C剪贴板通信Dlg::OnInitDialog()
{
CDialog::OnInitDialog();
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void C剪贴板通信Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void C剪贴板通信Dlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR C剪贴板通信Dlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void C剪贴板通信Dlg::OnBnClickedSendmessage()
{
//#define _unicode
// TODO: 在此添加控件通知处理程序代码
/*//加入提供汉字的支持,SetClipboardData指定文本格式为CF_UNICODETEXT,复制的时候用wcscp
if(this->OpenClipboard())
{
CString str;
wchar_t * pBuf;
EmptyClipboard();
GetDlgItemText(IDC_SEND,str);
//HGLOBAL hClip = GlobalAlloc(GMEM_MOVEABLE,str.GetLength()+1);
HGLOBAL hClip = (wchar_t *)GlobalAlloc(GHND,sizeof(wchar_t) + str.GetLength()*2);
pBuf = (wchar_t*)GlobalLock(hClip);
wcscpy(pBuf,str);
GlobalUnlock(hClip);
SetClipboardData(CF_UNICODETEXT,hClip);
CloseClipboard();
}
else
{
MessageBox(TEXT("@打开剪贴板失败@"));
}*/
//匿名通道写
char recvbuf[100] = "we all like operation system";
DWORD num;
if(!WriteFile(hWrite,recvbuf,strlen(recvbuf)+1,&num,NULL))
{
MessageBox(TEXT("Error In Write File"));
return;
}
//MessageBox(CString(recvbuf));
}
void C剪贴板通信Dlg::OnBnClickedRecvmessage()
{
// TODO: 在此添加控件通知处理程序代码
/*if(OpenClipboard())
{
if(IsClipboardFormatAvailable(CF_UNICODETEXT))
{
HANDLE hClip = GetClipboardData(CF_UNICODETEXT);
wchar_t * pBuf =(wchar_t*) GlobalLock(hClip);
SetDlgItemText(IDC_RECV,pBuf);
}
CloseClipboard();
}*/
//匿名管道通信
char buf[100];
DWORD num;
if(!ReadFile(hRead,buf,100,&num,NULL))
{
MessageBox(TEXT("读取数据失败"));
return;
}
MessageBox(CString(buf));
}
void C剪贴板通信Dlg::OnClose()
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if(hRead)
CloseHandle(hRead);
if(hWrite)
CloseHandle(hWrite);
CDialog::OnClose();
}
void C剪贴板通信Dlg::OnBnClickedCreate()
{
// TODO: 在此添加控件通知处理程序代码
/*SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL ;
sa.bInheritHandle = true;
if(!CreatePipe(&hRead,&hWrite,&sa,0))
{
MessageBox(TEXT("&Error In Create Pipe&"));
return ;
}
STARTUPINFO sui;
PROCESS_INFORMATION pi;
ZeroMemory(&sui,sizeof(STARTUPINFO));
sui.cb = sizeof(STARTUPINFO);
sui.hStdInput = hRead;
sui.hStdOutput = hWrite;
sui.hStdError = GetStdHandle(STD_ERROR_HANDLE);
sui.dwFlags = STARTF_USESTDHANDLES;
if(!CreateProcess(TEXT("..\\Debug\\Child.exe"),NULL,NULL,NULL,true,0,NULL,NULL,&sui,&pi))
{
DWORD ni= GetLastError();
MessageBox(TEXT("Error In Create Process"));
CloseHandle(hRead);
CloseHandle(hWrite);
hRead = NULL;
hWrite = NULL;
return ;
}
else
{
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}*/
SECURITY_ATTRIBUTES sa;
sa.bInheritHandle = true;
sa.lpSecurityDescriptor = NULL;
sa.nLength =sizeof(SECURITY_ATTRIBUTES);
if(!CreatePipe(&hRead,&hWrite,&sa,0))
{
MessageBox(_T("创建管道失败!"));
return;
}
//NULL
STARTUPINFO sui;
PROCESS_INFORMATION pi;
ZeroMemory(&sui,sizeof(STARTUPINFO));
sui.cb = sizeof(STARTUPINFO);
sui.dwFlags =STARTF_USESTDHANDLES;
sui.hStdInput =hRead;
sui.hStdOutput =hWrite;
sui.hStdError =GetStdHandle(STD_ERROR_HANDLE);
if(!CreateProcess(_T("..\\Debug\\child.exe"),NULL,NULL,NULL,TRUE,0,NULL,NULL,&sui,&pi))
{
int s = GetLastError();
CloseHandle(hRead);
CloseHandle(hWrite);
hRead = NULL;
hWrite =NULL;
MessageBox(_T("创建进程失败!"));
return;
}
else
{
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
}
子进程中的代码
// ChildDlg.cpp : 实现文件
//
#include "stdafx.h"
#include "Child.h"
#include "ChildDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// 对话框数据
enum { IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()
// CChildDlg 对话框
CChildDlg::CChildDlg(CWnd* pParent /*=NULL*/)
: CDialog(CChildDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
hRead = NULL;
hWrite = NULL;
}
void CChildDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CChildDlg, CDialog)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
ON_BN_CLICKED(IDC_READ, &CChildDlg::OnBnClickedRead)
ON_BN_CLICKED(IDC_WRITE, &CChildDlg::OnBnClickedWrite)
ON_WM_CLOSE()
ON_WM_CREATE()
END_MESSAGE_MAP()
// CChildDlg 消息处理程序
BOOL CChildDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void CChildDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CChildDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CChildDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CChildDlg::OnBnClickedRead()
{
// TODO: 在此添加控件通知处理程序代码
char buf[100];
DWORD num;
if(!ReadFile(hRead,buf,100,&num,NULL))
{
MessageBox(TEXT("读取数据失败"));
return;
}
MessageBox(CString(buf));
}
void CChildDlg::OnBnClickedWrite()
{
// TODO: 在此添加控件通知处理程序代码
/*char buf[]= "we all like operation";
DWORD num;
if(!WriteFile(hWrite,buf,strlen(buf)+1,&num,NULL))
{
DWORD dw = GetLastError();
CString str;
str.Format(TEXT("%u"),dw);
MessageBox(str);
//MessageBox(TEXT("Error In Write File"));
return;
}
//MessageBox(CString(buf));*/
char pBuf[]="hello world!";
DWORD dwWrite;
if(!WriteFile(hWrite,pBuf,strlen(pBuf)+1,&dwWrite,NULL))
{
MessageBox(TEXT("读取数据失败!"));
return;
}
}
void CChildDlg::OnClose()
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if(hRead)
CloseHandle(hRead);
if(hWrite)
CloseHandle(hWrite);
CDialog::OnClose();
}
int CChildDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDialog::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: 在此添加您专用的创建代码
hRead = GetStdHandle(STD_INPUT_HANDLE);
hWrite = GetStdHandle(STD_OUTPUT_HANDLE);
return 0;
}
OK ,that' all ,今天考六级,蛋疼啊,后面还有三门课程和一个项目,注定蛋筒 啊,苦逼的娃子啊