connection_win.cpp
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 10 int GetProcessId() 11 { 12 return (int)::GetCurrentProcessId(); 13 } 14 15 struct BaseConnectionWin : public BaseConnection { 16 HANDLE pipe{INVALID_HANDLE_VALUE}; 17 }; 18 19 static 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 33 bool 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 64 bool 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 73 bool 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 96 bool 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 }