?? 021.txt
字號:
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,hwndEdit,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
.else
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
.else
invoke CloseHandle,hWrite
.while TRUE
invoke RtlZeroMemory,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,hwndEdit,EM_REPLACESEL,FALSE,addr buffer
.endw
.endif
invoke CloseHandle,hRead
.endif
.endif
.endif
.elseif uMsg==WM_DESTROY
invoke PostQuitMessage,NULL
.else
invoke DefWindowProc,hWnd,uMsg,wParam,lParam ret
.endif
xor eax,eax
ret
WndProc endp
end start
分析:
這個例子調用 ml.exe 來匯編一個名為 test.asm 的程序,并且重定向 ml.exe 的輸出到客戶區的 Edit 控件中。當程序被加載時,象往常一樣要注冊窗口類和創建主窗口。在主窗口被創建的過程中要做的第一件事就是創建用于顯示程序 ml.exe 輸出的 Edit 控件。
現在有趣的事來了,我們將改變此 Edit 控件的文本顏色和背景色。當 Edit 控件將要重畫客戶區時,它會給父窗口發送 WM_CTLCOLOREDIT 消息。參數 wParam 包含了用于畫控件自己的客戶區設備描述符的句柄 (HDC) 。我們可以利用這種機制來修改 HDC 的特性。
.elseif uMsg==WM_CTLCOLOREDIT
invoke SetTextColor,wParam,Yellow
invoke SetTextColor,wParam,Black
invoke GetStockObject,BLACK_BRUSH
ret
SetTextColor 把文本顏色變為黃色,背景顏色變為黑色。最后我們返回一個通過調用GetStockObject 而得到黑色刷子的句柄。處理WM_CTLCOLOREDIT 必須返回一個刷子的句柄,因為 Windows 將要使用這個刷子來重畫 Edit 控件的背景。在這個例子中,我希望背景是黑色,所以返回了一個黑色刷子的句柄。
現在當用戶選擇 Assemble 子菜單時,就會創建一個匿名管道。
.if ax==IDM_ASSEMBLE
mov sat.niLength,sizeof SECURITY_ATTRIBUTES
mov sat.lpSecurityDescriptor,NULL
mov sat.bInheritHandle,TRUE
在調用CreatePipe 之前,必須要填寫SECURITY_ATTRIBUTES 結構。如果我們不關心安全性的話,可以在lpSecurityDescriptor 成員中填入 NULL 。bInheritHandle 則必須為 TRUE ,這樣管道的句柄才可以被子進程繼承。
invoke CreatePipe,addr hRead,addr hWrite,addr sat,NULL
在此之后,我們調用CreatePipe 來創建管道,如果成功,那么變量hRead 和 hWrite 將分別被填入相應的管道的讀出端和寫入端的句柄。
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
下一步就是填寫STARTUPINFO 結構了。調用 GetStartupinfo 用父進程的缺省值來填寫STARTUPINFO 結構。如果要使程序同時工作在 Windows9x 和 Windows NT 下,就必須調用GetStartupInfo 來填寫STARTUPINFO 結構。調用返回后,就可以修改重要的成員了。因為我們要子進程輸出到父進程而不是缺省的標準輸出和標準錯誤,所以我們把hStdOutput 和 hStdError 都賦成管道寫端的句柄。為了隱藏子進程的主窗口,必須把成員變量wShowWidow 賦值為SW_HIDE 。最后通過把成員 dwFlags 賦值為STARTF_USESHOWWINDOW 和 STARTF_USESTDHANDLES 來指明成員hStdOutput, hStdError 和 wShowWindow 是有效的。
invoke CreateProcess, NULL, addr CommandLine, NULL, NULL, TRUE, NULL, NULL, NULL, addr startupinfo, addr pinfo
現在調用CreateProcess 來創建子進程。注意為使管道工作,參數bInheritHandles 必須設置為TRUE。 invoke CloseHandle,hWrite 成功創建子進程之后,在父進程中必須關閉管道的寫端。我們已經把寫端的句柄通過結構STARTUPINFO 傳給了子進程。如果不關閉,那么管道就有兩個寫入端,而這樣的管道是不會工作的。所以必須在創建子進程后但在讀數據前關閉這個句柄。
.while TRUE
invoke RtlZeroMemory,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,hwndEdit,EM_REPLACESEL,FALSE,addr buffer
.endw
現在已經準備好從子進程的標準輸出讀數據了。直到再也沒有數據了,即 ReadFile 返回為 NULL時才會退出循環,否則一直會等待數據。我們調用ReadFile 之前先調用RtlZeroMemory 來清空內存,并且用管道的讀句柄代替文件句柄。注意讀數據的最大長度為 1023 ( sizeof(buffer)-1 ),因為我們需要把接受的字符變為一個 Edit 控件可以處理的 ASCII 串。當ReadFile 返回時,就把此數據傳給 Edit 控件。然而這有一個小小的問題,如果使用SetWindowText API 往 Edit 控件中寫數據,新數據就會覆蓋已存在的舊數據,而我們想把新數據添加在已有數據的后面。為達此目的,首先通過發送一個 wParam 為-1的 EM_SETSEL 消息,把 Edit 控件的輸入焦點移動到文本的末端;然后發送一個 EM_REPLACESEL 消息把數據添加后面。
invoke CloseHandle,hRead
當ReadFile 返回為NULL時,就跳出循環并關閉管道的讀句柄。
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -