汇编教程:管道

这一讲将探索一下管道,看看它是什么、有什么用。为使之更加生动有趣,我将用怎样改变 Edit 控件的背景色和文本颜色来说明此技术。

理论:

管道,顾名思义就是有两个端的通道。可以使用管道在进程间、同一进程内进行数据交换,就像手提式无线电话机一样。把管道的一端给另一方,他就可以借助管道和你通讯了。

有两种管道,即有名管道和匿名管道。匿名管道就是没有名字的管道了,也就是说在使用它们时不需要知道其名字。而有名管道正好相反,在使用前必须知道其名字。

也可以根据管道的特性来分类,即是单向的还是双向的。单向管道,数据只能沿一个方向移动,从一端流向另一端,而双向管道数据可以在两端间自由交换。匿名管道通常是单向的而有名管道通常是双向的。有名管道常用于一个服务器联络多个客户端的网络环境。

这一讲将详细讨论一下匿名管道。匿名管道主要目的是作为父进程与子进程、子进程之间通讯的联结通路。在处理控制台问题时,匿名管道是相当有用的。控制台应用程序就是使用控制台作为输入和输出的一种 Win32 应用程序。一个控制台就像一个 DOS 窗口。但控制台应用程序的的确确是32位的应用程序,它可以向其它图形程序一样使用 GUI 函数,只不过它碰巧使用了控制台罢了。

控制台应用程序有三个用于输入输出的标准句柄,它们是标准输入、标准输出和标准错误句柄。标准输入用于从控制台读或取信息而标准输出用于往控制台写或打印信息。标准错误用于汇报输出不能重定向的错误。

控制台应用程序可以通过调用函数 GetStdHandle 来获得这三个句柄。一个图形应用程序没有控制台,如果在其中调用GetStdHandle 就会返回错误;如果的确要使用控制台,可以调用AllocConsole 来分配一个新的控制台以使用,但当处理完成时,别忘了调用 FreeConsole 来释放控制台。
  匿名管道用得最多的功能就是 重定向子进程的标准输入和标准输出。父进程可以是一个控制台或者是图形程序,而子进程必须是控制台应用程序。众所周知,控制台应用使用标准输入输出句柄。若要重定向输入输出,就得用指向管道一端的句柄来替换这个标准句柄。控制台应用程序不会知道我们使用了指向管道任一端的句柄,它会把这个句柄作为标准句柄来看待。借用面向对象的术语,这就是多态性的一种。因为子进程不需作任何改动,因此这种方法是非常有用的。

关于控制台应用程序应该掌握的另一点就是它从哪获得标准句柄。当一个控制台应用程序被创建时,父进程有两种选择:为子进程创建一个新的控制台或者是让子进程继承自己的控制台。若使用后者,那父进程本身必须是一个控制台应用程序,或者如果是 GUI 应用程序,它必须首先调用 AllocConsole 分配了一个控制台。

通过调用 CreatePipe 来创建一个匿名管道,它的原型为:

CreatePipe proto pReadHandle:DWORD, \
pWriteHandle:DWORD,\
pPipeAttributes:DWORD,\
nBufferSize:DWORD

pReadHandle 双字指针变量,指向管道读端的句柄。

pWriteHandle 双字指针变量,指向管道写端的句柄

pPipeAttributes 双字指针变量,指向SECURITY_ATTRIBUTES 结构,其用于决定读写句柄是否可以被子进程继承

nBufferSize 建议管道留给用户使用的缓冲区的大小,这仅仅是个建议值,可以用 NULL 来使用缺省值

如果函数调用成功返回值为非零,否则为零。成功调用之后,就会得到两个句柄,一个指向管道的读出端,另一个指向管道的写入端。现在我将要把重点放到重定向子控制台程序的标准输出到自己进程的所需的步骤上。注意我的这个方法不同于Borland 公司的 API 参考上的例子。Win32 API 参考上假设父进程是控制台应用程序,因此子进程可以继承它的标准句柄。然而大多数情况下我们需要重定向控制台应用程序的输出到 GUI 应用程序。

创建匿名管道使用 CreatePipe ,同时别忘了把 SECURITY_ATTRIBUTES 结构成员bInheritable 设置为TRUE,这样才可以继承句柄。

现在要准备好创建进程的函数即CreateProcess 的参数,只有它才可以装载子控制台应用程序。STARTUPINFO 是一个重要的结构,它决定了子进程出现时主窗口的外观,它对于我们的目标也是至关重要的。通过这个结构就可以隐藏主窗口并且把管道句柄传递给子进程。

以下就是必须要填写的成员:

cb STARTUPINFO结构的大小

dwFlags 二进制标志位,它决定本结构的哪些成员有效,也决定主窗口是显示还是隐藏的状态。在我们的程序中使用STARTF_USESHOWWINDOW 和 STARTF_USESTDHANDLES的组合

hStdOutput 和hStdError 你想要子进程使用的标准输出和标准错误句柄,对我们来说,我们将把管道的写端作为子进程的标准输出和错误。因此当子进程往标准输出或标准错误发送信息时,它实际上把这些信息通过管道传给了父进程

wShowWindow 决定主窗口是显示还是隐藏。我们不希望显示子进程的主窗口,因此把该成员置成SW_HIDE

调用CreateProcess 来创建子进程,但调用成功后子进程仍然不处于激活状态。它被装进了内存但并没有立即运行。

在父进程中关闭管道的写端也是必须的。这是因为父进程并不使用管道的写句柄,而且如果一个管道有两个写入端也就不会工作,因此我们在从管道往外读数据之前必须关闭管道的写端。但是不能在调用CreateProcess 之前关闭,否则管道就坏了。你应当在CreateProcess 刚刚返回并且在读数据之前关闭管道的写端。

现在就可以通过函数ReadFile 在管道的读端读数据了。通过使用ReadFile ,可以使子进程处于运行状态。它将开始执行,并且当它往标准输出( 实际上是管道的写端 )上写数据时,数据就会被送至管道的读端。应当不停调用ReadFile 直至它的返回值为 0 ,也就是说再也没有数据可读了。对从管道读来的数据你可以进行任何处理,在我们的例子中它被显示在 Edit 控件中。
  记得用完后关闭管道的读句柄。

时间: 2024-08-03 15:18:48

汇编教程:管道的相关文章

汇编教程:连接数据源

本教程中,我们将学习使用ODBC APIs的细节. 因为我们的程序并不与ODBC驱动程序直接通信,而是通过ODBC管理器来定义一系列APIs供你的程序调用以完成工作,所以我们需要包含odbc32.inc和odbc32.lib文件,当然还有windows.inc. 连接数据源需要以下几步: 分配一个环境句柄(environment handle). 在进行每个ODBC任务(session)时仅需这样做一次.一旦获得了句柄,我们就可修改环境属性来适合我们的需要.你可以把这想象为在DB工作中创建一个w

汇编教程:控制转移(2)

2.关于实例三的说明 有些步骤的实现方法已在前面的实例中做过介绍,下面就任务内无特权级变换的转移和使用局部描述符LDT等作些说明: (1)实模式下初始化LDT 演示任务使用了局部描述符表LDT,本实例中该LDT在实模式下初始化(当然,也可以在使用LDT前的保护模式初始化).为了简便,LDT中各描述符的界限和属性值在定义时预置,利用一个子程序设置各段的段基地址.为方便起见,在定义时把各段的段值安排在相应描述符的段基地址低16位字段中.由于实例中各段在实模式下定位(这是因为程序是从实模式下启动执行的

汇编教程:虚拟设备驱动程序结构

现在大家对vmm和vxd有了一定的了解,接下来我们来看一看如何编写vxd代码.首先,你必须具备Windows 95/98 Device Driver Development Kit.Window95 ddk只有MSDN 订户才能拿到,但Windows98 ddk却可以免费从Microsoft公司取得.尽管Windows 98 ddk是面向WDM的,但你还是可以用它来开发VxD程序.你可以从 http://www.microsoft.com/hwdev/ddk/install98ddk.htm?下

汇编教程:客户寄存器结构

我们将学习本教程中另外一个重要的结构,叫客户寄存器结构.在本文中,V86指虚拟8086模式.在这里下载例子程序 理论 VxDs与正常的win32/win16/DOS应用程序有很大不同.大多数情况下,当其他应用程序正常工作时,它们是休眠的.它们象一个监管者一样工作,其作用是监视ring-3应用程序并在其出错时改正它们.下面是其工作时的典型的情况: 1.中断发生时 2.VMM得到控制权时 3.VMM存贮寄存器组的值时 4.VMM服务于中断或调用其他VxDs完成此工作时 5.VMM交还控制权给被中断的

汇编教程:ODBC基础

这是使用 win32asm进行数据库编程系列的第一份教程.在如今的IT界,数据库编程变的越来越重要,所以我们不能再忽视它.但如今有很多种数据库在使用,如果我们为了实现win32下数据库汇编语言编程而学习各种数据库文件格式,所花时间大概称得上"永恒". 幸运的是,Microsoft的一项技术使得我们得以摆脱这个大麻烦.它被称为ODBC,是开放式数据库互连(Open Database Connectivity)的缩写,这是一族API,与Windows API相似.它主要与数据库打交道.就是

汇编教程:多文档界面(MDI)

本教程告诉你怎样创建MDI应用程序.事实上并不是很困难. 理论: 多文档界面(MDI)是同一时刻处理多个文档的应用程序的一个规范. 你很熟悉记事本.它是单文档界面(SDI)的一个例子.记事本在一个时候只能处理一个文档.假如你希望打开另一个文档,你首先必须关闭你前面打开的那一个.你可以想象这有多麻烦. 和Microsoft Word相比:Word可以随心所欲的在同一时刻打开任意多个文档,而且可以让用户选择使用哪一个文档.Microsoft Word 是多文档界面(MDI)的一个例子. MDI应用程

汇编教程:Win32调试API(3)

在本章中,我们将继续探讨win32调试api.特别地,我们将学习如何去跟踪被调试程序. 理论: 如果你以前使用过调试器,那么你应对跟踪比较熟悉.当"跟踪"一个程序时,程序在每执行一条指令后将会停止,这使你有机会去检查寄存器/内存中的值.这种单步运行的官方定义为跟踪(tracing). 单步运行的特色是由CPU本身提供的.标志寄存器的第8位称为陷阱标志trap flag.如果该位设置,则CPU运行于单步模式.CPU将在每条指令后产生一个debug异常.当debug 异常产生后,陷阱标志自

汇编教程:Win32调试API(1)

在本教程中,我们将学习Win32提供给开发者的用于调试的原语. 在教程的结尾,我们将学习如何调试一个进程. 理论: Win32有一些供程序员使用的API,它们提供相当于调试器的功能. 他们被称作Win32调试API(或原语).利用这些API,我们可以: 加载一个程序或捆绑到一个正在运行的程序上以供调试 获得被调试的程序的低层信息,例如进程ID,进入地址,映像基址等. 当发生与调试有关的事件时被通知,例如进程/线程的开始/结束, DLL的加载/释放等. 修改被调试的进程或线程 简而言之,我们可以用

汇编教程之基本概念(win32)

我们先假设您已知道了如何使用MASM.如果您还不知道的话,请下载 win32asm.exe ,并请仔细研读其中所附带的文档资料.好,如果您已准备就绪,我们这就开始吧! 理论: WIN32 程序运行在保护模式下的,保护模式的历史可以追溯到 80286.而今 80286 已成为了历史.所以我们将只把精力集中于 80386 及后续的X86 系列 CPU.Windows 把每一个 Win32 应用程序放到分开的虚拟地址空间中去运行,也就是说每一个应用程序都拥有其相互独立的 4GB 地址空间,当然这倒不是