From the GUI perspective the engine is a process. Free Pascal defines a class TProcess, where you can specify something like the command line to the executable, what pipes are used and so on. When the GUI lanches it calles TProcess.Execute which starts the engine. It is running as process in the background. You see no engine window but it is listed in the Windows Task Manager process list.
To send something to the engine you add a CRLF (#13#10) to the string (defined in the UCI protocol) and call engine.Input.Write
To look for input and receive it from the engine you use
if Process.Output.NumBytesAvailable>0 then ReadCnt := Process.Output.Read(ReadBuf[Length(ReadBuf) - BUF_INC + 1], BUF_INC) else ReadCnt:=0;
Process.Output.NumBytesAvailable is very useful because it allows you to check whether there is any input at all and if not just return. In pipe communication trying to read from a pipe that is empty might block you execution until input becomes available in the pipe.
On the engine side of the communication Process.Output.NumBytesAvailable does not exist and this makes the interface on the engine side much more difficult and brings some nasty consequences.
More to that in another post