Skip to content

Instantly share code, notes, and snippets.

@Bak-Jin-Hyeong
Last active May 13, 2017 04:48
Show Gist options
  • Save Bak-Jin-Hyeong/b0b4843c92b485d6d89d8ecf4f200e29 to your computer and use it in GitHub Desktop.
Save Bak-Jin-Hyeong/b0b4843c92b485d6d89d8ecf4f200e29 to your computer and use it in GitHub Desktop.
#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