Integrate windows process

This commit is contained in:
Loic Guegan 2022-02-03 07:10:32 +01:00
parent 053b44639f
commit db4d104ed9
6 changed files with 187 additions and 8 deletions

View file

@ -2,11 +2,11 @@ cmake_minimum_required(VERSION 3.10)
project(uciadapter)
# Configure Process
add_definitions(-DUNIX)
SET(process src/ProcessLinux.cpp)
SET(COMPILE_PLATFORM UNIX)
if(WIN32)
remove_definitions(-DUNIX)
message(FATAL_ERROR "uciadapter is not yet compatible with Windows")
SET(process src/ProcessWindows.cpp)
SET(COMPILE_PLATFORM WIN32)
endif()
add_library(uciadapter SHARED src/UCI.cpp ${process})
@ -14,7 +14,7 @@ add_library(uciadapter SHARED src/UCI.cpp ${process})
set(UCIADAPTER_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/includes) # For conveniance
set(UCIADAPTER_INCLUDE_DIR ${UCIADAPTER_INCLUDE_DIR} PARENT_SCOPE) # To be used by other projects with add_subdirectory()
file(MAKE_DIRECTORY ${UCIADAPTER_INCLUDE_DIR})
configure_file(src/UCI.hpp ${UCIADAPTER_INCLUDE_DIR} COPYONLY)
configure_file(src/UCI.hpp.in ${UCIADAPTER_INCLUDE_DIR}/UCI.hpp)
configure_file(src/Process.hpp ${UCIADAPTER_INCLUDE_DIR} COPYONLY)
configure_file(src/ProcessLinux.hpp ${UCIADAPTER_INCLUDE_DIR} COPYONLY)
include_directories(${UCIADAPTER_INCLUDE_DIR})

View file

@ -4,7 +4,7 @@
# uciadapter
*uciadapter* is a C++ library that allows you to communicate with any chess
engines that follows the [UCI Protocol](http://wbec-ridderkerk.nl/html/UCIProtocol.html).
It aims to work on Linux and Windows (not yet on windows).
It works on both platforms, Linux and Windows.
# How to use it ?
PGNP can be used as a shared library in your project.

View file

@ -1,5 +1,4 @@
#include <string>
#define ENGINE_TIMEOUT 5 // In seconds
#define BUFFER_SIZE 1024
@ -12,7 +11,8 @@ public:
virtual void Kill() = 0;
/// @brief Start the engine from file path
virtual void Start(std::string) = 0;
/// @brief Read one line from the stdout of the engine (could raise a ReadTimeoutExpire)
/// @brief Read one line from the stdout of the engine (could raise a
/// ReadTimeoutExpire)
virtual std::string ReadLine() = 0;
/// @brief Write to engine stdin
virtual void Write(std::string) = 0;

148
src/ProcessWindows.cpp Normal file
View file

@ -0,0 +1,148 @@
#include "ProcessWindows.hpp"
#include <atlstr.h>
namespace uciadapter {
void ProcessWindows::CreateChildProcess(std::string engine_path)
// Create a child process that uses the previously created pipes for STDIN and
// STDOUT.
{
TCHAR szCmdline[1024];
_tcscpy_s(szCmdline, CA2T(engine_path.c_str()));
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
BOOL bSuccess = FALSE;
// Set up members of the PROCESS_INFORMATION structure.
ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
// Set up members of the STARTUPINFO structure.
// This structure specifies the STDIN and STDOUT handles for redirection.
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = g_hChildStd_OUT_Wr;
siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
siStartInfo.hStdInput = g_hChildStd_IN_Rd;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
// Create the child process.
bSuccess = CreateProcess(NULL,
szCmdline, // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
// If an error occurs, exit the application.
if (!bSuccess)
ErrorExit(TEXT("CreateProcess"));
else {
// Close handles to the child process and its primary thread.
// Some applications might keep these handles to monitor the status
// of the child process, for example.
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
// Close handles to the stdin and stdout pipes no longer needed by the child
// process. If they are not explicitly closed, there is no way to recognize
// that the child process has ended.
CloseHandle(g_hChildStd_OUT_Wr);
CloseHandle(g_hChildStd_IN_Rd);
}
}
void ProcessWindows::ErrorExit(PTSTR lpszFunction)
// Format a readable error message, display a message box,
// and exit from the application.
{
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpMsgBuf, 0, NULL);
lpDisplayBuf =
(LPVOID)LocalAlloc(LMEM_ZEROINIT, (lstrlen((LPCTSTR)lpMsgBuf) +
lstrlen((LPCTSTR)lpszFunction) + 40) *
sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf, LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"), lpszFunction, dw,
lpMsgBuf);
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
ExitProcess(1);
}
ProcessWindows::ProcessWindows() {
printf("\n->Start of parent execution.\n");
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0))
ErrorExit(TEXT("StdoutRd CreatePipe"));
// Ensure the read handle to the pipe for STDOUT is not inherited.
if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
ErrorExit(TEXT("Stdout SetHandleInformation"));
// Create a pipe for the child process's STDIN.
if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0))
ErrorExit(TEXT("Stdin CreatePipe"));
// Ensure the write handle to the pipe for STDIN is not inherited.
if (!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0))
ErrorExit(TEXT("Stdin SetHandleInformation"));
}
void ProcessWindows::Kill() {}
void ProcessWindows::Start(std::string path) { CreateChildProcess(path); }
std::string ProcessWindows::ReadLine() {
DWORD dwRead, dwWritten;
CHAR chBuf[2014];
BOOL bSuccess = FALSE;
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
std::string line = "";
for (;;) {
CHAR c;
bSuccess = ReadFile(g_hChildStd_OUT_Rd, &c, 1, &dwRead, NULL);
line += c;
if (!bSuccess || dwRead == 0)
break;
if (c == '\n')
break;
}
printf("ejeh\n");
return (line);
}
void ProcessWindows::Write(std::string data) {
DWORD dwRead, dwWritten;
CHAR chBuf[1024];
BOOL bSuccess = FALSE;
bSuccess =
WriteFile(g_hChildStd_IN_Wr, data.c_str(), data.size(), &dwWritten, NULL);
}
} // namespace uciadapter

27
src/ProcessWindows.hpp Normal file
View file

@ -0,0 +1,27 @@
#include "Process.hpp"
#include <chrono>
#include <stdio.h>
#include <strsafe.h>
#include <tchar.h>
#include <windows.h>
namespace uciadapter {
class ProcessWindows : public Process {
HANDLE g_hChildStd_IN_Rd = NULL;
HANDLE g_hChildStd_IN_Wr = NULL;
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
SECURITY_ATTRIBUTES saAttr;
void ProcessWindows::ErrorExit(PTSTR lpszFunction);
void ProcessWindows::CreateChildProcess(std::string);
public:
ProcessWindows();
void Kill();
void Start(std::string);
std::string ReadLine();
void Write(std::string);
};
}; // namespace uciadapter

View file

@ -1,9 +1,13 @@
#define @COMPILE_PLATFORM@
#ifdef UNIX
#include "ProcessLinux.hpp"
#define INIT_PROCESS(p) \
{ p = static_cast<Process *>(new ProcessLinux()); }
#else
#endif
#ifdef WIN32
#include "ProcessWindows.hpp"
#define INIT_PROCESS(p) \
{ p = static_cast<Process *>(new ProcessWindows()); }
#endif
#include <chrono>
#include <sstream>