• MSDN介绍

CreatePipe

A pipe is a section of shared memory that processes use for communication. The process that creates a pipe is the pipe server. A process that connects to a pipe is a pipe client. One process writes information to the pipe, then the other process reads the information from the pipe. This overview describes how to create, manage, and use pipes.

管 道(Pipe)实际是用于进程间通信的一段共享内存,创建管道的进程称为管道服务器,连接到一个管道的进程为管道客户机。一个进程在向管道写入数据后,另 一进程就可以从管道的另一端将其读取出来。匿名管道(Anonymous Pipes)是在父进程和子进程间单向传输数据的一种未命名的管道,只能在本地计算机中使用,而不可用于网络间的通信。
BOOL WINAPI CreatePipe(_Out_    PHANDLE               hReadPipe,_Out_    PHANDLE               hWritePipe,_In_opt_ LPSECURITY_ATTRIBUTES lpPipeAttributes,_In_     DWORD                 nSize
);

Return value

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

CreatePipe creates the pipe, assigning the specified pipe size to the storage buffer. CreatePipe also creates handles that the process uses to read from and write to the buffer in subsequent calls to the ReadFile and WriteFile functions.

To read from the pipe, a process uses the read handle in a call to the ReadFile function. ReadFile returns when one of the following is true: a write operation completes on the write end of the pipe, the number of bytes requested has been read, or an error occurs.

When a process uses WriteFile to write to an anonymous pipe, the write operation is not completed until all bytes are written. If the pipe buffer is full before all bytes are written, WriteFile does not return until another process or thread uses ReadFile to make more buffer space available.

Anonymous pipes are implemented using a named pipe with a unique name. Therefore, you can often pass a handle to an anonymous pipe to a function that requires a handle to a named pipe.

If CreatePipe fails, the contents of the output parameters are indeterminate. No assumptions should be made about their contents in this event.

To free resources used by a pipe, the application should always close handles when they are no longer needed, which is accomplished either by calling the CloseHandle function or when the process associated with the instance handles ends. Note that an instance of a pipe may have more than one handle associated with it. An instance of a pipe is always deleted when the last handle to the instance of the named pipe is closed.

CreateProcess

Creates a new process and its primary thread. The new process runs in the security context of the calling process.
BOOL WINAPI CreateProcess(_In_opt_    LPCTSTR               lpApplicationName,_Inout_opt_ LPTSTR                lpCommandLine,_In_opt_    LPSECURITY_ATTRIBUTES lpProcessAttributes,_In_opt_    LPSECURITY_ATTRIBUTES lpThreadAttributes,_In_        BOOL                  bInheritHandles,_In_        DWORD                 dwCreationFlags,_In_opt_    LPVOID                lpEnvironment,_In_opt_    LPCTSTR               lpCurrentDirectory,_In_        LPSTARTUPINFO         lpStartupInfo,_Out_       LPPROCESS_INFORMATION lpProcessInformation
);

  • 先简单介绍一下重定向

stdin是标准输入,stdout是标准输出,stderr是标准错误输出。大多数的命令行程序从stdin输入,输出到stdout或 stderr,有时我们需要重定向stdout,stderr,stdin。比如:将输出写入文件,又或者我们要将命令行程序输出结果显示到 Windows对话框中。

在Windows编程中,重定向需要用到管道(Pipe)的概念。管道是一种用于在进程间共享数据的机制。一个管道类似于一个管子的两端,一端是写入的,一端是读出的。由一个进程从写入端写入、另一个进程从读出端读出,从而实现通信,就向一个“管道”一样。

重定向的原理是:

首先声明两个概念:主程序(重定向的操纵者)、子进程(被重定向的子进程)

如果要重定位stdout的话,先生成一个管道, 管道的写入端交给子进程去写,主程序从管道的读出端读数据,然后可以把数据写成文件、显示等等。重定向stderr和stdout是相同的。

同理,要重定向stdin的话,生成一个管道, 管道的写入端由主程序写,子进程从管道的读出端读数据。

其中需要用到几个Windows API :  CreatePipe, DuplicateHandle, CreateProcess, ReadFile, WriteFile 等,函数详解可参见MSDN.

比如一个控制台程序打印一行文字:

会在windows弹出的对话框中输出:

为什么会输出到这里而不是别的地方呢?因为这里就是所说的StdOut(标准输出)的地方。如果你想输出到别的地方,那就得把stdout重定向到别的地方才行。

比如,某网友写了一个重定向程序将stdout重定向到自己写的一个窗口中,就会产生如下的效果:

  • 先详细介绍一下管道,这里以匿名管道为例:

第一:匿名管道只能实现本地进程之间的通信,不能实现跨网络之间的进程间的通信。

第二:匿名管道只能实现父进程和子进程之间的通信,而不能实现任意两个本地进程之间的通信。

匿名管道主要用于本地父进程和子进程之间的通信,在父进程中的话,首先是要创建一个匿名管道,在创建匿名管道成功后,可以获取到对这个匿名管道的读写句柄,然后父进程就可以向这个匿名管道中写入数据和读取数据了,但是如果要实现的是父子进程通信的话,那么还必须在父进程中创建一个子进程,同时,这个子进程必须能够继承和使用父进程的一些公开的句柄,因为在子进程中必须要使用父进程创建的匿名管道的读写句柄,通过这个匿名管道才能实现父子进程的通信,所以必须继承父进程的公开句柄。同时在创建子进程的时候,必须将子进程的标准输入句柄设置为父进程中创建匿名管道时得到的读管道句柄,将子进程的标准输出句柄设置为父进程中创建匿名管道时得到的写管道句柄。然后在子进程就可以读写匿名管道了。

  • 下面来讲CreatePipe:

CreatePipe时会获取两个句柄,一个是读句柄,一个是写句柄(这里的读句柄表示要从哪里读取数据,写句柄表示要把数据写到哪里)。

父进程可以调用进程创建函数CreateProcess()生成子进程。如果父进程要发送数据到子进程,父进程可调用WriteFile()将数据写入到管 道(传递管道写句柄给函数),子进程则调用GetStdHandle()取得管道的读句柄,将该句柄传入ReadFile()后从管道读取数据。(如果是父进程从子进程读取数据,那么由子进程调用GetStdHandle()取得管道的写入句柄,并调用WriteFile()将数据写入到管道。然后,父进程调用ReadFile()从管道读取出数据(传递管道读句柄给函数))//GetStdHandle()是由子进程调用

在 用WriteFile()函数向管道写入数据时,只有在向管道写完指定字节的数据后或是在有错误发生时函数才会返回。如管道缓冲已满而数据还没有写 完,WriteFile()将要等到另一进程对管道中数据读取以释放出更多可用空间后才能够返回。管道服务器在调用CreatePipe()创建管道时以 参数nSize对管道的缓冲大小作了设定。
匿名管道并不支持异步读、写操作,这也就意味着不能在匿名管道中使用ReadFileEx()和WriteFileEx()(它只能用于异步读写文件操作,异步操作完成后会调用指定的回调函数),而且ReadFile() 和WriteFile()中的lpOverLapped参数也将被忽略。匿名管道将在读、写句柄都被关闭后退出,也可以在进程中调用 CloseHandle()函数来关闭此句柄(个人理解就是,匿名管道,只能是你全部往管道中读写完之前,就不能干别的事,只能写或等待(管道满的时候处在等待状态);而子进程在全部接收完管道的数据之前也只能读或等待(没数据时等待),也不能去干其它的事)。

根据上边API的原型,通过hReadPipe和hWritePipe所指向的句柄可分别以只读、只写的方式去访问管道。在使用匿名管道通信时,服务器进程(父进程)必须将其中的一个句柄传送给客户机进程。句柄的传递多通过继承来完成(如何继承?请往下看),服务器进程也允许这些句柄为子进程所继承。

在调用CreatePipe()函数时,如果管道服务器将lpPipeAttributes 指向的SECURITY_ATTRIBUTES数据结构的数据成员bInheritHandle设置为TRUE,那么CreatePipe()创建的管道读、写句柄将会被继承(管道服务器可调用DuplicateHandle()函数改变管道句柄的继承。管道服务器可以为一个可继承的管道句柄创建一个不可 继承的副本或是为一个不可继承的管道句柄创建一个可继承的副本。CreateProcess()函数还可以使管道服务器有能力决定子进程对其可继承句柄是 全部继承还是不继承)。

在生成子进程之前,父进程首先调用Win32 API SetStdHandle()使子进程、父进程可共用标准输入、标准输出和标准错误句柄(StdOut、StdIn、StdErr)。当父进程向子进程发送数据时,用SetStdHandle()将 管道的读句柄赋予标准输入句柄(这样就不会从标准输入读入数据,而从读句柄所表示的位置读取数据);在从子进程接收数据时,则用SetStdHandle()将管道的写句柄赋予标准输出(或标准错误)句柄。然后,父进程可以调用进程创建函数CreateProcess()生成子进程。如果父进程要发送数据到子进程,父进程可调用WriteFile()将数据写入到管道(传 递管道写句柄给函数),子进程则调用GetStdHandle()取得管道的读句柄,将该句柄传入ReadFile()后从管道读取数据。//SetStdHandle()是由父进程调用

  • 举例:
#include <iostream>
#include <windows.h>
#include <Shlwapi.h>using namespace std;#define BUFSIZE 4096int main()
{BOOL bRet = FALSE;DWORD dwRead = 0;DWORD dwAvail = 0;char cbBuf[4096] = { 0 };HANDLE hReadPipe = NULL;HANDLE hWritePipe = NULL;SECURITY_ATTRIBUTES sa;sa.nLength = sizeof(sa);sa.bInheritHandle = TRUE;sa.lpSecurityDescriptor = NULL;char *pCommandLine = new TCHAR[0x200];//
    char szPath[] = "C:\\Windows\\System32\\calc.exe";CreatePipe(&hReadPipe, &hWritePipe, &sa, 0);STARTUPINFO si = { 0 };si.cb = sizeof(STARTUPINFO);GetStartupInfo(&si);si.wShowWindow = SW_HIDE;si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;si.hStdError = hWritePipe;si.hStdOutput = hWritePipe;PROCESS_INFORMATION   pi = { 0 };memset(pCommandLine, 0, sizeof(szPath));lstrcpy(pCommandLine, szPath);if (!CreateProcess(NULL, pCommandLine, NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi))//创建子进程
    {if (pCommandLine)delete pCommandLine;CloseHandle(pi.hProcess);CloseHandle(pi.hThread);CloseHandle(hReadPipe);CloseHandle(hWritePipe);return 1;}std::string strResult;do{cout << "test.." << endl;if (!PeekNamedPipe(hReadPipe, NULL, NULL, &dwRead, &dwAvail, NULL) || dwAvail <= 0)//PeekNamePipe用来预览一个管道中的数据,用来判断管道中是否为空
        {break;}if (ReadFile(hReadPipe, cbBuf, BUFSIZE, &dwRead, NULL))//这里是读管道,即便已经没有数据,仍然会等待接收数据,因为,子进程会认为父进程仍有数据要发送,只是暂时没法送,{                                                        //所以,会“卡”在这里。所以才需要PeekNamePipeif (dwRead == 0)break;cout << dwRead << endl;cout << cbBuf << endl;}} while (TRUE);if (pCommandLine)delete pCommandLine;cout << "delete" << endl;CloseHandle(pi.hProcess);CloseHandle(pi.hThread);CloseHandle(hReadPipe);CloseHandle(hWritePipe);return 0;
}

  • 参考:
MSDN:https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499%28v=vs.85%29.aspx
http://qiusuoge.com/11496.html
http://www.cnblogs.com/vicsmb/archive/2012/02/03/2337049.html
一篇比较好的参考文章:
http://www.cnblogs.com/BoyXiao/archive/2011/01/01/1923828.html

转载于:https://www.cnblogs.com/predator-wang/p/4786253.html

WindowsAPI 之 CreatePipe、CreateProcess相关推荐

  1. C++ MFC常用函数(转)

    WinExec() ExitWindowsEx() GlobalMemoryStatus() GetSystemInfo() GetSystemDirectory() GetWindowsDirect ...

  2. 易语言服务器php,易语言PHP服务器源码

    易语言PHP服务器源码系统结构:监听服务,编码转换程序,进制转换,取页面地址,取域名,取端口,取指定内容中间,取文本之间,取文本之后,ChrW,十到十六,到十六进制文本,去除首部零,URL编码_UTF ...

  3. 怎样在windows环境中启动某控制台程序并改变它的stdin、stdout和stderr? http://book.77169.org/ask18/how106297.htm

    ? MSDN里面有一些文档可以看看,方法是利用CreateProcess的 LPSTARTUPINFO 参数, 设置dwFlags为STARTF_USESTDHANDLES: 然后自定义: HANDL ...

  4. Windows API Reference for C#, VB.NET

    不错的.net 下用API的参考站点 地址在:http://www.webtropy.com/articles/Win32-API-DllImport-art9.asp 下面摘抄分类,便于大家直接就拿 ...

  5. API函数的中文说明及所有的32位WindowsAPI函数的定义

    API函数的中文说明及所有的32位WindowsAPI函数的定义 ============================API函数的中文说明============================= ...

  6. CreatePipe匿名管道通信

    管道(Pipe)实际是用于进程间通信的一段共享内存,创建管道的进程称为管道服务器,连接到一个管道的进程为管道客户机.一个进程在向管道写入数据后,另一进程就可以从管道的另一端将其读取出来.匿名管道(An ...

  7. 管道(Pipe)/createPipe

    BOOL CreatePipe(PHANDLE hReadPipe, // 指向读句柄的指针 PHANDLE hWritePipe, // 指向写句柄的指针 LPSECURITY_ATTRIBUTES ...

  8. CreateProcess 执行CMD命令,并重定向输出

    1. 参考网址:http://www.cnblogs.com/cnarg/archive/2011/02/20/1959292.html 1 function TfrmMain.ExecDosCmd ...

  9. WindowsAPI函数大全

    Api函数名 函数说明 WIN16可用 WIN95可用 WINNT可用 AbortDoc 终止一项打印作业 是 是 是 AbortPath 终止或取消DC中的一切路径 否 是 是 AbortPrint ...

  10. CreateProcess()接收程序的输出

    环境:win10 64位,vs2015 mfc程序 目的:记录CreateProcess()接收启动程序的输出.注:cmd程序,而不是带ui的程序 起始原由:通过调用git工具来完成自己的一些需求 参 ...

最新文章

  1. 人工智能正在向具有“高情商”发展
  2. MySQL死锁如何处理
  3. [html] web workers有用过吗?能帮我们解决哪些问题?
  4. 命令行部署程序保存pid到文件
  5. IP互动电视的坚强后盾
  6. bzoj 1396: 识别子串 bzoj 2865: 字符串识别【后缀数组+线段树】
  7. linux的IO调度算法和回写机制
  8. mysql批量插入死锁的问题
  9. C++ Primer 第五版 课后章节练习答案 第九章
  10. 一部手机背后的小镇青年:吃着蜜糖、喝着毒药
  11. 人工神经网络—神经元的数学模型
  12. 单一窗口关区备案_【亚东关务】单一窗口集中申报来了,集报备案、集报清单详细操作手册...
  13. SpringBoot 与 Kotlin 完美交融
  14. php解析psd文件,PSD解析工具实现(二)
  15. Sentiment140数据集
  16. 设备管理是对计算机什么的系统管理,什么是指对计算机系统所有的外部设备的管理...
  17. 我的创作纪念日---祈愿
  18. 解决Mac苹果电脑没有声音,喇叭会显示为灰色禁用状态
  19. 坎坎坷坷的深度学习之路(一)-环境搭建
  20. 什么是HTTP/2?HTTP/2和HTTP/1.1区别是什么?

热门文章

  1. 数据库约束六大约束语句
  2. 如何将图片素材转为矢量图?
  3. web 网页设计规范介绍
  4. Zynq-Linux移植学习笔记之13-i2c驱动配置
  5. Ubuntu16.04安装百度网盘亲测可用
  6. 服务器v1v2v3v4性能区别,昂达平板电脑V1V2V3V4V5版本之间的区别
  7. 【Python古诗词鉴赏小程序】千古绝唱,精选中国最美古诗句,经典咏流传~
  8. 计划策略(planning strategy)
  9. 根据后缀名/扩展名获取content-type/Mime类型
  10. 《信息物理融合系统(CPS)设计、建模与仿真——基于 Ptolemy II 平台》——第1章 异构建模 1.1语法、语义、语用...