news 2026/4/15 19:42:02

汇编语言全接触-68.Win32汇编教程十二

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
汇编语言全接触-68.Win32汇编教程十二

在这儿下载本节的所有源程序

概述

Windows 引入了多进程和多线程机制。同时也提供了多个进程之间的通信手段,包括剪贴板、DDE、OLE、管道等,和其他通信手段相比,管道有它自己的限制和特点,管道实际上是一段共享内存区,进程把共享消息放在那里。并通过一些 API 提供信息交换。

管道是两个头的东西,每个头各连接一个进程或者同一个进程的不同代码,按照管道的类别分有两种管道,匿名的和命名的;按照管道的传输方向分也可以分成两种,单向的双向的。根据管道的特点,命名管道通常用在网络环境下不同计算机上运行的进程之间的通信(当然也可以用在同一台机的不同进程中)它可以是单向或双向的;而匿名管道只能用在同一台计算机中,它只能是单向的。匿名管道其实是通过用给了一个指定名字的有名管道来实现的。

使用管道的好处在于:读写它使用的是对文件操作的 api,结果操作管道就和操作文件一样。即使你在不同的计算机之间用命名管道来通信,你也不必了解和自己去实现网络间通信的具体细节。

我们简单的介绍一下命名管道的使用。

命名管道是由服务器端的进程建立的,管道的命名必须遵循特定的命名方法,就是 "\\.\pipe\管道名",当作为客户端的进程要使用时,使用"\\计算机名\\pipe\管道名" 来打开使用,具体步骤如下:

服务端通过函数 CreateNamedPipe 创建一个命名管道的实例并返回用于今后操作的句柄,或为已存在的管道创建新的实例。

服务端侦听来自客户端的连接请求,该功能通过 ConnectNamedPipe 函数实现。

客户端通过函数 WaitNamedPipe 来等待管道的出现,如果在超时值变为零以前,有一个管道可以使用,则 WaitNamedPipe 将返回 True,并通过调用 CreateFile 或 CallNamedPipe 来呼叫对服务端的连接。

此时服务端将接受客户端的连接请求,成功建立连接,服务端 ConnectNamedPipe 返回 True

建立连接之后,客户端与服务器端即可通过 ReadFile 和 WriteFile,利用得到的管道文件句柄,彼此间进行信息交换。

当客户端与服务端的通信结束,客户端调用 CloseFile,服务端接着调用 DisconnectNamedPipe。最后调用函数CloseHandle来关闭该管道。

由于命名管道使用时作为客户端的程序必须知道管道的名称,所以更多的用在同一“作者”编写的服务器/工作站程序中,你不可能随便找出一个程序来要求它和你写的程序来通过命名管道通信。而匿名管道的使用则完全不同,它允许你和完全不相干的进程通信,条件是这个进程通过控制台“console”来输入输出,典型的例子是老的 Dos 应用程序,它们在运行时 Windows 为它们开了个 Dos 窗口,它们的输入输出就是 console 方式的。还有一些标准的 Win32 程序也使用控制台输入输出,如果在 Win32 编程中不想使用图形界面,你照样可以使用 AllocConsole 得到一个控制台,然后通过 GetStdHandle 得到输入或输出句柄,再通过 WriteConsole 或 WriteFile 把结果输出到控制台(通常是一个象 Dos 窗口)的屏幕上。虽然这些程序看起来象 Dos 程序,但它们是不折不扣的 Win32 程序,如果你在纯 Dos 下使用,就会显示“The program must run under Windows!”。

一个控制台有三个句柄:标准输入、标准输出和和标准错误句柄,标准输入、标准输出句柄是可以重新定向的,你可以用匿名管道来代替它,这样一来,你可以在管道的另一端用别的进程来接收或输入,而控制台一方并没有感到什么不同,就象 Dos 下的 > 或者 < 可以重新定向输出或输入一样。通常控制台程序的输入输出如下:

(控制台进程output) write ----> 标准输出设备(一般是屏幕)

(控制台进程input) read <---- 标准输入设备(一般是键盘)

而用管道代替后:

(作为子进程的控制台进程output) write ----> 管道1 ----> read (父进程)

(作为子进程的控制台进程input) read <----> 管道2 <---- write (父进程)

使用匿名管道的步骤如下:

使用 CreatePipe 建立两个管道,得到管道句柄,一个用来输入,一个用来输出

准备执行控制台子进程,首先使用 GetStartupInfo 得到 StartupInfo

使用第一个管道句柄代替 StartupInfo 中的 hStdInput,第二个代替 hStdOutput、hStdError,即标准输入、输出、错误句柄

使用 CreateProcess 执行子进程,这样建立的子进程输入和输出就被定向到管道中

父进程通过 ReadFile 读第二个管道来获得子进程的输出,通过 WriteFile 写第一个管道来将输入写到子进程

父进程可以通过 PeekNamedPipe 来查询子进程有没有输出

子进程结束后,要通过 CloseHandle 来关闭两个管道。

下面是具体的说明和定义:

1. 建立匿名管道使用 CreatePipe 原形如下:

BOOL CreatePipe(

PHANDLE hReadPipe, // address of variable for read handle

PHANDLE hWritePipe, // address of variable for write handle

LPSECURITY_ATTRIBUTES lpPipeAttributes, // pointer to security attributes

DWORD nSize // number of bytes reserved for pipe

);

当管道建立后,结构中指向的 hReadPipe 和 hWritePipe 可用来读写管道,当然由于匿名管道是单向的,你只能使用其中的一个句柄,参数中的 SECURITY_ATTRIBUTES 的结构必须填写,定义如下:

typedef struct_SECURITY_ATTRIBUTES{

DWORD nLength: //定义以字节为单位的此结构的长度

LPVOID lpSecurityDescriptor; //指向控制这个对象共享的安全描述符,如果为NULL这个对象将被分配一个缺省的安全描述

BOOL bInheritHandle; //当一个新过程被创建时,定义其返回是否是继承的.供系统API函数使用.

}SECURITY_ATTRIBUTES;

2. 填写创建子进程用的 STARTUPINFO 结构,一般我们可以先用 GetStartupInfo 来填写一个缺省的结构,然后改动我们用得到的地方,它们是:

hStdInput -- 用其中一个管道的 hWritePipe 代替

hStdOutput、hStdError -- 用另一个管道的 hReadPipe 代替

dwFlags -- 设置为 STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW 表示输入输出句柄及 wShowWindow 字段有效

wShowWindow -- 设置为 SW_HIDE,这样子进程执行时不显示窗口。

填写好以后,就可以用 CreateProcess 来执行子进程了,具体有关执行子进程的操作可以参考上一篇教程《进程控制》

3. 在程序中可以用 PeekNamedPipe 查询子进程有没有输出,原形如下:

BOOL PeekNamedPipe(

HANDLE hNamedPipe, // handle to pipe to copy from

LPVOID lpBuffer, // pointer to data buffer

DWORD nBufferSize, // size, in bytes, of data buffer

LPDWORD lpBytesRead, // pointer to number of bytes read

LPDWORD lpTotalBytesAvail, // pointer to total number of bytes available

LPDWORD lpBytesLeftThisMessage // pointer to unread bytes in this message

);

我们可以将尝试读取 nBuffersize 大小的数据,然后可以通过返回的 BytesRead 得到管道中有多少数据,如果不等于零,则表示有数据可以读取。

4. 用 ReadFile 和 WriteFile 来读写管道,它们的参数是完全一样的,原形如下:

ReadFile or WriteFile(

HANDLE hFile, // handle of file to read 在这里使用管道句柄

LPVOID lpBuffer, // address of buffer that receives data 缓冲区地址

DWORD nNumberOfBytesToRead, // number of bytes to read 准备读写的字节数

LPDWORD lpNumberOfBytesRead, // address of number of bytes read,实际读到的或写入的字节数

LPOVERLAPPED lpOverlapped // address of structure for data 在这里用 NULL

);

5. 用 CloseHandle 关闭管道一和管道二的 hReadPipe和 hWritePipe 这四个句柄。

下面给出了一个例子程序,这个程序是上篇教程《进程控制》的例子的扩充,如果你对有的 api 感到陌生的话,请先阅读上一篇教程。

源程序 - 汇编源文件

DEBUG equ 0

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; Programmed by 罗云彬, bigluo@telekbird.com.cn

; Website: http://asm.yeah.net

; LuoYunBin's Win32 ASM page (罗云彬的编程乐园)

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; 版本信息

; 汇编教程附带例子程序 - 管道例子

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

.386

.model flat, stdcall

option casemap :none ; case sensitive

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; Include 数据

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

include windows.inc

include user32.inc

include kernel32.inc

include comctl32.inc

include comdlg32.inc

include gdi32.inc

includelib user32.lib

includelib kernel32.lib

includelib comctl32.lib

includelib comdlg32.lib

includelib gdi32.lib

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; Equ 数据

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

ICO_MAIN equ 1000

MENU_MAIN equ 2000

IDM_EXEC equ 2001

IDM_EXIT equ 2002

F_RUNNING equ 0001h ;进程在运行中

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; 数据段

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

.data?

stStartUp STARTUPINFO <?>

hInstance dd ?

hMenu dd ?

hWinMain dd ?

hWinText dd ?

hFont dd ?

hRunThread dd ?

hRead1 dd ?

hWrite1 dd ?

hRead2 dd ?

hWrite2 dd ?

szBuffer db 512 dup (?)

dwFlag dd ?

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

.data

szMenuExecute db '连接 MS-&DOS 方式',0

szExcuteError db '启动应用程序错误!',0

szCaption db '管道示例程序 ... http://asm.yeah.net',0

szClassName db 'PipeExample',0

;szDllName db 'riched32.dll',0

;szClassNameRedit db 'RichEdit',0

szDllName db 'riched20.dll',0

szClassNameRedit db 'richedit20a',0

szCommand db 'c:\command.com',0

stLogFont LOGFONT <24,0,0,0,FW_NORMAL,\

0,0,0,ANSI_CHARSET,OUT_DEFAULT_PRECIS,\

CLIP_STROKE_PRECIS,DEFAULT_QUALITY,\

DEFAULT_PITCH or FF_SWISS,"Fixedsys">

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; 代码段

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

.code

if DEBUG

include Debug.asm

endif

include Win.asm

;********************************************************************

; 执行程序用的线程

; 1. 用 CreateProcess 建立进程

; 2. 用 WaitForSingleOject 等待进程结束

;********************************************************************

_RunThread proc uses ebx ecx edx esi edi,\

dwParam:DWORD

local @stSecurity:SECURITY_ATTRIBUTES

local @dwExitCode

local @dwBytesRead

local @stRange:CHARRANGE

or dwFlag,F_RUNNING

;********************************************************************

; “执行”菜单改为“结束”

;********************************************************************

invoke EnableMenuItem,hMenu,IDM_EXEC,MF_GRAYED

invoke

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 13:45:48

GLM-TTS采样率对比测试:24kHz和32kHz音质与速度权衡

GLM-TTS采样率对比测试&#xff1a;24kHz和32kHz音质与速度权衡 在语音合成系统日益深入日常应用的今天&#xff0c;一个看似微小的技术参数——采样率&#xff0c;正悄然影响着用户体验的边界。无论是智能客服中的一句应答&#xff0c;还是有声书中长达数小时的情感叙述&#…

作者头像 李华
网站建设 2026/4/16 11:57:49

GLM-TTS情感迁移机制剖析:如何通过参考音频传递情绪特征

GLM-TTS情感迁移机制剖析&#xff1a;如何通过参考音频传递情绪特征 在虚拟主播深夜播报新闻时&#xff0c;声音里带着一丝疲惫的沙哑&#xff1b;客服机器人提醒还款时&#xff0c;语气中透出恰到好处的关切——这些不再是精心标注数据训练出的固定模式&#xff0c;而是模型“…

作者头像 李华
网站建设 2026/4/16 11:59:58

PHP分库分表数据迁移核心技术解析(附真实迁移案例)

第一章&#xff1a;PHP分库分表数据迁移核心技术解析&#xff08;附真实迁移案例&#xff09;在高并发、大数据量的业务场景下&#xff0c;单库单表架构难以支撑系统性能需求&#xff0c;分库分表成为常见解决方案。当系统需要进行数据迁移时&#xff0c;如何保证数据一致性、迁…

作者头像 李华
网站建设 2026/4/16 3:14:22

AI Agent:程序员和普通人,在AI落地迷茫中的最佳选择!

2025年&#xff0c;AI智能体&#xff08;Agent&#xff09;已成为企业智能化转型的核心引擎&#xff0c;人才缺口高达百万级。从WAIC 2025世界人工智能大会到各大厂重磅产品&#xff0c;AI Agent正从“被动应答”走向“主动执行”&#xff0c;开启“我说AI做”的新时代。 一、…

作者头像 李华
网站建设 2026/4/15 15:01:28

揭秘PHP跨域预检请求:99%开发者忽略的5个关键细节

第一章&#xff1a;PHP跨域预检请求的本质解析当浏览器向不同源的服务器发起某些类型的 HTTP 请求时&#xff0c;会自动触发 CORS&#xff08;跨域资源共享&#xff09;机制中的“预检请求”&#xff08;Preflight Request&#xff09;。该机制的核心目的是在实际请求发送前&am…

作者头像 李华
网站建设 2026/4/16 13:44:16

GLM-TTS支持中英混合语音生成,助力多语言内容创作

GLM-TTS 支持中英混合语音生成&#xff0c;助力多语言内容创作 在短视频、播客和在线教育内容爆发式增长的今天&#xff0c;创作者对语音合成的需求早已不再局限于“把文字读出来”。他们需要的是有个性、能跨语言、带情绪、高保真的声音——一个真正像“人”一样的数字声线。而…

作者头像 李华