| ||
Q. Are there methods of organizing information exchange between running applications?
I have already described various methods of synchronization and using the shared memory. There is another interesting approach implemented in Windows anonymous (unnamed) pipes. [i] This approach is the most efficient for organizing information exchange with the console process generated by the current process. Assume that you need your console process started by some application (e.g., some string compiler) to output information to the edit window of the primary process instead of to console. The example of such application is shown in Listing 18.3.
// The PIPE.RC file // Constant definitions #define WS_SYSMENU 0x00080000L #define WS_VISIBLE 0x100000000L #define WS_TABSTOP 0x00010000L #define WS_VSCROLL 0x00200000L #define DS_3DLOOK 0x0004L #define ES_LEFT 0x0000L #define WS_CHILD 0x40000000L #define WS_BORDER 0x00800000L #define ES_MULTILINE 0x0004L #define WS_VSCROLL 0x00200000L #define WS_HSCROLL 0x00100000L MENUP MENU { POPUP "&Start the program" { MENUITEM "S&tart", 200 MENUITEM "E&xit the program", 300 } } // Dialog box definition DIAL1 DIALOG 0, 0, 200, 140 STYLE WS_SYSMENU DS_3DLOOK CAPTION "Example of PIPE use" FONT 8, "Arial" { CONTROL "", 101, "edit", ES_LEFT ES_MULTILINE WS_VISIBLE WS_BORDER WS_VSCROLL WS_HSCROLL, 24, 20, 128, 70 } ; The PIPE.INC file ; Constants SW_HIDE equ 0 SW_SHOWNORMAL equ 1 STARTFJJSESHOWWINDOW equ 1h STARTF_USESTDHANDLES equ 100h STARTF_ADD = STARTFUSESHOWWINDOW + STARTF_USESTDHANDLES ; This message arrives when the window is closed WM_CLOSE equ 10h WM_INITDIALOG equ 110h WM_COMMAND equ 111h EM_REPLACESEL equ 0C2h ; Prototypes of external procedures IFDEF MASM EXTERN ReadFile@20:NEAR EXTERN CloseHandle@4:NEAR EXTERN CreatePipe@16:NEAR EXTERN SetMenu@8:NEAR EXTERN LoadMenuA@8:NEAR EXTERN CreateProcessA@40:NEAR EXTERN ExitProcess@4:NEAR EXTERN GetModuleHandleA@4:NEAR EXTERN DialogBoxParamA@20:NEAR EXTERN EndDialog@8:NEAR EXTERN SendDlgItemMessageA@20:NEAR ELSE EXTERN ReadFile:NEAR EXTERN CloseHandle:NEAR EXTERN CreatePipe:NEAR EXTERN TerminateProcess: NEAR EXTERN WaitForSingleObject:NEAR EXTERN SetMenu:NEAR EXTERN LoadMenuA:NEAR EXTERN CreateProcessA:NEAR EXTERN ExitProcess:NEAR EXTERN GetModuleHandleA:NEAR EXTERN DialogBoxParamA:NEAR EXTERN EndDialog:NEAR EXTERN SendDlgItemMessageA:NEAR ReadFile@20 = ReadFile CloseHandle@4 = CloseHandle CreatePipe@16 = CreatePipe TerminateProcess@8 = TerminateProcess WaitForSingleObject@8 = WaitForSingleObject SetMenu@8 = SetMenu LoadMenuA@8 = LoadMenuA CreateProcessA@40 = CreateProcessA ExitProcess@4 = ExitProcess GetModuleHandleA@4 = GetModuleHandleA DialogBoxParamA@20 = DialogBoxParamA EndDialog@8 = EndDialog SendDlgItemMessageA@20 = SendDlgItemMessageA ENDIF ; Structures ; Message structure MSGSTRUCT STRUC MSHWND DD ? MSMESSAGE DD ? MSWPARAM DD ? MSLPARAM DD ? MSTIME DD ? MSPT DD ? MSGSTRUCT ENDS ; Structure for CreateProcess STARTUP STRUC cb DD 0 lpReserved DD 0 lpDesktop DD 0 lpTitle DD 0 dwX DD 0 dwY DD 0 dwXSize DD 0 dwYSize DD 0 dwXCountChars DD 0 dwYCountChars DD 0 dwFillAttribute DD 0 dwFlags DD 0 wShowWindow DW 0 cbReserved2 DW 0 lpReserved2 DD 0 hStdInput DD 0 hStdOutput DD 0 hStdError DD 0 STARTUP ENDS ; Structure - Information about the process PROCINF STRUC hProcess DD ? hThread DD ? Idproc DD ? idThr DD ? PROCINF ENDS ; The PIPE.ASM file .586P ; Flat memory model .MODEL FLAT, stdcall include pipe.inc ; INCLUDELIB directives for the linker IFDEF MASM includelib c:\masm32\lib\user32.lib includelib c:\masm32\lib\kernel32.lib ELSE includelib c:\tasm32\lib\import32.lib ENDIF ;--------------------------------------------- ; Data segment _DATA SEGMENT STRUP STARTUP <?> INF PROCINF <?> MSG MSGSTRUCT <?> HINST DD 0 ; Application descriptor PA DB "DIAL1", 0 CMD DB "c:\tasm32\bin\tlink32.exe", 0 PMENU DB "MENUP", 0 HW DD ? HR DD ? BUFER DB 3000 DUP(0) BYT DD ? _DATA ENDS ; Code segment _TEXT SEGMENT START: ; Get the application handle PUSH 0 CALL GetModuleHandleA@4 MOV [HINST], EAX ;-------------------------------- PUSH 0 PUSH OFFSET WNDPROC PUSH 0 PUSH OFFSET PA PUSH [HINST] CALL DialogBoxParamA@20 CMP EAX, -1 JNE KOL ; Error message KOL: ;------------------------------- PUSH 0 CALL ExitProcess@4 ;------------------------------- ; Window procedure ; Position of parameters in the stack ; [BP+014H] ; LPARAM ; [BP+10H] ; WAPARAM ; [BP+0CH] ; MES ; [BP+8] ; HWND WNDPROC PROC PUSH EBP MOV EBP, ESP PUSH EBX PUSH ESI PUSH EDI ----------------- CMP DWORD PTR [EBP+0CH], WM_CLOSE JNE L1 L3: PUSH 0 PUSH DWORD PTR [EBP+08H] CALL EndDialog@8 JMP FINISH L1: CMP DWORD PTR [EBP+0CH], WM_INITDIALOG JNE L2 ; Load the menu PUSH OFFSET PMENU PUSH [HINST] CALL LoadMenuA@8 ; Set the menu PUSH EAX PUSH DWORD PTR [EBP+08H] CALL SetMenu@8 JMP FINISH L2: CMP DWORD PTR [EBP+0CH], WM_COMMAND JNE FINISH CMP WORD PTR [EBP+10H], 300 JE L3 CMP WORD PTR [EBP+10H], 200 JNE FINISH ; Startup here ; PIPE in the beginning PUSH 0 PUSH 0 PUSH OFFSET HW PUSH OFFSET HR CALL CreatePipe@16 MOV EAX, HW ; Console application starts here MOV STRUP.cb, 68 MOV STRUP.lpReserved, 0 MOV STRUP.lpDesktop, 0 MOV STRUP.lpTitle, 0 MOV STRUP.dwFlags, STARTF_ADD MOV STRUP.cbReserved2, 0 MOV STRUP.lpReserved2, 0 MOV STRUP.wShowWindow, SW_HIDE ; Process window is invisible MOV STRUP.hStdOutput, EAX MOV STRUP.hStdError, EAX ;------------------------------ PUSH OFFSET INF PUSH OFFSET STRUP PUSH 0 PUSH 0 PUSH 0 PUSH 1 ; Inherit descriptors PUSH 0 PUSH 0 PUSH OFFSET CMD PUSH 0 CALL CreateProcessA@40 ; Read information PUSH 0 PUSH OFFSET BYT PUSH 3000 PUSH OFFSET BUFER PUSH HR CALL ReadFile@20 PUSH OFFSET BUFER PUSH 0 PUSH EM_REPLACESEL PUSH 101 PUSH DWORD PTR [EBP+08H] CALL SendDlgItemMessageA@20 ; Close the handle for writing PUSH HW CALL CloseHandle@4 ; Close the handle for reading PUSH HR CALL CloseHandle@4 FINISH: MOV EAX, 0 POP EDI POP ESI POP EBX POP EBP RET 16 WNDPROC ENDP _TEXT ENDS END START
The underlying idea of pipes is easy. When creating a process, it is possible to assign it the appropriate pipe descriptor as the input or the output descriptor. After that, it will be possible to organize information exchange between two processes using the WriteFile and ReadFile functions.
To translate the program presented in Listing 18.3, issue the following commands using MASM32:
ml /c /coff /DMASM pipe.asm rc pipe.rc link /subsystem:windows pipe.obj pipe.res
Issue the following commands using TASM32:
tasm32 /ml pipe.asm brcc32 pipe.rc tlink32 -aa pipe.obj,,,,,pipe.res
The program that you just considered requires some comments.
Starting a console application is a complicated task. Therefore, I won't dive into details. In the program in Listing 18.3, this procedure is practically no different from the one used in Chapter 15 for starting the WINWORD.EXE application. Consider, however, new features implemented in this program. Note that the EditBox control plays an interesting role here. This window element plays the role of the output console. To achieve this, set the ES_MULTILINE property, which displays the entire text sent to the window using the EM_REPLACESEL message. To read the information, a large buffer is used. Principally, it is possible to read the data in smaller portions, checking the number of read bytes as with files.
[i] So-called named pipes are implemented in Windows NT.
| ||