Page 1 of 1

gui for gtp engines in c#, how?

Posted: Tue Jan 17, 2012 6:07 am
by blade90
I want to make a simple GUI for GTP engines in C#, because I'm learning C# and want to know this for curiosity.
But the problem is how can I start a engine in gtp mode, send commands to it and receive the output?
After hours of search and trying everything out I still wasn't able to do it.
This is all I found: http://www.codeproject.com/KB/cs/ProcessStartDemo.aspx
Those who know C# will realize that this does not work. Because it this method will always wait for the process to end before reading the output. Reading the output while it runs results in freezing the GUI.

Is it even possible in C#? If yes how? If not are there any tutorials or documentation for C++? (I only know basics about C++)
Is it possible to write a DLL in C++ that does sending commands and receive the output - and use it in a C# application?

Re: gui for gtp engines in c#, how?

Posted: Tue Jan 17, 2012 6:16 am
by msgreg
You would have to start the program in another thread or use BeginOutputReadline for an asynchronous call.

Doing this as your first C# program is going to be a challenge unless you have threading experience from other languages or OSes.

Re: gui for gtp engines in c#, how?

Posted: Tue Jan 17, 2012 7:35 am
by blade90
It's not my first C# program, I already made a few but never something like threading and all this.
I used BeginOutputReadline but it does not work how I want, the problem is to send more then only one command to the engine.
The first command in my case sends "list_commands" to gnugo and receive the list.
The second command sends "showboard" but then it freezes, I made many changes and now it tells me "you cannot write in a closed TextWriter". That confuses me because the code is:

Code: Select all

StreamWriter Writer = Engine.StandardInput;
Writer.WriteLine(Command);
Writer.Close(); // Without this the command won't be send


Looks like I can't open it again until I restart the engine itself.

Re: gui for gtp engines in c#, how?

Posted: Tue Jan 17, 2012 7:39 am
by msgreg
Try flush()

Post again with results or questions. You're on the right track.

Re: gui for gtp engines in c#, how?

Posted: Tue Jan 17, 2012 8:49 am
by blade90
msgreg wrote:Try flush()

Post again with results or questions. You're on the right track.

flush() does nothing, the engine never recives the command.
When I close my application then it sends the command, in other words as soon as TextWriter has been closed.

Re: gui for gtp engines in c#, how?

Posted: Mon Jan 23, 2012 4:37 pm
by Rémi
What you want to do is very complicated in Windows. Below is some C++ code I wrote to start a process and setup pipes for communication. I suppose C# has access to the same kind of Windows API.

Then you should use threads for I/O, which is also complicated.

Rémi

Code: Select all

 //
 // Set the bInheritHandle flag so pipe handles are inherited.
 //
 SECURITY_ATTRIBUTES saAttr;
 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
 saAttr.bInheritHandle = TRUE;
 saAttr.lpSecurityDescriptor = 0;

 //
 // Redirect child process's STDOUT:
 //
 HANDLE hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);
 {
  HANDLE hChildStdoutRd;
  CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0);
  SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr);
  DuplicateHandle(GetCurrentProcess(),
                  hChildStdoutRd,
                  GetCurrentProcess(),
                  &hChildStdoutRdDup ,
                  0,
                  FALSE,
                  DUPLICATE_SAME_ACCESS);
  CloseHandle(hChildStdoutRd);
 }

 //
 // Redirect child process's STDIN:
 //
 HANDLE hSaveStdin = GetStdHandle(STD_INPUT_HANDLE);
 {
  HANDLE hChildStdinWr;
  CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0);
  SetStdHandle(STD_INPUT_HANDLE, hChildStdinRd);
  DuplicateHandle(GetCurrentProcess(),
                  hChildStdinWr,
                  GetCurrentProcess(),
                  &hChildStdinWrDup,
                  0,
                  FALSE,
                  DUPLICATE_SAME_ACCESS);
  CloseHandle(hChildStdinWr);
 }

 //
 // Now create the child process.
 //
 {
  STARTUPINFO siStartInfo;
  ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
  siStartInfo.cb = sizeof(STARTUPINFO);
  fHasChild = CreateProcess(0,
                            pszCommandLine,
                            0,
                            0,
                            TRUE,
                            0,
                            0,
                            sDirectory.c_str(),
                            &siStartInfo,
                            &piProcInfo);
 }

 //
 // After process creation, restore the saved STDIN and STDOUT.
 //
 SetStdHandle(STD_INPUT_HANDLE, hSaveStdin);
 SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout);