Win32 assembly: 21. Pipeline

zhaozj2021-02-17  61

Twenty-first class pipeline

This lecture will explore the pipeline to see what it is, what is used. In order to make it more vivid, I will use how to change the background color and text color of the Edit control.

theory:

Pipeline, as the name suggests, there are two end channels. You can use the pipeline between the processes, data exchange within the same process, just like a portable radiotelephone. Give one end of the pipe to the other, he can communicate with you with the pipeline.

There are two pipelines, namely, a famous pipe and anonymous pipe. Anonymous pipeline is a pipe with no name, that is, do not need to know its name when using them. The famous pipeline is just the opposite, and it must be known before use.

It is also possible to classify according to the characteristics of the pipe, ie the one-way or two-way. One-way pipe, data can only be moved in one direction, flow from one end to the other, and the bidirectional conduit data can be freely exchanged between the two ends. Anonymous pipelines are usually unidirectional and famous pipes are usually two-way. A well-known pipe is often used in a server contact multiple client network environments.

This lecture will discuss anonymous pipeline in detail. The main purpose of anonymous pipeline is a linkage pathway that communicates between the parent process and the child process. The anonymous pipeline is quite useful when processing a console problem. The console application is a Win32 application using the console as an input and output. A console is like a DOS window. But the console application is indeed a 32-bit application, which can use the GUI function as other graphics programs, but it happens to use the console.

The console application has three standard handles for inputting output, which are standard input, standard output, and standard error handles. Standard input is used to read or take information from the console to write or print information. Standard Error is used to report errors that cannot be redirected.

The console application can get these three handles by calling the function getStdHandle. A graphics application has no console. If you call getStdHandle, it will return an error; if you do use a console, you can call allocConsole to assign a new console for use, but don't forget to call FreeConsole when the processing is complete. Release the console.

The function of the anonymous pipeline is used to redirect the standard input and standard output of the sub-process. The parent process can be a console or a graphics, while the child process must be a console application. It is well known that console applications use standard input and output handles. To redirect the input and output, you have to replace this standard handle with the handle to point to the pipe. The console application will not know that we use the handle to any end of the pipe, which will treat this handle as a standard handle. By borrowing object-oriented terms, this is one of the polymorphism. This method is very useful because the child process does not need to be changed.

Another point to the console application should be mastered is where it gives a standard handle. When a console application is created, the parent process has two options: Creating a new console for the child process or allows the child to inherit your console. If you use the latter, the parent process itself must be a console application, or if it is a GUI application, it must first call allocConsole allocated a console.

Create an anonymous pipe by calling createpipe, its prototype:

CreatePipe Proto Preadhandle: DWORD, / PWRITEHANDLE: DWORD, / PPIPEATTRIBUTES: DWORD, / NBUFFERSIZE: DWORD

The preadhandle double-word pointer variable, points to the handle of the pipe reading end. PWRiteHandle double-word pointer variable, pointing to the PPIPEATTRIBUTES dual pointer variable, pointing to the security_attributes structure, which is used to determine whether the read and write handle can inherit the NBuffersize suggestion the size of the buffer to be used, this is just a suggestion. Value, you can use NULL to use the default value if the function call successfully returns to zero, otherwise zero. After successful call, two handles are obtained, a read end pointing to the pipe, and the other pointing to the pipeline. Now I am going to put the focus on the criteria for the sub-console program to output to the desired steps of their own process. Note that my method is different from the example of Borland's API reference. Win32 API Referring is assumed that the parent process is a console application, so the child process can inherit its standard handle. However, most of the cases we need to redirect the output to the GUI application.

Create an anonymous pipeline using createpipe, and don't forget to set the Security_Attributes structural member binheritable to TRUE, so that the handle can be inherited.

Now you have to prepare a function of creating a process, the parameters of CreateProcess, and only it can load the child console application. StartupInfo is an important structure that determines the appearance of the main window when the child process appears, which is also crucial for our goals. Through this structure, you can hide the main window and pass the pipe handle to the child process.

The following is a member you have to fill in:

The size of the CB StartupInfo structure DWFLAGS binary logo, which determines which members of this structure are valid, and also determine whether the main window is displayed or hidden. In our program, using Startf_USESHOWWINDOW and STARTF_USESTDHANDLES combined HSTDOUTPUT and HSTDERROR you want to use the standard output and standard error handles used by the sub-process, for us, we will put the pipelines as the standard output and errors of the child process. Therefore, when the child process is sent to standard output or standard error, it actually passes this information through the pipe to the parent process wshowWindow determines the main window is displayed or hidden. We do not want to display the main window of the sub-process, so put the member into sw_hide

Call CREATEPROCESS to create a child process, but the successful postus is still not in the active state. It is put into memory but does not run immediately.

The write end of the shutdown pipe in the parent process is also necessary. This is because the parent process does not use the write handle of the pipe, and if a pipe has two write-in, we must turn off the writing of the pipe before reading the data from the pipe. But you can't turn it off before calling createprocess, otherwise the pipeline is broken. You should turn off the pipe in CreateProcess just closing the pipe before reading data.

Now you can read the data through the function readfile read the data in the pipeline. By using the readfile, you can make the child process in operation. It will begin to execute, and when it writes data to standard output (actually the write end of the pipe), the data will be sent to the read end of the pipe. It should not be invisible to the READFILE until its return value is 0, that is, no data can be read again. You can do any processing from the data read from the pipe, which is displayed in the Edit control in our example.

Remember to close the read handles of the pipe after use.

Code example:

.386

.Model flat, stdcall

Option CaseMAP: NONE

INCLUDE /MASM32/INCLUDE/Windows.inc

INCLUDE /MASM32/INCLUDE/USER32.INC

INCLUDE /MASM32/INCLUDE / WANEL32.INC

Include /masm32/include/gdi32.incincludelib /masm32/lib/gdi32.lib

INCLUDELIB /MASM32/LIB/USER32.LIB

INCLUDELIB /MASM32/LIB/kernel32.lib

Winmain Proto: DWORD,: DWORD,: DWORD,: DWORD

.const

IDR_MAINMENU EQU 101; The id of the main menu

IDM_ASSEMBLE EQU 40001

.DATA

ClassName DB "PirewinClass", 0

Appname DB "One-Way Pipe Example", 0 Editclass DB "Edit", 0

CreatePipeError DB "Error During Pipe Creation", 0

CreateProcesSserror DB "Error During Process Creation", 0

CommandLine DB "ml / c / coff / cp test.asm", 0

.DATA?

Hinstance Hinstance?

HWndIt DD?

.code

Start:

Invoke getModuleHandle, NULL

Mov Hinstance, EAX

Invoke Winmain, Hinstance, Null, NULL, SW_SHOWDEFAULT

Invoke EXITPROCESS, EAX

Winmain Proc Hinst: DWORD, HPREVINST: DWORD, CMDLINE: DWORD, CMDSHOW: DWORD

Local WC: WNDCLASSEX

Local MSG: MSG

Local hwnd: hwnd

Mov wc.cbsize, sizeof wndclassex

Mov wc.style, cs_hredraw or cs_vredraw mov wc.lpfnwndproc, Offset WndProc

Mov wc.cbclsextra, NULL

Mov wc.cbwndextra, null

Push hinst

POP wc.hinstance

Mov wc.hbrbackground, Color_AppWorkspace

Mov wc.lpszMenuname, IDR_MainMenu

MOV wc.lpszclassname, Offset ClassName

Invoke Loadicon, NULL, IDI_APPLICATION

Mov wc.hicon, EAX

Mov wc.hiconsm, EAX

Invoke loadcursor, null, IDC_ARROW

Mov wc.hcursor, EAX

Invoke RegisterClassex, Addr WC

Invoke CreateWindowex, WS_EX_CLIENTEDGE, ADDR CLASSNAME, AddR Appname, / WS_OVERLAPPEDWINDOW WS_VISible, CW_USEDEFAULT, / CW_USEDEFAULT, 400, 200, NULL, NULL, / HINST, NULL

MOV HWND, EAX

.While true

Invoke GetMessage, Addr MSG, NULL, 0, 0

.Break .if (! EAX)

Invoke TranslateMessage, Addr MSG

Invoke DispatchMessage, Addr MSG

.endw

Mov Eax, Msg.wParam

RET

Winmain ENDP

WndProc Proc HWND: HWND, UMSG: UINT, WPARAM: WPARAM, LPARAM: LPARAMLOCAL RECT: RECT

Local Hread: DWORD

Local HWRITE: DWORD

Local Startupinfo: StartupInfo

Local Pinfo: Process_Information

Local Buffer [1024]: Byte

Local BytesRead: DWORD

Local HDC: DWORD

Local Sat: Security_Attributes

.IF uMSG == WM_CREATE

Invoke CreateWindowex, Null, Addr Editclass, NULL, WS_CHILD WS_VISible ES_MULTILINE ES_AUTOHSCROLL ES_AUTOVSCROLL, 0, 0, 0, 0, HWND, NULL, HINSTANCE, NULL

Mov hwndedit, EAX

.ELSEIF uMSG == WM_CTLCOLOREDIT

Invoke setTextColor, WPARAM, YELLOW

Invoke SetBkcolor, WPARAM, Black

Invoke GetStockObject, Black_brush

RET

.ELSEIF uMSG == WM_SIZE

Mov Edx, LParam

MOV ECX, EDX

SHR ECX, 16

And EDX, 0FFFFH

Invoke MoveWindow, Hwndit, 0,0, EDX, ECX, True

.ELSEIF uMSG == WM_COMMAND

.IF lparam == 0

Mov Eax, WPARAM

.IF AX == IDM_ASSEMBLE

Mov Sat.nilength, Sizeof Security_Attributes

Mov Sat.lpsecurityDescriptor, Null

Mov sat.binherithandle, True

Invoke CreatePipe, Addr Hread, Addr HWRITE, AddR Sat, Null

.IF EAX == NULL

Invoke Messagebox, HWnd, Addr CreatePipeError, Addr Appname, MB_ICONERROR MB_OK

.lse

Mov Startupinfo.cb, Sizeof Startupinfo

Invoke GetStartupinfo, Addr Startupinfo

Mov Eax, HWRITE

Mov Startupinfo.hstdoutput, EAX

Mov Startupinfo.hstderror, EAX

Mov Startupinfo.dwflags, Startf_useshowWindow Startf_usestdhandles

Mov Startupinfo.WshowWindow, SW_HIDE

Invoke CreateProcess, Null, Addr Commandline, Null, NULL, TRUE, NULL, NULL, NULL, ADDR Startupinfo, Addr Pinfo

.IF EAX == NULL

Invoke Messagebox, HWnd, Addr CreateProcesserror, Addr Appname, MB_ICONERROR MB_OK

.lse

Invoke Closehandle, Hwrite

.While true

Invoke RTLZERMEMORY, ADDR BUFFER, 1024

Invoke Readfile, Hread, Addr Buffer, 1023, Addr Bytesread, Null.if Eax == Null

.break

.endif

Invoke SendMessage, HWndedit, EM_SETSEL, -1, 0

Invoke SendMessage, Hwndit, EM_REPLAASEL, FALSE, ADDR BUFFER

.endw

.endif

Invoke Closehandle, HREAD

.endif

.endif

.endif

.ELSEIF uMSG == WM_DESTROY

Invoke PostquitMessage, NULL

.lse

Invoke DefWindowProc, HWND, UMSG, WPARAM, LPARAM RET

.endif

XOR EAX, EAX

RET

WNDPROC ENDP

End Start

analysis:

This example calls ml.exe to assemble a program named Test.asm and redirect Ml.exe's output to the EDIT control of the client area. When the program is loaded, I want to register the window class and create a main window. The first thing to do during the process of the main window is created is to create an Edit control used to display Ml.exe output.

Now interesting things, we will change the text color and background colors of this Edit control. When the EDIT control will seize the WM_CTLCOLOREDIT message to the parent window when the EDIT control will override the customer area. Parameters WPARAM contain handles (HDCs) for painting your own client area device descriptor. We can use this mechanism to modify the characteristics of the HDC.

.ELSEIF uMSG == WM_CTLCOLOREDIT

Invoke setTextColor, WPARAM, YELLOW

Invoke SetTextColor, WPARAM, Black

Invoke GetStockObject, Black_brush

RET

SetTextColor turns a text color into yellow, background color becomes black. Finally, we return a handle that gets a black brush by calling getStockObject. Handling WM_CTLCOLOREDIT must return a handle of a brush because Windows will use this brush to redraw Edit control background. In this example, I hope the background is black, so I returned a handle of a black brush.

Now when the user selects the Assemble submenu, an anonymous pipe will be created.

.IF AX == IDM_ASSEMBLE

Mov Sat.nilength, Sizeof Security_Attributes

Mov Sat.lpsecurityDescriptor, Null

Mov sat.binherithandle, True

Before calling CREATEPIPE, you must fill in the Security_Attributes structure. If we don't care about security, you can fill in NULL in the LPSecurityDescriptor member. BinheritHandle must be True so that the handle of the pipe can inherit the quilt process.

Invoke CreatePipe, Addr Hread, Addr HWRITE, AddR Sat, Null

After that, we call CreatePipe to create a pipe. If successful, the variable HREAD and HWRITE will be filled in the corresponding pipe read end and the handle of the write end.

Mov Startupinfo.cb, Sizeof Startupinfo

Invoke GetStartupinfo, Addr Startupinfo

Mov Eax, HWRITE

Mov Startupinfo.hstdoutput, EAX

Mov Startupinfo.hstderror, Eaxmov Startupinfo.dwflags, StartF_USESHOWINDOW Startf_usestdhandles

Mov Startupinfo.WshowWindow, SW_HIDE

The next step is to fill in the StartupInfo structure. Call the GetStartupInfo's default value of the Parent process to fill in the StartupInfo structure. If you want to make the program under Windows9x and Windows NT, you must call GetStartupInfo to fill in the StartupInfo structure. Once the call is returned, you can modify important members. Because we want the child process to output to the parent process rather than the default standard output and standard errors, we assign HSTDOUTPUT and HSTDERROR to the handle of the pipeline. In order to hide the main window of the child process, the member variable wshowwidow must be assigned to sw_hide. Finally, the member HSTDOUTPUT, HSTDESTPUT, HSTDESTPUT, HSTDESTPUT, HSTDESTPUT, HSTDESTPUT, HSTDESTPUT, HSTDESTPUT, HSTDERROR, and WSHOWWINDOW are specifically assigned to StartF_USESTDHANDOW and STARTF_USESTDHANDOW and STARTF_USESTDHANDOW.

Invoke CreateProcess, Null, Addr Commandline, Null, NULL, TRUE, NULL, NULL, NULL, ADDR Startupinfo, Addr Pinfo

CreateProcess is now called to create a child process. Note that the pipeline must be set to TRUE. Invoke CloseHandle, HWRITE successfully created a child process, must close the write of the pipe in the parent process. We have passed the handle of the write to the child process through the structure startupinfo. If it is not closed, then the pipe has two writes, and such a pipe will not work. So you must turn this handle before you create a sub-process but before reading the data.

.While true

Invoke RTLZERMEMORY, ADDR BUFFER, 1024

Invoke Readfile, Hread, Addr Buffer, 1023, Addr Bytesread, Null

.IF EAX == NULL

.break

.endif

Invoke SendMessage, HWndedit, EM_SETSEL, -1, 0

Invoke SendMessage, Hwndit, EM_REPLAASEL, FALSE, ADDR BUFFER

.endw

It is now ready to read data from the standard output of the child process. Until no data is no longer, readfile returns to null, will exit cycles, otherwise it will wait for data. We call RTLZERMEMORY before calling readfile to empty the memory and use the pipeline reader to instead of the file handle. Note that the maximum length of reading data is 1023 (sizeof (buffer) -1), because we need to turn the accepted characters into an ASCII string that can be processed by an Edit control. When ReadFile returns, this data is passed to the Edit control. However, this has a small problem. If you write data in the EDIT control using the SetWindowText API, new data will overwrite the existing old data, and we want to add new data to the existing data. To reach the purpose, first move the input focus of the EDIT control to the end of the text by sending a WPARAM to -1; then send an EM_REPLACESEL message to add the data back.

Invoke Closehandle, HREAD

When ReadFile returns NULL, you jump out of the loop and close the reader of the pipe.

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

New Post(0)