; 测试程序test.exe会用标准输出/错误/输出句柄进行I/O,并在之后死循环,用来测试WriteFile()阻塞的情况
; 可以在WM_CREATE消息处理时用如invoke SendDlgItemMessage,hWnd,EDIT_OUTPUT,EM_SETSEL,-1,0
;invoke SendDlgItemMessage,hWnd,EDIT_OUTPUT,EM_REPLACESEL,FALSE,lParam的函数调用来向EDIT控件中添加输出,而
; 不用等EDIT控件先显示出来
include common.asm
EDIT_OUTPUT = 3
EDIT_INPUT = 4
BTN_INPUT = 5
CY_EDIT_INPUT = 25
CX_BTN_INPUT = 50
CY_BTN_INPUT = CY_EDIT_INPUT
BORDER = 3 ; 各控件间的间隔,包括与主窗口边框间的
WM_CHILDOUTPUT = WM_USER + 101H
.data
hInstance dd ?
hWndMain dd ?
szBuf db 256 dup (?)
.code
ReadThreadProc proc param
local @cbReadWritten
local @szBuf[256]:byte
comment /*
To read from the pipe, a process uses the read handle in a call to the ReadFile function. ReadFile returns when one of the following is true: a write operation completes on the write end of the pipe, the number of bytes requested has been read, or an error occurs. 这三个条件即:有数据可读;读完指定字节数的数据;出错
*/
.while 1
invoke ReadFile,param,addr @szBuf,sizeof @szBuf -1, \
addr @cbReadWritten, NULL ; 可能阻塞
.if eax ; 读到一些数据
mov eax, @cbReadWritten
mov @szBuf[eax], 0
invoke SendMessage, hWndMain, WM_CHILDOUTPUT, 0, addr @szBuf
.else ; 不加这个,会死循环,占用大量CPU时间
;msgbox ,CTXT("ReadFile() ERROR!")
; 子进程结束后,ReadFile()会出错,last error为ERROR_BROKEN_PIPE
.break ;
.endif
.endw
ret
ReadThreadProc endp
WriteThreadProc proc param
local @cbReadWritten
comment /*
When a process uses WriteFile to write to an anonymous pipe, the write operation is not completed until all bytes are written. If the pipe buffer is full before all bytes are written, WriteFile does not return until another process or thread uses ReadFile to make more buffer space available.
*/
invoke lstrlen, addr szBuf
mov ebx, eax
invoke WriteFile,param,addr szBuf, ebx, \
addr @cbReadWritten, NULL ;可能会阻塞
;.if !eax ; 子进程结束后,WriteFile()会出错, last error为ERROR_NO_DATA
; msgbox ,CTXT("WriteFile() ERROR!")
;.endif
ret
WriteThreadProc endp
WndProc proc uses ebx esi edi hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
local @startupinfo:STARTUPINFO
local @sat:SECURITY_ATTRIBUTES
static _pinfo, PROCESS_INFORMATION, <<>>
static _hRead,dword, INVALID_HANDLE_VALUE
static _hWrite,dword,INVALID_HANDLE_VALUE
static _hRead2,dword,INVALID_HANDLE_VALUE
static _hWrite2,dword,INVALID_HANDLE_VALUE
static _hWriteThread, dword, NULL
.if uMsg==WM_COMMAND
.if !lParam
return 0
.endif
mov eax, wParam
mov edx, eax
and eax, 0ffffh
shr edx, 16
.if edx!=BN_CLICKED
return 0
.endif
.if eax!=BTN_INPUT
return 0
.endif
.if _hWriteThread ; 已创建过写管道线程
push eax
invoke GetExitCodeThread,_hWriteThread, esp
pop eax ;exit code
.if eax==STILL_ACTIVE ; 很可能被阻塞
msgbox hWndMain, CTXT("The pipe's buffer maybe is full now. Try it again later."),\
CTXT("info")
return 0 ;
.else ; 已终止
invoke CloseHandle,_hWriteThread
mov _hWriteThread, NULL
.endif
.endif
invoke GetDlgItemText,hWnd,EDIT_INPUT,addr szBuf, sizeof szBuf-2
.if _hWrite!=INVALID_HANDLE_VALUE
mov szBuf[eax], CR ; 在输入框中什么也不输,则输入回车
mov szBuf[eax+1], LF
mov szBuf[eax+2], 0
push eax
invoke CreateThread, NULL, 0, offset WriteThreadProc, _hWrite, 0, esp
pop edx ;Thread id
mov _hWriteThread, eax
.endif
.elseif uMsg==WM_CHILDOUTPUT
invoke SendDlgItemMessage,hWnd,EDIT_OUTPUT,EM_SETSEL,-1,0 ;或-1,-1
invoke SendDlgItemMessage,hWnd,EDIT_OUTPUT,EM_REPLACESEL,FALSE,lParam
.elseif uMsg==WM_CTLCOLOREDIT
comment /*
An edit control that is not read-only or disabled sends the WM_CTLCOLOREDIT message to its parent window when the control is about to be drawn.
*/
invoke SetTextColor, wParam, Magenta ;洋红
invoke SetBkColor, wParam, White
invoke GetStockObject, WHITE_BRUSH
ret ;
.elseif uMsg==WM_CTLCOLORSTATIC
comment /*
Read-only or disabled edit controls do not send the WM_CTLCOLOREDIT message; instead, they send the WM_CTLCOLORSTATIC message.
*/
invoke SetTextColor, wParam, Yellow
invoke SetBkColor, wParam, Black
invoke GetStockObject, BLACK_BRUSH
ret
.elseif uMsg==WM_SIZE
invoke GetDlgItem, hWnd, EDIT_OUTPUT
mov ebx, eax
mov eax, lParam
mov edx, eax
and eax, 0ffffh
mov esi, eax ;
sub eax, BORDER*2 ; 各控件间的间隔,包括与主窗口边框间的
shr edx, 16
mov edi, edx ;
sub edx, CY_EDIT_INPUT+BORDER*3
invoke MoveWindow,ebx,BORDER,BORDER, eax, edx, TRUE
invoke GetDlgItem, hWnd, EDIT_INPUT
mov ecx, edi
sub ecx, CY_EDIT_INPUT+BORDER
mov edx, esi
sub edx, CX_BTN_INPUT+BORDER*3
invoke MoveWindow,eax,BORDER,ecx,edx, CY_EDIT_INPUT, TRUE
invoke GetDlgItem, hWnd, BTN_INPUT
mov ecx, esi
sub ecx, CX_BTN_INPUT+BORDER
mov edx, edi
sub edx, CY_BTN_INPUT+BORDER
invoke MoveWindow,eax,ecx,edx,CX_BTN_INPUT,CY_BTN_INPUT,TRUE
.elseif uMsg==WM_CREATE
invoke CreateWindowEx,NULL, CTXT("edit"),NULL,\
WS_CHILD or WS_VISIBLE or ES_MULTILINE or WS_BORDER or \
ES_AUTOHSCROLL or ES_AUTOVSCROLL or ES_READONLY,\
0,0,0,0,hWnd,EDIT_OUTPUT,hInstance,NULL
invoke CreateWindowEx,NULL, CTXT("edit"), CTXT("dir"),\
WS_CHILD or WS_VISIBLE or WS_BORDER or\
ES_AUTOHSCROLL or WS_TABSTOP,\
0,0,0,0,hWnd,EDIT_INPUT,hInstance,NULL
invoke CreateWindowEx,NULL, CTXT("button"), CTXT("input"),\
WS_CHILD or WS_VISIBLE or WS_TABSTOP or WS_BORDER,\
0,0,0,0,hWnd,BTN_INPUT,hInstance,NULL
mov @sat.nLength, sizeof @sat
mov @sat.lpSecurityDescriptor, NULL
mov @sat.bInheritHandle, TRUE
; 这一个管道用来向子进程传递信息,即由父进程写给子进程,父进程使用_hWrite
invoke CreatePipe, addr _hRead, addr _hWrite, addr @sat, NULL
; use the default buffer size
.if !eax
invoke MessageBox,hWnd,CTXT("Error during pipe creation"),\
CTXT("One-way Pipe Example"),MB_ICONERROR or MB_OK
return 0
.endif
; 这一个管道用来从子进程读取信息,即父进程读子进程写到管道的内容,父进程使用_hRead2
invoke CreatePipe, addr _hRead2, addr _hWrite2, addr @sat, NULL
.if !eax
invoke CloseHandle, _hRead
mov _hRead, INVALID_HANDLE_VALUE
invoke CloseHandle,_hWrite
mov _hWrite, INVALID_HANDLE_VALUE
invoke MessageBox,hWnd,CTXT("Error during pipe creation"),\
CTXT("One-way Pipe Example"),MB_ICONERROR or MB_OK
return 0
.endif
mov @startupinfo.cb, sizeof @startupinfo
invoke GetStartupInfo, addr @startupinfo
m2m @startupinfo.hStdInput, _hRead
m2m @startupinfo.hStdOutput, _hWrite2
m2m @startupinfo.hStdError, _hWrite2
mov @startupinfo.dwFlags, STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW
mov @startupinfo.wShowWindow, SW_HIDE ;
invoke CreateProcess,NULL,CTXT("cmd"),\
NULL,NULL,TRUE,NULL,NULL,NULL,addr @startupinfo, addr _pinfo
.if !eax
invoke MessageBox,hWnd,CTXT("Error during process creation"),\
CTXT("One-way Pipe Example"),MB_ICONERROR or MB_OK
invoke CloseHandle, _hRead
mov _hRead, INVALID_HANDLE_VALUE
invoke CloseHandle,_hWrite
mov _hWrite, INVALID_HANDLE_VALUE
invoke CloseHandle,_hRead2
mov _hRead2, INVALID_HANDLE_VALUE
invoke CloseHandle, _hWrite2
mov _hWrite2, INVALID_HANDLE_VALUE
return 0
.endif
invoke CloseHandle, _hRead
mov _hRead, INVALID_HANDLE_VALUE
invoke CloseHandle, _hWrite2
mov _hWrite2, INVALID_HANDLE_VALUE
invoke CloseHandle, _pinfo.hThread
mov _pinfo.hThread, NULL
push eax
invoke CreateThread, NULL, 0, offset ReadThreadProc, _hRead2, 0, esp
pop edx ;thread id
invoke CloseHandle, eax
.elseif uMsg==WM_DESTROY
.if _hWrite!=INVALID_HANDLE_VALUE
invoke CloseHandle,_hWrite
mov _hWrite, INVALID_HANDLE_VALUE
.endif
.if _hRead2!=INVALID_HANDLE_VALUE
invoke CloseHandle,_hRead2
mov _hRead2, INVALID_HANDLE_VALUE
.endif
.if _hWriteThread
invoke CloseHandle, _hWriteThread
mov _hWriteThread, NULL
.endif
.if _pinfo.hProcess
push eax
invoke GetExitCodeProcess,_pinfo.hProcess, esp
pop eax ;exit code
.if eax==STILL_ACTIVE
invoke TerminateProcess,_pinfo.hProcess,0
.endif
invoke CloseHandle,_pinfo.hProcess
mov _pinfo.hProcess, NULL
.endif
invoke PostQuitMessage, 0
.else
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif
return 0
WndProc endp
start proc
local @wc:WNDCLASSEX
local @msg:MSG
invoke GetModuleHandle, NULL
mov hInstance,eax
mov @wc.cbSize, sizeof @wc
mov @wc.style, CS_HREDRAW or CS_VREDRAW
mov @wc.lpfnWndProc, offset WndProc
mov @wc.cbClsExtra, 0
mov @wc.cbWndExtra, 0
m2m @wc.hInstance, hInstance
mov @wc.hbrBackground, COLOR_APPWORKSPACE+1
mov @wc.lpszMenuName, NULL
mov @wc.lpszClassName, CTXT("PipeWinClass")
invoke LoadIcon, 0, IDI_APPLICATION
mov @wc.hIcon,eax
mov @wc.hIconSm,eax
invoke LoadCursor, 0, IDC_ARROW
mov @wc.hCursor,eax
invoke RegisterClassEx, addr @wc
invoke CreateWindowEx,WS_EX_CLIENTEDGE, CTXT("PipeWinClass"),CTXT("One-way Pipe Example"),\
WS_OVERLAPPEDWINDOW or WS_VISIBLE,CW_USEDEFAULT,\
CW_USEDEFAULT,400,200,NULL,NULL,\
hInstance, NULL
mov hWndMain, eax
.while 1
invoke GetMessage, addr @msg,NULL,0,0
.break .if !eax
invoke IsDialogMessage, hWndMain, addr @msg
.continue .if eax
invoke TranslateMessage, addr @msg
invoke DispatchMessage, addr @msg
.endw
invoke ExitProcess, @msg.wParam
start endp
end start
---------------------------------------------------------------
; test.asm
include common.asm
.code
start proc
local @szBuf[8]:byte
invoke SetConsoleTitle, CTXT("CONSOLE DEMO")
invoke _StdOut, CTXT("HELLO, CONSOLE!", CR, LF)
invoke _StdErr, CTXT("你好!", CR, LF)
invoke _StdIn, addr @szBuf, sizeof @szBuf
invoke _StdOut, addr @szBuf
invoke _GetFileRootPathName, CTXT("j:abc.txt"), addr @szBuf
invoke _StdOut, addr @szBuf
.while 1
invoke Sleep, 3000
.endw
xor eax, eax
ret
start endp
end start