Win32 Assembly tutorial 12 Pipeline operations

Source: Internet
Author: User
Tags readfile

--------------------------------------------------------------------------------

Download all source programs in this section

Overview

Windows introduces multi-process and multi-thread mechanisms. At the same time, it also provides communication means between multiple processes, including clipboard, DDE, Ole, and pipelines. Compared with other communication means, pipelines have their own restrictions and characteristics, the MPs queue is actually a shared memory zone where the process places the shared messages. And provides information exchange through some APIs.
A pipeline is a two-header object. Each header connects to a process or different code of the same process. There are two types of pipelines according to the pipeline type, namely, anonymous and named; the pipeline transmission direction can also be divided into two types, one-way two-way. Based on the characteristics of pipelines, named pipelines communicate with processes running on different computers in a network environment (of course, they can also be used in different processes of the same machine) it can be unidirectional or bidirectional, while an anonymous pipeline can only be used on the same computer. It can only be unidirectional. An anonymous pipeline is actually implemented by a famous Pipeline with a specified name.
The advantage of using pipelines is that the APIs used for file operations are read and written, and the Result Operation pipelines are the same as the operation files. Even if you use a named pipe to communicate with different computers, you do not have to understand the details of inter-network communication with yourself.

We will briefly introduce the use of named pipelines.

A named pipe is created by a process on the server. The Pipe name must follow a specific naming method, that is "//. /pipe/MPS queue name. When a client-side process is to be used, use "// computer name // pipe/MPS queue name". The procedure is as follows:

The server creates an instance named pipeline by using the createnamedpipe function, returns a handle for future operations, or creates a new instance for an existing pipeline.
The server listens for connection requests from clients. This function is implemented through the connectnamedpipe function.
The client uses the waitnamedpipe function to wait for the emergence of an MPS queue. If a MPs queue can be used before the timeout value changes to zero, waitnamedpipe returns true, call createfile or callnamedpipe to call the connection to the server.
In this case, the server accepts the client connection request and establishes the connection successfully. The server connectnamedpipe returns true.
After the connection is established, the client and server can use readfile and writefile to exchange information with each other using the obtained pipeline file handle.
When the communication between the client and the server ends, the client calls closefile, and the server then calls disconnectnamedpipe. Finally, the closehandle function is called to close the pipeline.
Because the program used as the client must know the name of the MPs queue, it is used in server/workstation programs written by the same author, you can't just find a program and ask it to communicate with the program you write through the naming pipeline. The use of the anonymous pipeline is completely different. It allows you to communicate with completely unrelated processes, provided that the process inputs and outputs through the console, A typical example is an old dos application. during runtime, Windows opens a DOS window for them, and their input and output are in the Console mode. Some standard Win32 programs also use console input and output. If you do not want to use the GUI in Win32 programming, you can still use allocconsole to get a console and then get the input or output handle through getstdhandle, then, output the result to the console (usually a DOS window) through the writeconsole or writefile. Although these programs look like DOS programs, they are exactly Win32 programs. If you use them in pure dos, the "the program must run under Windows!" will be displayed !".

A console has three handles: standard input, standard output, and standard error handle. The standard input and standard output handle can be reoriented. you can replace it with an anonymous pipeline, in this way, you can use other processes on the other end of the pipeline to receive or input data, and the console side does not feel any different, it is like> or <in DOS that can be redirected to output or input again. Generally, the input and output of the console program are as follows:

(Console process output) Write ----> standard output device (usually screen)
(Console process input) read <---- standard input device (generally a keyboard)

After the pipeline is replaced:

(As the console process output of the sub-process) Write ----> pipeline 1 ----> Read (parent process)
(As the console process input of the sub-process) read <----> pipeline 2 <---- write (parent process)

Follow these steps to use an anonymous pipeline:

Use createpipe to create two pipelines to obtain the pipeline handle, one for input and the other for output.
Prepare to execute the sub-process of the console. First, use getstartupinfo to get startupinfo.
Use the first pipe handle to replace hstdinput in startupinfo, and the second to replace hstdoutput and hstderror, that is, standard input, output, and error handle.
Use CreateProcess to execute the sub-process, so that the input and output of the created sub-process are directed to the pipeline.
The parent process reads the second pipeline through readfile to obtain the output of the sub-process, and writes the input to the sub-process through writefile.
The parent process can use peeknamedpipe to query whether the child process has output.
After the sub-process ends, you must use closehandle to close two pipelines.
The specific descriptions and definitions are as follows:

1. Create an anonymous pipeline and use createpipe as follows:

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
);

After the pipeline is created, the hreadpipe and hwritepipe pointed to in the structure can be used to read and write pipelines. Of course, because the anonymous pipeline is unidirectional, you can only use one of the handles, the security_attributes structure in the parameter must be filled in and defined as follows:

Typedef struct_security_attributes {
DWORD nlength: // defines the length of this structure in bytes.
Lpvoid lpsecuritydescriptor; // point to the security descriptor that controls the sharing of this object. If it is null, this object will be assigned a default security description.
Bool binherithandle; // when a new process is created, it defines whether the returned result is inherited for use by system API functions.
} Security_attributes;

2. Fill in the startupinfo structure used to create the sub-process. Generally, we can use getstartupinfo to enter a default structure, and then modify what we use. They are:

Hstdinput -- replace it with the hwritepipe of one of the pipelines
Hstdoutput and hstderror -- use the hreadpipe of another pipeline
Dwflags -- if it is set to startf_usestdhandles or startf_useshowwindow, the input and output handle and wshowwindow fields are valid.
Wshowwindow -- set to sw_hide, so that the window is not displayed when the process is executed.
After entering this information, you can use CreateProcess to execute sub-processes. For details about how to execute sub-processes, refer to process control in the previous tutorial.

3. You can use peeknamedpipe in the program to query whether the sub-process has output. The prototype is as follows:

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
);

We can try to read the data of the nbuffersize, and then we can use the returned bytesread to obtain the amount of data in the pipeline. If the value is not equal to zero, it means that the data can be read.

4. Read and Write pipelines using readfile and writefile. Their parameters are identical, and their prototype is as follows:

Readfile or writefile (
Handle hfile, // handle of file to read use the pipe handle here
Lpvoid lpbuffer, // address of buffer that contains es data buffer address
DWORD nnumberofbytestoread, // number of bytes to read
Lpdword lpnumberofbytesread, // address of number of bytes read, number of bytes actually read or written
Lpoverlapped // address of structure for data null is used here
);

5. Use closehandle to close the hreadpipe and hwritepipe handles of pipelines 1 and 2.

The following is an example program. This program is an extension of the example in Process Control in the previous tutorial. If you are unfamiliar with Some APIs, read the previous tutorial first.

Source program-compile source file

Debug equ 0
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>>>>
; Programmed by Luo yunbin, bigluo@telekbird.com.cn
; Website: http://asm.yeah.net
; Luoyunbin's Win32 ASM page (luyun Bin's programming Park)
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>>>>
; Version information
Assembly tutorial with example Program-pipeline example
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>>>>
. 386
. Model flat, stdcall
Option Casemap: none; case sensitive
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include data
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>>>>
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 data
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>>>>
Ico_main equ 1000
Menu_main equ 2000
Idm_exec equ 2001
Idm_exit equ 2002

F_running equ 0001 h; the process is running
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>>>>
; Data Segment
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>>>>
. 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 'Connection MS-& dos mode', 0
Szexcuteerror db' An error occurred while starting the application! ', 0
Szcaption dB 'pipeline sample program... http://asm.yeah.net ', 0
Szclassname dB 'pipelexample ', 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, fw_normal ,/
0, 0, 0, ansi_charset, out_default_precis ,/
Clip_stroke_precis, default_quality ,/
Default_pitch or ff_swiss, "fixedsys">

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>>>>
; Code segment
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>>>>
. Code

If debug
Include debug. ASM
Endif
Include win. ASM

; **************************************** ****************************
Thread used to execute the program
; 1. Use CreateProcess to create a process
; 2. Use waitforsingleoject to wait for the process to end
; **************************************** ****************************
_ 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
; **************************************** ****************************
; Change the "execution" menu to "end"
; **************************************** ****************************
Invoke enablemenuitem, hmenu, idm_exec, mf_grayed
Invoke enablemenuitem, hmenu, idm_exit, mf_grayed
; **************************************** ****************************
; Create an MPS queue
; **************************************** ****************************
MoV @ stsecurity. nlength, sizeof security_attributes
MoV @ stsecurity. lpsecuritydescriptor, null
MoV @ stsecurity. binherithandle, true
Invoke createpipe, ADDR hread1, ADDR hwrite1, ADDR @ stsecurity, null
Invoke createpipe, ADDR hread2, ADDR hwrite2, ADDR @ stsecurity, null

; **************************************** ****************************
; Execution file. If successful, wait until the program ends.
; **************************************** ****************************
Invoke getstartupinfo, ADDR ststartup
MoV eax, hread1
MoV ststartup. hstdinput, eax
MoV eax, hwrite2
MoV ststartup. hstdoutput, eax
MoV ststartup. hstderror, eax
MoV ststartup. dwflags, startf_usestdhandles or startf_useshowwindow
MoV ststartup. wshowwindow, sw_hide
Invoke CreateProcess, null, ADDR szcommand, null, null ,/
Null, normal_priority_class, null, null, offset ststartup, offset stprocinfo
. If eax! = 0
. While true
Invoke getexitcodeprocess, stprocinfo. hprocess, ADDR @ dwexitcode
. Break. If @ dwexitcode! = Still_active
Invoke peeknamedpipe, hread2, ADDR szbuffer, 511, ADDR @ dwbytesread, null, null
. If @ dwbytesread! = 0
Invoke rtlzeromemory, ADDR szbuffer, 512
Invoke readfile, hread2, ADDR szbuffer, @ dwbytesread, ADDR @ dwbytesread, null
MoV @ strange. CPMin,-1
MoV @ strange. cpmax,-1
Invoke sendmessage, hwintext, em_exsetsel, 0, ADDR @ strange
Invoke sendmessage, hwintext, em_replacesel, false, ADDR szbuffer
Invoke sendmessage, hwintext, em_scrollcaret, null, null
Invoke sendmessage, hwintext, wm_setfont, hfont, 0
. Endif
. Endw
Invoke closehandle, stprocinfo. hprocess
Invoke closehandle, stprocinfo. hthread
. Else
Invoke MessageBox, hwinmain, ADDR szexcuteerror, null, mb_ OK or mb_iconerror
. Endif
; **************************************** ****************************
; Close MPs queue
; **************************************** ****************************
Invoke closehandle, hread1
Invoke closehandle, hwrite1
Invoke closehandle, hread2
Invoke closehandle, hwrite2
; **************************************** ****************************
; Change the "end" menu to "execute"
; **************************************** ****************************
Invoke enablemenuitem, hmenu, idm_exec, mf_enabled
Invoke enablemenuitem, hmenu, idm_exit, mf_enabled
Invoke enablewindow, hwintext, false
And dwflag, not f_running
RET

_ Runthread endp

; **************************************** ****************************
; Window Program
; **************************************** ****************************
Wndmainproc proc uses ebx edi esi ,/
Hwnd: DWORD, wmsg: DWORD, wparam: DWORD, lparam: DWORD

MoV eax, wmsg
; **************************************** ****************************
. If eax = wm_create
MoV eax, hwnd
MoV hwinmain, eax
Call _ init
; **************************************** ****************************
. Elseif eax = wm_size
MoV edX, lparam
MoV ECx, EDX
SHR ECx, 16
And EDX, 0 ffffh
Invoke movewindow, hwintext, 0, 0, EDX, ECx, true
Invoke postmessage, hwintext, wm_size, wparam, lparam
; **************************************** ****************************
. Elseif eax = wm_close
Test dwflag, f_running
. If zero?
Invoke destroywindow, hwinmain
Invoke postquitmessage, null
. Endif
; **************************************** ****************************
. Elseif eax = wm_command
MoV eax, wparam
. If AX = idm_exec
; **************************************** ****************************
; If the thread is not being executed (dwflag is not set), a thread is created and the program is executed in the thread.
If the execution is in progress, use terminateprocess to terminate the execution.
; **************************************** ****************************
Test dwflag, f_running
. If zero?
Invoke enablewindow, hwintext, true
Invoke setfocus, hwintext
Invoke createthread, null, null, offset _ runthread ,/
Null, null, offset hrunthread
. Else
Invoke terminateprocess, stprocinfo. hprocess,-1
. Endif
. Elseif AX = idm_exit
Invoke destroywindow, hwinmain
Invoke postquitmessage, null
. Endif
. Else
Invoke defwindowproc, hwnd, wmsg, wparam, lparam
RET
. Endif
XOR eax, eax
RET

Wndmainproc endp
; **************************************** ****************************
; Program entry
; **************************************** ****************************
Start:
Call _ winmain
Invoke exitprocess, null
; **************************************** ****************************
_ Winmain proc
Local @ stwcmain: wndclassex
Local @ stmsg: msg
Local @ hrichedit

Invoke loadlibrary, offset szdllname
MoV @ hrichedit, eax

Invoke initcommoncontrols
Invoke getmodulehandle, null
MoV hinstance, eax
Invoke loadmenu, hinstance, menu_main
MoV hmenu, eax
; ******************** *******************
Invoke loadcursor, 0, idc_arrow
MoV @ stwcmain. hcursor, eax
MoV @ stwcmain. cbsize, sizeof wndclassex
MoV @ stwcmain. hiconsm, 0
MoV @ stwcmain. style, cs_hredraw or cs_vredraw
MoV @ stwcmain. lpfnwndproc, offset wndmainproc
MoV @ stwcmain. cbclsextra, 0
MoV @ stwcmain. cbwndextra, 0
MoV eax, hinstance
MoV @ stwcmain. hinstance, eax
Invoke loadicon, hinstance, ico_main
MoV @ stwcmain. hicon, eax
MoV @ stwcmain. hbrbackground, color_btnface + 1
MoV @ stwcmain. lpszclassname, offset szclassname
MoV @ stwcmain. lpszmenuname, 0
Invoke registerclassex, ADDR @ stwcmain
; * **************** Create an output window ******************** *********************
Invoke createmediawex, null ,/
Offset szclassname, offset szcaption ,/
Ws_overlappedwindow ,/
0, 0, 680,420 ,/
Null, hmenu, hinstance, null

Invoke showwindow, hwinmain, sw_shownormal
Invoke updatewindow, hwinmain
; **************************************** ****************************
. While true
Invoke getmessage, ADDR @ stmsg, null, 0, 0
. Break. If eax = 0
Invoke translatemessage, ADDR @ stmsg
Invoke dispatchmessage, ADDR @ stmsg
. Endw
Invoke freelibrary, @ hrichedit
Invoke deleteobject, hfont
RET

_ Winmain endp

; **************************************** ****************************
; Input Program
; **************************************** ****************************
_ Inputproc proc uses ebx edi esi ,/
Hwnd: DWORD, umsg: DWORD, wparam: DWORD, lparam: DWORD
Local @ szbuffer [4]: byte
Local @ dwbyteswrite

MoV eax, umsg
. If eax = wm_char
MoV eax, wparam
Movzx eax, Al
MoV dword ptr @ szbuffer, eax
Test dwflag, f_running
. If! Zero?
Invoke writefile, hwrite1, ADDR @ szbuffer, 1, ADDR @ dwbyteswrite, null
. Endif
XOR eax, eax
RET
. Endif
Invoke getwindowlong, hwnd, gwl_userdata
Invoke callwindowproc, eax, hwnd, umsg, wparam, lparam
RET

_ Inputproc endp
; **************************************** ****************************
_ Init proc

; * ************* Create an output RichEdit window ********************* **************
Invoke createappswex, ws_ex_clientedge, offset szclassnameredit ,/
Null, ws_child or ws_visible or ws_vscroll or ws_hscroll/
Or es_multiline or es_autohscroll or es_autovscroll ,/
0, 0, 0 ,/
Hwinmain, null, hinstance, null
MoV hwintext, eax
; *********************** ************************
Invoke createfontindirect, offset stlogfont
MoV hfont, eax
Invoke sendmessage, hwintext, wm_setfont, hfont, 0
Invoke sendmessage, hwintext, em_setreadonly, true, null

Invoke setwindowlong, hwintext, gwl_wndproc, offset _ inputproc
Invoke setwindowlong, hwintext, gwl_userdata, eax
Invoke enablewindow, hwintext, false

Invoke _ centerwindow, hwinmain
Invoke setfocus, hwintext

RET

_ Init endp
; **************************************** ****************************
End start

Program Analysis and key points

In the program, I first set up a RichEdit control to display the output of the child process. At the same time, I subclass RichEdit and intercept its keyboard input so that it can be sent to the child process.

Invoke setwindowlong, hwintext, gwl_wndproc, offset _ inputproc

This statement refers to the RichEdit process in _ inputproc, and then writes the writefile character entered in wm_char of _ inputproc to the MPs queue. I created two MPs queues in the program and then executed C: /command.com. In this way, a DOS command line process is obtained, and peeknamedpipe is used in the loop to check whether the sub-process has output. If yes, the sub-process is read through readfile and displayed in RichEdit.

When running the example program, you must note that you can execute almost all other programs in this "command.com", but do not execute such as UCDOS, programs such as pctools that do not use standard input/output (that is, programs that do not use ">" or "<" redirection in DOS), because ws_hide is used when loading sub-processes, therefore, the original command.com window is hidden. If you execute such a program, it means you lose control of the child process, because they do not use standard input to receive the keyboard, you cannot exit the pipelines.

Another usage of the anonymous pipeline can be extended here. If you are running a program similar to arj.exe instead of command.com, you do not need to display its output to RichEdit, but it is processed in the program. Then you can write a winarj. Of course, you only need to write the cooperation between the window interface and arj.exe.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.