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}