all repos — mgba @ 1285aa2749e7cf4984829aa34a7f708220b6eb24

mGBA Game Boy Advance Emulator

src/third-party/discord-rpc/src/connection_win.cpp (view raw)

  1#include "connection.h"
  2
  3#define WIN32_LEAN_AND_MEAN
  4#define NOMCX
  5#define NOSERVICE
  6#define NOIME
  7#include <assert.h>
  8#include <windows.h>
  9
 10int GetProcessId()
 11{
 12    return (int)::GetCurrentProcessId();
 13}
 14
 15struct BaseConnectionWin : public BaseConnection {
 16    HANDLE pipe{INVALID_HANDLE_VALUE};
 17};
 18
 19static BaseConnectionWin Connection;
 20
 21/*static*/ BaseConnection* BaseConnection::Create()
 22{
 23    return &Connection;
 24}
 25
 26/*static*/ void BaseConnection::Destroy(BaseConnection*& c)
 27{
 28    auto self = reinterpret_cast<BaseConnectionWin*>(c);
 29    self->Close();
 30    c = nullptr;
 31}
 32
 33bool BaseConnection::Open()
 34{
 35    wchar_t pipeName[]{L"\\\\?\\pipe\\discord-ipc-0"};
 36    const size_t pipeDigit = sizeof(pipeName) / sizeof(wchar_t) - 2;
 37    pipeName[pipeDigit] = L'0';
 38    auto self = reinterpret_cast<BaseConnectionWin*>(this);
 39    for (;;) {
 40        self->pipe = ::CreateFileW(
 41          pipeName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
 42        if (self->pipe != INVALID_HANDLE_VALUE) {
 43            self->isOpen = true;
 44            return true;
 45        }
 46
 47        auto lastError = GetLastError();
 48        if (lastError == ERROR_FILE_NOT_FOUND) {
 49            if (pipeName[pipeDigit] < L'9') {
 50                pipeName[pipeDigit]++;
 51                continue;
 52            }
 53        }
 54        else if (lastError == ERROR_PIPE_BUSY) {
 55            if (!WaitNamedPipeW(pipeName, 10000)) {
 56                return false;
 57            }
 58            continue;
 59        }
 60        return false;
 61    }
 62}
 63
 64bool BaseConnection::Close()
 65{
 66    auto self = reinterpret_cast<BaseConnectionWin*>(this);
 67    ::CloseHandle(self->pipe);
 68    self->pipe = INVALID_HANDLE_VALUE;
 69    self->isOpen = false;
 70    return true;
 71}
 72
 73bool BaseConnection::Write(const void* data, size_t length)
 74{
 75    if (length == 0) {
 76        return true;
 77    }
 78    auto self = reinterpret_cast<BaseConnectionWin*>(this);
 79    assert(self);
 80    if (!self) {
 81        return false;
 82    }
 83    if (self->pipe == INVALID_HANDLE_VALUE) {
 84        return false;
 85    }
 86    assert(data);
 87    if (!data) {
 88        return false;
 89    }
 90    const DWORD bytesLength = (DWORD)length;
 91    DWORD bytesWritten = 0;
 92    return ::WriteFile(self->pipe, data, bytesLength, &bytesWritten, nullptr) == TRUE &&
 93      bytesWritten == bytesLength;
 94}
 95
 96bool BaseConnection::Read(void* data, size_t length)
 97{
 98    assert(data);
 99    if (!data) {
100        return false;
101    }
102    auto self = reinterpret_cast<BaseConnectionWin*>(this);
103    assert(self);
104    if (!self) {
105        return false;
106    }
107    if (self->pipe == INVALID_HANDLE_VALUE) {
108        return false;
109    }
110    DWORD bytesAvailable = 0;
111    if (::PeekNamedPipe(self->pipe, nullptr, 0, nullptr, &bytesAvailable, nullptr)) {
112        if (bytesAvailable >= length) {
113            DWORD bytesToRead = (DWORD)length;
114            DWORD bytesRead = 0;
115            if (::ReadFile(self->pipe, data, bytesToRead, &bytesRead, nullptr) == TRUE) {
116                assert(bytesToRead == bytesRead);
117                return true;
118            }
119            else {
120                Close();
121            }
122        }
123    }
124    else {
125        Close();
126    }
127    return false;
128}