194 lines
4.8 KiB
C++
194 lines
4.8 KiB
C++
#pragma once
|
|
|
|
#include <Windows.h>
|
|
#include <string>
|
|
#include <memory>
|
|
#include <cstdint>
|
|
#include "Domain/Services/ServiceLocator.h"
|
|
|
|
#define BUFFER_SIZE 16384
|
|
|
|
class NamedPipe
|
|
{
|
|
public:
|
|
const bool Connect(const std::wstring& pipeName)
|
|
{
|
|
if (m_Pipe == NULL || m_PipeName != pipeName)
|
|
{
|
|
if (m_Pipe != NULL) {
|
|
DisconnectNamedPipe(m_Pipe);
|
|
CloseHandle(m_Pipe);
|
|
}
|
|
else
|
|
{
|
|
CreateOverlapped(m_ConntectingOverlapped);
|
|
CreateOverlapped(m_ReadingOverlapped);
|
|
CreateOverlapped(m_WritingOverlapped);
|
|
}
|
|
|
|
m_Pipe = CreateNamedPipeW((L"\\\\.\\pipe\\" + pipeName).c_str(),
|
|
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
|
|
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
|
|
PIPE_UNLIMITED_INSTANCES,
|
|
BUFFER_SIZE * sizeof(wchar_t),
|
|
BUFFER_SIZE * sizeof(wchar_t),
|
|
NMPWAIT_USE_DEFAULT_WAIT,
|
|
NULL
|
|
);
|
|
|
|
if (m_Pipe == INVALID_HANDLE_VALUE)
|
|
{
|
|
Services::ServiceLocator::GetInstance().GetLogger()->Error(L"cannot connect to the pipe ""{}""", m_PipeName);
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DisconnectNamedPipe(m_Pipe);
|
|
}
|
|
|
|
TryToConnect();
|
|
|
|
WaitForMultipleObjects(1, &m_ConntectingOverlapped.hEvent, false, INFINITE);
|
|
|
|
DWORD ret;
|
|
m_Connected = GetOverlappedResult(m_Pipe, &m_ConntectingOverlapped, &ret, false);
|
|
|
|
m_PipeName = pipeName;
|
|
|
|
return m_Connected;
|
|
}
|
|
|
|
void Send(const std::wstring& message)
|
|
{
|
|
if (!m_Connected)
|
|
{
|
|
return;
|
|
}
|
|
|
|
const std::wstring preparedMessage = message + L"\n";
|
|
|
|
DWORD written;
|
|
const auto result = WriteFile(m_Pipe, message.c_str(), (message.size() + 1) * sizeof(wchar_t), &written, &m_WritingOverlapped);
|
|
|
|
const auto lastError = GetLastError();
|
|
if (!result)
|
|
{
|
|
if (lastError == ERROR_IO_PENDING)
|
|
{
|
|
WaitForMultipleObjects(1, &m_WritingOverlapped.hEvent, false, INFINITE);
|
|
DWORD ret;
|
|
const auto overlappedResult = GetOverlappedResult(m_Pipe, &m_WritingOverlapped, &ret, false);
|
|
if (!overlappedResult)
|
|
{
|
|
Services::ServiceLocator::GetInstance().GetLogger()->Error(L"cannot get overlapped result for the pipe ""{}"" when writing", m_PipeName);
|
|
m_Connected = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Services::ServiceLocator::GetInstance().GetLogger()->Error(L"cannot write to the pipe ""{}"": {}", m_PipeName, lastError);
|
|
m_Connected = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
const std::wstring Receive()
|
|
{
|
|
if (!m_Connected)
|
|
{
|
|
return L"";
|
|
}
|
|
|
|
DWORD dwRead;
|
|
std::unique_ptr<wchar_t[]> buffer = std::make_unique<wchar_t[]>(BUFFER_SIZE);
|
|
const auto result = ReadFile(m_Pipe, buffer.get(), BUFFER_SIZE * sizeof(wchar_t), &dwRead, &m_ReadingOverlapped);
|
|
|
|
const auto lastError = GetLastError();
|
|
if (!result)
|
|
{
|
|
if (lastError == ERROR_IO_PENDING)
|
|
{
|
|
WaitForMultipleObjects(1, &m_ReadingOverlapped.hEvent, false, INFINITE);
|
|
DWORD ret;
|
|
const auto overlappedResult = GetOverlappedResult(m_Pipe, &m_ReadingOverlapped, &ret, false);
|
|
if (!overlappedResult)
|
|
{
|
|
Services::ServiceLocator::GetInstance().GetLogger()->Error(L"cannot get overlapped result for the pipe ""{}"" when reading", m_PipeName);
|
|
m_Connected = false;
|
|
return L"";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Services::ServiceLocator::GetInstance().GetLogger()->Error(L"cannot read from the pipe ""{}"": {}", m_PipeName, lastError);
|
|
m_Connected = false;
|
|
return L"";
|
|
}
|
|
}
|
|
|
|
std::wstring message = std::wstring(buffer.get());
|
|
|
|
return message;
|
|
}
|
|
|
|
const bool IsConnected() const
|
|
{
|
|
return m_Connected;
|
|
}
|
|
|
|
virtual ~NamedPipe()
|
|
{
|
|
if (m_Pipe != NULL)
|
|
{
|
|
CloseHandle(m_Pipe);
|
|
}
|
|
}
|
|
NamedPipe() = default;
|
|
|
|
private:
|
|
void TryToConnect()
|
|
{
|
|
const bool connected = ConnectNamedPipe(m_Pipe, &m_ConntectingOverlapped) == 0;
|
|
if (!connected)
|
|
{
|
|
Services::ServiceLocator::GetInstance().GetLogger()->Error(L"cannot connect to the pipe ""{}"": {}", m_PipeName, GetLastError());
|
|
}
|
|
|
|
switch (GetLastError())
|
|
{
|
|
// The overlapped connection in progress.
|
|
case ERROR_IO_PENDING:
|
|
break;
|
|
// Client is already connected, so signal an event.
|
|
case ERROR_PIPE_CONNECTED:
|
|
if (SetEvent(m_ConntectingOverlapped.hEvent))
|
|
break;
|
|
default:
|
|
Services::ServiceLocator::GetInstance().GetLogger()->Error(L"an error has occurred when connecting to the pipe ""{}"": {}", m_PipeName, GetLastError());
|
|
}
|
|
}
|
|
|
|
void CreateOverlapped(OVERLAPPED& overlapped)
|
|
{
|
|
if (overlapped.hEvent == NULL)
|
|
{
|
|
overlapped.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
|
|
if (overlapped.hEvent == NULL)
|
|
{
|
|
Services::ServiceLocator::GetInstance().GetLogger()->Error(L"cannot create overlapped for the pipe ""{}"": {}", m_PipeName, GetLastError());
|
|
return;
|
|
}
|
|
overlapped.Offset = 0;
|
|
overlapped.OffsetHigh = 0;
|
|
}
|
|
}
|
|
|
|
private:
|
|
std::wstring m_PipeName = L"";
|
|
HANDLE m_Pipe = NULL;
|
|
bool m_Connected = false;
|
|
OVERLAPPED m_ConntectingOverlapped = OVERLAPPED();
|
|
OVERLAPPED m_ReadingOverlapped = OVERLAPPED();
|
|
OVERLAPPED m_WritingOverlapped = OVERLAPPED();
|
|
}; |