Win32 assembly tutorial 12 pipe operation

zhaozj2021-02-08  317

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

Download all source programs of this section here

Overview

Windows introduces multi-process and multi-threaded mechanisms. At the same time, there is also a communication method between multiple processes, including clipboard, DDE, OLE, pipeline, etc. Compared to other communication means, the pipe has its own restrictions and characteristics, and the pipeline is actually a shared memory area, process Place the shared message there. And provide information exchange through some APIs.

The pipe is two heads, each of each head connected to a process or different code of the same process, with two types of pipes, anonymity and naming; according to the pipeline transfer direction, single Bidirectional. Depending on the characteristics of the pipeline, the named pipe is usually used between the processes running on different computers in a network environment (of course, in different processes of the same machine) it can be unidirectional or two-way; and anonymous pipeline only Can be used in the same computer, it can only be one-way. Anonymous pipe is actually achieved by a famous pipe for a specified name.

The benefit of using the pipe is that reading and writing It is used by the API for file operation, and the results are the same as the operational file. Even if you communicate with a naming pipe between different computers, you don't have to know the specific details of the network communication between networks.

We briefly introduce the use of named pipes.

The named pipe is established by the server-side process. The naming of the pipe must follow the specific naming method, that is, "//pipe/ pipe name", when used as a client, use "// computer name // PIPE / Pipe name "to open the use, the specific steps are as follows:

The server creates an instance of a named pipe through the function CreateNameDpipe and returns the handle for future operation, or creates a new instance for existing pipes.

The server listened to the connection request from the client, which is implemented through the connection function.

The client is waiting for the appearance of the pipe through function WaitNameDpipe. If the timeout value becomes zero, there is a pipe to use, then WaitNameDpipe will return True and call the server connection by calling CREATEFILE or CALLNAMEDPE.

At this point, the server will accept the client's connection request, successfully establish a connection, and the server connectNamedPipe returns true.

After establishing a connection, the client can use readfile and writefile to use the obtained pipe file handle, information exchange with each other.

When the client is ended with the server, the client calls Closefile, and the server then calls DisconnectNamedPipe. Finally, the function closehandle is called to turn off the pipe.

Since the program is used as the client, the program must know the name of the pipe, so more in the server / workstation program written in the same "author", you can't find a program to ask it to write the program. By named pipe communication. The use of anonymous pipeline is completely different. It allows you and completely unpacked process communication, the condition is that this process enters the output through the console "console", typical example is the old DOS application, they are running Windows They open a DOS window, and their input and output is console mode. There are also some standard Win32 programs that also use the console input and output. If you don't want to use the graphical interface in Win32, you can use allocconsole to get a console, then get the input or output handle via the GetStdHandle, and then use WriteConsole or Writefile to put the result Outputs to the console (usually an icon DOS window). Although these programs look like a DOS program, they are unclosed Win32 programs. If you use it under pure DOS, "The Program Must Run Under Windows!" Is displayed. One console has three handles: standard input, standard output, and standard error handles, standard input, standard output handle can be reordered, you can replace it with anonymous pipeline, so that you can take the other end of the pipe Use another process to receive or enter, and the control desk is not feeling different, just like the> or

(Console Process Output) WRITE ----> Standard Output Equipment (Generally Screen)

(Console Process Input) Read <---- Standard Input Device (Usually Keyboard)

And use the pipe instead of:

(As the console process of the sub-process) Write ----> Pipe 1 ----> Read (Parent Process)

(As a console process in Pi Process) Read <----> Pipe 2 <---- Write (Parent Process)

The steps to use anonymous pipes are as follows:

Use CreatePipe to build two pipes, get the pipe handle, one is used to input, one is used to output

Ready to perform the control station process, first get startupinfo using getStartupInfo

Use the first pipe handle instead of HSTDINPUT in Startupinfo, the second instead of HSTDOTPUT, HSTDEROR, namely standard input, output, error handle

Use the CreateProcess execution sub-process so that the sub-process input and output of this created are directed to the pipeline.

The parent process reads the second pipe through the ReadFile to obtain the output of the child process, write the first pipeline through WriteFile to write the sub-process

The parent process can check the sub-process without output via PeekNameDpipe.

After the child process is over, you should close the two pipes through CloseHandle.

Here are specific instructions and definitions:

1. Establish anonymous pipeline using the CreatePipe protogin 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 TRIBUTES

DWORD nsize // number of bytes reserved for pipe);

When the pipe is established, the HREADPIPE and HWRITEPIPE pointed to the structure can be used to read and write the pipeline. Of course, because the anonymous pipeline is unidirectional, you can only use one of the handles, the configuration of the security_attributes in the parameter must be filled, the definition is as follows:

Typedef struct_security_attributes {

DWORD NLENGTH: / / Define the length of this structure in bytes

LPVOID LPSECURITYDESCRIPTOR; / / Point to control the security descriptor shared by this object, if this object will be assigned a default security description

Bool binherithandle; // When a new process is created, it defines whether it returns whether it is inherited. The system API function is used.

Security_attribute;

2. Fill in the StartupInfo structure for creating sub-processes, usually we can fill in a default structure with GetStartupInfo, then change the place where we get it, they are:

HSTDINPUT - uses one of the pipes of HWRITEPIPE instead

HSTDOUTPUT, HSTDERROR - replaced with another pipe of HREADPIPE

DWFLAGS - Set to startf_usestdhandles or startf_useshowwindow indicates that the input / output handle and the wshowwindow field are valid.

WshowWindow - Set to sw_hide, so that the window does not display when executed.

After filling out, you can use createProcess to perform sub-processes, and the specific operation of the execution sub-process can refer to the previous tutorial "process control"

3. You can use the peeknamedpipe query sub-process in the program. The original shape 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 NBuffersize size data, then you can get how much data in the pipe by returning BytesRead, if not equal to zero, indicating that there is data to be read.

4. Read the pipeline with readfile and writefile, their parameters are exactly the same, the original shape is as follows:

Readfile or Writefile

Handle Hfile, // Handle of File To Read Use the pipe handle here

LPVOID LPBUFFER, // Address of Buffer That Receives Data Buffer Address

DWORD NNUMBEROFBYTESTOREAD, // Number of Bytes To Read and write bytes

LPDWORD LPNUMBEROFBYTESREAD, // address of number of bytes read, actually read or written by number

LPoverlapped LPoverlapped // Address of Structure for Data Use null here;

5. Close the four handles of the HREADPIPE and HWRITEPE for Pipelines and Pipelines with CloseHandle.

The following example is given, this program is an extension of the previous tutorial "process control", if you feel strange to some API, please read the previous tutorial.

Source program - assembly source file

Debug EQU 0

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

PROGRAMMED by Luo Yunbin, Bigluo@telekbird.com.cn

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

Luoyunbin's Win32 ASM Page (Luo Yunbin's Programming Park)

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

; Version Information

; Assembly test with example - Pipeline example

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

.386

.Model flat, stdcall

Option Casemap: None; Case Sensitive

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

Include data

; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Folder 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 0001H; Process is in operation

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

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

Sz Genexecute DB 'Connect MS- & DOS Way, 0

SZEXCUTEERROR DB 'Launches an application error! ', 0

SZCAPTION DB 'Pipeline sample program ... http://asm.yeah.net' ,0

SzclassName DB 'PIPEEXAMPLE', 0

SZDLNAME DB 'Riched32.dll', 0

Szclassnamered DB 'Richedit', 0

SZDLNAME 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

*********************************************************** ***************; the thread for executing the program

1. Establish a process with CreateProcess

; 2. Waiting for the process of waiting for the process of 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

*********************************************************** *******************

"Execute" menu is changed to "end"

*********************************************************** *******************

Invoke EnableMenuItem, HMENU, IDM_EXEC, MF_GRAYED

Invoke EnableMenuItem, HMENU, IDM_EXIT, MF_GRAYED

*********************************************************** *******************

Establish a pipeline

*********************************************************** *******************

Mov @ stsecurity.nlength, sizeof security_attributes, SIZEOF Security_ATINGTH, SIZEOF SECURITY_ATTRIBUTES

Mov @ stsecurity.lpsecurityDescriptor, NULL

Mov @ stsecurity.binherithandle, true

Invoke CreatePipe, AddR Hread1, AddR HWrite1, Addr @ StSecurity, Null

Invoke Cread2, AddR HWRITE2, ADDR @ StSecurity, NULL

*********************************************************** *******************

; Execute file, wait for the end to end if successful

*********************************************************** *******************

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 RTLZERMEMORY, 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

.lse

Invoke Messagebox, Hwinmain, Addr SzexcuteError, NULL, MB_OK OR MB_ICONERROR

.endif

*********************************************************** *******************

Close the pipeline

*********************************************************** *******************

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_CREATEMOV EAX, HWND

Mov Hwinmain, EAX

Call_init

*********************************************************** *******************

.ELSEIF EAX == WM_SIZE

Mov Edx, LParam

MOV ECX, EDX

SHR ECX, 16

And EDX, 0FFFFH

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 established if not in the execution (dwflag is not set), execute the program in the thread

If it is already in execution, use TerminateProcess to terminate execution

*********************************************************** *******************

Test dwflag, f_running

.IF ZERO?

Invoke EnableWindow, HWINTEXT, TRUE

Invoke setfocus, hwintext

Invoke CreateThread, Null, Null, Offset _Runthread, /

NULL, NULL, OFFSET HRUNTHREAD

.lse

Invoke TerminateProcess, StProcinfo.hprocess, -1

.endif

.ELSEIF AX == IDM_EXIT

Invoke DestroyWindow, HwinMain

Invoke PostquitMessage, NULL

.endif

.lse

Invoke DefWindowProc, Hwnd, WMSG, WPARAM, LPARAM

RET

.endif

XOR EAX, EAX

RET

WNDMAINPROC ENDP

*********************************************************** *******************

Procedure

*********************************************************** *******************

Start:

Call_winmain

Invoke EXITPROCESS, NULL

*********************************************************** *******************

_WinMain Proc

Local @stwcmain: WNDCLASSEX

Local @stmsg: msg

Local @hrichedit

Invoke loadLibrary, Offset szdllnamemov @ hrichedit, eax

Invoke INITCOMMONCONTROLS

Invoke getModuleHandle, NULL

Mov Hinstance, EAX

Invoke loadmenu, hinstance, menu_main

Mov Hmenu, EAX

**************** Registration window *************************************** **********

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

**************** Establish an output window ************************************** ************

Invoke CreateWindowex, 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 GetMsg, NULL, 0, 0

.break .if eax == 0

Invoke TranslateMsg, 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

*************** Establish an output RicheDit window ************************************** *****

Invoke CreateWindowex, 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, 0, /

Hwinmain, Null, Hinstance, Null

Mov Hwintext, EAX

*************** Set font *************************************** ****************

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 points

In the program, I first established a RicheDit control to display the output of the sub-process, and simultaneize the Richedit subclass, intercept its keyboard input to send it to the child process.

Invoke setWindowlong, Hwintext, GWL_WndProc, Offset _inputproc

This statement refers to the _inputproc process, then in the _inputproc's WM_CHAR, I will type in the line, I set up two pipes first in the program, then execute C: /command.com, so Get a DOS command line process, then there is no output through the PeeknameDpipe detection sub-process in the loop, if any, read it via the readfile, in the Richedit.

Be careful when running an example, you can perform almost all other programs in this "command.com", but do not perform programs such as UCDOS, PCTools, and programs that do not use standard input output (not used in DOS ">" Or "<" redirected procedure), because we used WS_HIDE when we loaded the process, the original command.com's window is hidden. If you perform this program, it means you lose The control of the sub-process, because they do not use standard input to receive the keyboard, you can't get them from the pipeline. Here you can also quote another usage of anonymous pipes. If you don't have command.com but similar to the arj.exe program, then you don't have to display its output into the Richedit, but in the program, So, you can write a Winarj, of course, you only need to write a window interface and the cooperation between Arj.exe.

转载请注明原文地址:https://www.9cbs.com/read-1453.html

New Post(0)