Last active
May 13, 2017 04:48
-
-
Save Bak-Jin-Hyeong/b0b4843c92b485d6d89d8ecf4f200e29 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef ANONYMOUSPIPE__HPP__ | |
#define ANONYMOUSPIPE__HPP__ | |
#if !defined(_WINDOWS_) && !defined(__AFX_H__) | |
#define WIN32_LEAN_AND_MEAN | |
#include <Windows.h> | |
#endif | |
#include <cstdlib> | |
#include <cstdio> | |
template<HANDLE Invalid = nullptr> | |
struct ScopedWin32Handle { | |
public: | |
ScopedWin32Handle(); | |
explicit ScopedWin32Handle(HANDLE attachment); | |
ScopedWin32Handle(ScopedWin32Handle&& other); | |
~ScopedWin32Handle(); | |
ScopedWin32Handle& operator=(ScopedWin32Handle&& rhs); | |
HANDLE Underlying() const; | |
bool Valid() const; | |
void Swap(ScopedWin32Handle& other); | |
void Attach(HANDLE h); | |
HANDLE Detach(); | |
void Close(); | |
private: | |
HANDLE handle = Invalid; | |
private: | |
ScopedWin32Handle(const ScopedWin32Handle&) = delete; | |
void operator=(const ScopedWin32Handle&) = delete; | |
}; | |
template<HANDLE Invalid> | |
ScopedWin32Handle<Invalid>::ScopedWin32Handle() = default; | |
template<HANDLE Invalid> | |
ScopedWin32Handle<Invalid>::ScopedWin32Handle(HANDLE attachment) | |
: handle{ attachment } { | |
} | |
template<HANDLE Invalid> | |
ScopedWin32Handle<Invalid>::ScopedWin32Handle(ScopedWin32Handle&& other) | |
: handle{ other.handle } { | |
other.handle = Invalid; | |
} | |
template<HANDLE Invalid> ScopedWin32Handle<Invalid>::~ScopedWin32Handle() { | |
Close(); | |
} | |
template<HANDLE Invalid> | |
ScopedWin32Handle<Invalid>& | |
ScopedWin32Handle<Invalid>::operator=(ScopedWin32Handle&& other) { | |
if (this != &other) { | |
Attach(other.Detach()); | |
} | |
return *this; | |
} | |
template<HANDLE Invalid> | |
HANDLE ScopedWin32Handle<Invalid>::Underlying() const { | |
return handle; | |
} | |
template<HANDLE Invalid> bool ScopedWin32Handle<Invalid>::Valid() const { | |
return handle != Invalid; | |
} | |
template<HANDLE Invalid> | |
void ScopedWin32Handle<Invalid>::Swap(ScopedWin32Handle& other) { | |
auto h = handle; | |
handle = other.handle; | |
other.handle = h; | |
} | |
template<HANDLE Invalid> void ScopedWin32Handle<Invalid>::Attach(HANDLE h) { | |
auto x = handle; | |
handle = h; | |
if (x != Invalid) { | |
::CloseHandle(x); | |
} | |
} | |
template<HANDLE Invalid> HANDLE ScopedWin32Handle<Invalid>::Detach() { | |
auto x = handle; | |
handle = Invalid; | |
return x; | |
} | |
template<HANDLE Invalid> void ScopedWin32Handle<Invalid>::Close() { | |
Attach(Invalid); | |
} | |
class AnonymousReadPipe; | |
class AnonymousWritePipe; | |
class AnonymousPipe : private ScopedWin32Handle<> { | |
public: | |
static const size_t required_parameter_buffer_length = 64; | |
enum class Inheritable { | |
Read, | |
Write, | |
}; | |
struct IOResult { | |
int error; | |
DWORD numBytes; | |
}; | |
struct Pair; | |
using ScopedWin32Handle<>::Underlying; | |
using ScopedWin32Handle<>::Valid; | |
using ScopedWin32Handle<>::Attach; | |
using ScopedWin32Handle<>::Detach; | |
using ScopedWin32Handle<>::Close; | |
static Pair Create(Inheritable inheritence, DWORD size); | |
static Pair AcquireFromParameters(int argc, wchar_t* argv[]); | |
template<size_t bufferCapacity> | |
static bool BuildParameters( | |
const AnonymousReadPipe& r, const AnonymousWritePipe& w, | |
wchar_t(&buffer)[bufferCapacity]); | |
protected: | |
AnonymousPipe(); | |
explicit AnonymousPipe(HANDLE attachment); | |
~AnonymousPipe(); | |
private: | |
AnonymousPipe(const AnonymousPipe&) = delete; | |
void operator=(const AnonymousPipe&) = delete; | |
}; | |
class AnonymousReadPipe : public AnonymousPipe { | |
public: | |
AnonymousReadPipe() = default; | |
explicit AnonymousReadPipe(HANDLE attachment); | |
AnonymousReadPipe(AnonymousReadPipe&&); | |
~AnonymousReadPipe() = default; | |
AnonymousReadPipe& operator=(AnonymousReadPipe&&); | |
IOResult Read(void* buffer, DWORD cbToRead); | |
}; | |
class AnonymousWritePipe : public AnonymousPipe { | |
public: | |
AnonymousWritePipe() = default; | |
explicit AnonymousWritePipe(HANDLE attachment); | |
AnonymousWritePipe(AnonymousWritePipe&&); | |
~AnonymousWritePipe() = default; | |
AnonymousWritePipe& operator=(AnonymousWritePipe&&); | |
IOResult Write(const void* buffer, DWORD cbToWrite); | |
}; | |
struct AnonymousPipe::Pair { | |
AnonymousReadPipe r; | |
AnonymousWritePipe w; | |
}; | |
inline AnonymousPipe::AnonymousPipe() = default; | |
inline AnonymousPipe::~AnonymousPipe() = default; | |
inline AnonymousPipe::AnonymousPipe(HANDLE attachment) | |
: ScopedWin32Handle{ attachment } { | |
} | |
inline AnonymousPipe::Pair AnonymousPipe::Create( | |
Inheritable inheritable, DWORD size) { | |
HANDLE r = nullptr; | |
HANDLE w = nullptr; | |
SECURITY_ATTRIBUTES sa = { sizeof(sa), nullptr, true }; | |
if (!::CreatePipe(&r, &w, &sa, size)) { | |
return{}; | |
} | |
auto MakeNonInheritable = [](HANDLE source) -> HANDLE { | |
auto p = GetCurrentProcess(); | |
HANDLE duplicated = nullptr; | |
const auto b = ::DuplicateHandle(p, source, p, &duplicated, | |
DUPLICATE_SAME_ACCESS, false, DUPLICATE_SAME_ACCESS); | |
::CloseHandle(source); | |
if (b) { | |
return duplicated; | |
} | |
else { | |
if (duplicated) { | |
::CloseHandle(duplicated); | |
} | |
return{}; | |
} | |
}; | |
if (inheritable == Inheritable::Write) { | |
r = MakeNonInheritable(r); | |
} | |
else if (inheritable == Inheritable::Read) { | |
w = MakeNonInheritable(w); | |
} | |
Pair result{ AnonymousReadPipe{ r }, AnonymousWritePipe{ w } }; | |
if (result.r.Valid() && result.w.Valid()) { | |
return result; | |
} | |
else { | |
return{}; | |
} | |
} | |
inline AnonymousPipe::Pair | |
AnonymousPipe::AcquireFromParameters(int argc, wchar_t* argv[]) { | |
Pair p; | |
for (int i = 0; i < argc; ++i) { | |
const auto a = argv[i]; | |
if (!p.r.Valid() && _wcsnicmp(L"-ReadPipe=", a, 10) == 0) { | |
auto h = static_cast<uintptr_t>(wcstoull(a + 10, nullptr, 16)); | |
p.r.Attach(reinterpret_cast<HANDLE>(h)); | |
} | |
else if ( | |
!p.w.Valid() && _wcsnicmp(L"-WritePipe=", a, 11) == 0) { | |
auto h = static_cast<uintptr_t>(wcstoull(a + 11, nullptr, 16)); | |
p.w.Attach(reinterpret_cast<HANDLE>(h)); | |
} | |
} | |
return p; | |
} | |
template<size_t bufferCapacity> | |
inline bool AnonymousPipe::BuildParameters( | |
const AnonymousReadPipe& r, const AnonymousWritePipe& w, | |
wchar_t(&buffer)[bufferCapacity]) { | |
const auto format = L"-ReadPipe=%p -WritePipe=%p"; | |
const auto required = _scwprintf(format, r.Underlying(), w.Underlying()); | |
_snwprintf_s(buffer, _TRUNCATE, format, r.Underlying(), w.Underlying()); | |
return static_cast<size_t>(required) < bufferCapacity; | |
} | |
AnonymousReadPipe::AnonymousReadPipe(HANDLE attachment) | |
: AnonymousPipe(attachment) { | |
} | |
AnonymousReadPipe::AnonymousReadPipe(AnonymousReadPipe&& other) { | |
Attach(other.Detach()); | |
} | |
AnonymousReadPipe& AnonymousReadPipe::operator=(AnonymousReadPipe&& rhs) { | |
if (this != &rhs) { | |
Attach(rhs.Detach()); | |
} | |
return *this; | |
} | |
inline AnonymousPipe::IOResult | |
AnonymousReadPipe::Read(void* buffer, DWORD cbToRead) { | |
DWORD read = 0; | |
if (!::ReadFile(Underlying(), buffer, cbToRead, &read, nullptr)) { | |
return{ static_cast<int>(::GetLastError()), read }; | |
} | |
return{ 0, read }; | |
} | |
AnonymousWritePipe::AnonymousWritePipe(HANDLE attachment) | |
: AnonymousPipe(attachment) { | |
} | |
AnonymousWritePipe::AnonymousWritePipe(AnonymousWritePipe&& other) { | |
Attach(other.Detach()); | |
} | |
AnonymousWritePipe& AnonymousWritePipe::operator=(AnonymousWritePipe&& rhs) { | |
if (this != &rhs) { | |
Attach(rhs.Detach()); | |
} | |
return *this; | |
} | |
inline AnonymousPipe::IOResult | |
AnonymousWritePipe::Write(const void* buffer, DWORD cbToWrite) { | |
DWORD written = 0; | |
if (!::WriteFile(Underlying(), buffer, cbToWrite, &written, nullptr)) { | |
return{ static_cast<int>(::GetLastError()), written }; | |
} | |
return{ 0, written }; | |
} | |
#endif // #ifndef ANONYMOUSPIPE__HPP__ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment