mirror of
https://gitlab.com/manzerbredes/uciadapter.git
synced 2025-04-05 17:46:27 +02:00
Integrate windows process
This commit is contained in:
parent
053b44639f
commit
db4d104ed9
6 changed files with 187 additions and 8 deletions
|
@ -2,11 +2,11 @@ cmake_minimum_required(VERSION 3.10)
|
||||||
project(uciadapter)
|
project(uciadapter)
|
||||||
|
|
||||||
# Configure Process
|
# Configure Process
|
||||||
add_definitions(-DUNIX)
|
|
||||||
SET(process src/ProcessLinux.cpp)
|
SET(process src/ProcessLinux.cpp)
|
||||||
|
SET(COMPILE_PLATFORM UNIX)
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
remove_definitions(-DUNIX)
|
SET(process src/ProcessWindows.cpp)
|
||||||
message(FATAL_ERROR "uciadapter is not yet compatible with Windows")
|
SET(COMPILE_PLATFORM WIN32)
|
||||||
endif()
|
endif()
|
||||||
add_library(uciadapter SHARED src/UCI.cpp ${process})
|
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 ${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()
|
set(UCIADAPTER_INCLUDE_DIR ${UCIADAPTER_INCLUDE_DIR} PARENT_SCOPE) # To be used by other projects with add_subdirectory()
|
||||||
file(MAKE_DIRECTORY ${UCIADAPTER_INCLUDE_DIR})
|
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/Process.hpp ${UCIADAPTER_INCLUDE_DIR} COPYONLY)
|
||||||
configure_file(src/ProcessLinux.hpp ${UCIADAPTER_INCLUDE_DIR} COPYONLY)
|
configure_file(src/ProcessLinux.hpp ${UCIADAPTER_INCLUDE_DIR} COPYONLY)
|
||||||
include_directories(${UCIADAPTER_INCLUDE_DIR})
|
include_directories(${UCIADAPTER_INCLUDE_DIR})
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
# uciadapter
|
# uciadapter
|
||||||
*uciadapter* is a C++ library that allows you to communicate with any chess
|
*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).
|
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 ?
|
# How to use it ?
|
||||||
PGNP can be used as a shared library in your project.
|
PGNP can be used as a shared library in your project.
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#define ENGINE_TIMEOUT 5 // In seconds
|
#define ENGINE_TIMEOUT 5 // In seconds
|
||||||
#define BUFFER_SIZE 1024
|
#define BUFFER_SIZE 1024
|
||||||
|
|
||||||
|
@ -12,7 +11,8 @@ public:
|
||||||
virtual void Kill() = 0;
|
virtual void Kill() = 0;
|
||||||
/// @brief Start the engine from file path
|
/// @brief Start the engine from file path
|
||||||
virtual void Start(std::string) = 0;
|
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;
|
virtual std::string ReadLine() = 0;
|
||||||
/// @brief Write to engine stdin
|
/// @brief Write to engine stdin
|
||||||
virtual void Write(std::string) = 0;
|
virtual void Write(std::string) = 0;
|
||||||
|
|
148
src/ProcessWindows.cpp
Normal file
148
src/ProcessWindows.cpp
Normal 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
27
src/ProcessWindows.hpp
Normal 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
|
|
@ -1,9 +1,13 @@
|
||||||
|
#define @COMPILE_PLATFORM@
|
||||||
#ifdef UNIX
|
#ifdef UNIX
|
||||||
#include "ProcessLinux.hpp"
|
#include "ProcessLinux.hpp"
|
||||||
#define INIT_PROCESS(p) \
|
#define INIT_PROCESS(p) \
|
||||||
{ p = static_cast<Process *>(new ProcessLinux()); }
|
{ p = static_cast<Process *>(new ProcessLinux()); }
|
||||||
#else
|
#endif
|
||||||
|
#ifdef WIN32
|
||||||
#include "ProcessWindows.hpp"
|
#include "ProcessWindows.hpp"
|
||||||
|
#define INIT_PROCESS(p) \
|
||||||
|
{ p = static_cast<Process *>(new ProcessWindows()); }
|
||||||
#endif
|
#endif
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <sstream>
|
#include <sstream>
|
Loading…
Add table
Reference in a new issue