| Left: | ||
| Right: |
| LEFT | RIGHT |
|---|---|
| 1 #include <AdblockPlus.h> | 1 #include <AdblockPlus.h> |
| 2 #include <iostream> | 2 #include <iostream> |
| 3 #include <Lmcons.h> | |
| 3 #include <ShlObj.h> | 4 #include <ShlObj.h> |
| 4 #include <sstream> | 5 #include <sstream> |
| 5 #include <vector> | 6 #include <vector> |
| 6 #include <Windows.h> | 7 #include <Windows.h> |
| 7 #include <Sddl.h> | 8 #include <Sddl.h> |
|
Wladimir Palant
2013/05/16 11:52:16
I think that the usual order of includes is from g
Felix Dahlke
2013/05/17 09:11:36
We're using alphabetical in most places, but it's
| |
| 8 | 9 |
| 9 namespace | 10 namespace |
| 10 { | 11 { |
| 11 const std::wstring pipeName = L"\\\\.\\pipe\\adblockplusengine"; | 12 std::wstring GetUserName() |
| 13 { | |
| 14 const DWORD maxLength = UNLEN + 1; | |
| 15 std::auto_ptr<wchar_t> buffer(new wchar_t[maxLength]); | |
| 16 DWORD length = maxLength; | |
| 17 if (!::GetUserName(buffer.get(), &length)) | |
| 18 { | |
| 19 std::stringstream stream; | |
| 20 stream << "Failed to get the current user's name (Error code: " << GetLast Error() << ")"; | |
| 21 throw std::runtime_error("Failed to get the current user's name"); | |
| 22 } | |
| 23 return std::wstring(buffer.get(), length); | |
| 24 } | |
| 25 | |
| 26 const std::wstring pipeName = L"\\\\.\\pipe\\adblockplusengine_" + GetUserName (); | |
| 12 const int bufferSize = 1024; | 27 const int bufferSize = 1024; |
| 13 std::auto_ptr<AdblockPlus::FilterEngine> filterEngine; | 28 std::auto_ptr<AdblockPlus::FilterEngine> filterEngine; |
| 14 HANDLE filterEngineMutex; | |
| 15 | 29 |
| 16 class AutoHandle | 30 class AutoHandle |
| 17 { | 31 { |
| 18 public: | 32 public: |
| 19 AutoHandle() | 33 AutoHandle() |
| 20 { | 34 { |
| 21 } | 35 } |
| 22 | 36 |
| 23 AutoHandle(HANDLE handle) : handle(handle) | 37 AutoHandle(HANDLE handle) : handle(handle) |
| 24 { | 38 { |
| 25 } | 39 } |
| 26 | 40 |
| 27 ~AutoHandle() | 41 ~AutoHandle() |
| 28 { | 42 { |
| 29 CloseHandle(handle); | 43 CloseHandle(handle); |
| 30 } | 44 } |
| 31 | 45 |
| 32 HANDLE get() | 46 HANDLE get() |
| 33 { | 47 { |
| 34 return handle; | 48 return handle; |
| 35 } | 49 } |
| 36 | 50 |
| 37 private: | 51 private: |
| 38 HANDLE handle; | 52 HANDLE handle; |
| 39 static int references; | |
|
Wladimir Palant
2013/05/16 11:52:16
Unused member?
Felix Dahlke
2013/05/23 12:31:20
Done.
| |
| 40 | 53 |
| 41 AutoHandle(const AutoHandle& autoHandle); | 54 AutoHandle(const AutoHandle& autoHandle); |
| 42 AutoHandle& operator=(const AutoHandle& autoHandle); | 55 AutoHandle& operator=(const AutoHandle& autoHandle); |
| 43 }; | 56 }; |
| 44 | 57 |
| 45 void Log(const std::string& message) | 58 void Log(const std::string& message) |
| 46 { | 59 { |
| 47 // TODO: Log to a log file | 60 // TODO: Log to a log file |
| 48 MessageBoxA(0, ("AdblockPlusEngine: " + message).c_str(), "", MB_OK); | 61 MessageBoxA(0, ("AdblockPlusEngine: " + message).c_str(), "", MB_OK); |
| 49 } | 62 } |
| 50 | 63 |
| 51 void LogLastError(const std::string& message) | 64 void LogLastError(const std::string& message) |
| 52 { | 65 { |
| 53 std::stringstream stream; | 66 std::stringstream stream; |
| 54 stream << message << " (Error code: " << GetLastError() << ")"; | 67 stream << message << " (Error code: " << GetLastError() << ")"; |
| 55 Log(stream.str()); | 68 Log(stream.str()); |
| 56 } | 69 } |
| 57 | 70 |
| 58 void LogException(const std::exception& exception) | 71 void LogException(const std::exception& exception) |
| 59 { | 72 { |
| 60 Log(std::string("An exception occurred: ") + exception.what()); | 73 Log(std::string("An exception occurred: ") + exception.what()); |
| 61 } | 74 } |
| 62 | 75 |
| 63 std::string MarshalStrings(const std::vector<std::string>& strings) | 76 std::string MarshalStrings(const std::vector<std::string>& strings) |
| 64 { | 77 { |
| 65 // TODO: This is some pretty hacky marshalling, replace it with something mo re robust | 78 // TODO: This is some pretty hacky marshalling, replace it with something mo re robust |
|
Wladimir Palant
2013/05/16 11:52:16
That's an understatement :)
| |
| 66 std::string marshalledStrings; | 79 std::string marshalledStrings; |
| 67 for (std::vector<std::string>::const_iterator it = strings.begin(); it != st rings.end(); it++) | 80 for (std::vector<std::string>::const_iterator it = strings.begin(); it != st rings.end(); it++) |
| 68 marshalledStrings += *it + ';'; | 81 marshalledStrings += *it + ';'; |
| 69 return marshalledStrings; | 82 return marshalledStrings; |
| 70 } | 83 } |
| 71 | 84 |
| 72 std::vector<std::string> UnmarshalStrings(const std::string& message) | 85 std::vector<std::string> UnmarshalStrings(const std::string& message) |
| 73 { | 86 { |
| 74 std::stringstream stream(message); | 87 std::stringstream stream(message); |
| 75 std::vector<std::string> strings; | 88 std::vector<std::string> strings; |
| 76 std::string string; | 89 std::string string; |
| 77 while (std::getline(stream, string, ';')) | 90 while (std::getline(stream, string, ';')) |
| 78 strings.push_back(string); | 91 strings.push_back(string); |
| 79 return strings; | 92 return strings; |
| 80 } | 93 } |
| 81 | 94 |
| 82 std::string ToString(std::wstring value) | 95 std::string ToUtf8String(std::wstring str) |
| 83 { | 96 { |
| 84 int size = WideCharToMultiByte(CP_UTF8, 0, value.c_str(), -1, 0, 0, 0, 0); | 97 size_t length = str.size(); |
|
Wladimir Palant
2013/05/16 11:52:16
WideCharToMultiByte() will return 0 on error, this
Felix Dahlke
2013/05/23 12:31:20
Done. Learnt something here: I thought std::string
| |
| 85 char* converted = new char[size]; | 98 if (length == 0) |
|
Wladimir Palant
2013/05/16 11:52:16
std::auto_ptr please, don't delete manually.
Felix Dahlke
2013/05/23 12:31:20
Done.
| |
| 86 WideCharToMultiByte(CP_UTF8, 0, value.c_str(), -1, converted, size, 0, 0); | 99 return std::string(); |
| 87 std::string string(converted); | 100 |
|
Wladimir Palant
2013/05/16 11:52:16
string(converted, size) please - you have an expli
Felix Dahlke
2013/05/17 09:11:36
Writing directly to the string buffer is still not
Felix Dahlke
2013/05/23 12:31:20
Decided to keep the function after all. ToUTF8Stri
Wladimir Palant
2013/05/23 14:25:01
No real objections but the function name should at
Felix Dahlke
2013/05/23 19:10:44
Just copied the function from libadblockplus, alth
| |
| 88 delete converted; | 101 DWORD utf8StringLength = WideCharToMultiByte(CP_UTF8, 0, str.c_str(), length , 0, 0, 0, 0); |
| 89 return string; | 102 if (utf8StringLength == 0) |
| 103 throw std::runtime_error("Failed to determine the required buffer size"); | |
| 104 | |
| 105 std::string utf8String(utf8StringLength, '\0'); | |
| 106 WideCharToMultiByte(CP_UTF8, 0, str.c_str(), length, &utf8String[0], utf8Str ingLength, 0, 0); | |
| 107 return utf8String; | |
| 90 } | 108 } |
| 91 | 109 |
| 92 std::string ReadMessage(HANDLE pipe) | 110 std::string ReadMessage(HANDLE pipe) |
| 93 { | 111 { |
| 94 std::stringstream stream; | 112 std::stringstream stream; |
| 95 std::auto_ptr<char> buffer(new char[bufferSize]); | 113 std::auto_ptr<char> buffer(new char[bufferSize]); |
| 96 bool hasError; | 114 bool doneReading = false; |
| 97 do | 115 while (!doneReading) |
| 98 { | 116 { |
| 99 DWORD bytesRead; | 117 DWORD bytesRead; |
| 100 hasError = !ReadFile(pipe, buffer.get(), bufferSize * sizeof(char), &bytes Read, 0); | 118 if (ReadFile(pipe, buffer.get(), bufferSize * sizeof(char), &bytesRead, 0) ) |
| 101 if (hasError && GetLastError() != ERROR_MORE_DATA) | 119 doneReading = true; |
| 120 else if (GetLastError() != ERROR_MORE_DATA) | |
| 102 { | 121 { |
| 103 std::stringstream stream; | 122 std::stringstream stream; |
| 104 stream << "Error reading from pipe: " << GetLastError(); | 123 stream << "Error reading from pipe: " << GetLastError(); |
| 105 throw std::runtime_error(stream.str()); | 124 throw std::runtime_error(stream.str()); |
| 106 } | 125 } |
| 107 stream << std::string(buffer.get(), bytesRead); | 126 stream << std::string(buffer.get(), bytesRead); |
| 108 } while (hasError); | 127 } |
|
Wladimir Palant
2013/05/16 11:52:16
The flow is rather hard to follow here, particular
Felix Dahlke
2013/05/23 12:31:20
Done.
| |
| 109 return stream.str(); | 128 return stream.str(); |
| 110 } | 129 } |
| 111 | 130 |
| 112 void WriteMessage(HANDLE pipe, const std::string& message) | 131 void WriteMessage(HANDLE pipe, const std::string& message) |
| 113 { | 132 { |
| 114 DWORD bytesWritten; | 133 DWORD bytesWritten; |
| 115 if (!WriteFile(pipe, message.c_str(), message.length(), &bytesWritten, 0)) | 134 if (!WriteFile(pipe, message.c_str(), message.length(), &bytesWritten, 0)) |
| 116 throw std::runtime_error("Failed to write to pipe"); | 135 throw std::runtime_error("Failed to write to pipe"); |
|
Wladimir Palant
2013/05/16 11:52:16
What if bytesWritten < message.length()? According
Felix Dahlke
2013/05/17 09:11:36
Yes, it's blocking. And writing long strings works
| |
| 117 } | 136 } |
| 118 | 137 |
| 119 std::string HandleRequest(const std::vector<std::string>& strings) | 138 std::string HandleRequest(const std::vector<std::string>& strings) |
| 120 { | 139 { |
| 121 std::string procedureName = strings[0]; | 140 std::string procedureName = strings[0]; |
| 122 if (procedureName == "Matches") | 141 if (procedureName == "Matches") |
| 123 return filterEngine->Matches(strings[1], strings[2], strings[3]) ? "1" : " 0"; | 142 return filterEngine->Matches(strings[1], strings[2], strings[3]) ? "1" : " 0"; |
| 124 if (procedureName == "GetElementHidingSelectors") | 143 if (procedureName == "GetElementHidingSelectors") |
| 125 return MarshalStrings(filterEngine->GetElementHidingSelectors(strings[1])) ; | 144 return MarshalStrings(filterEngine->GetElementHidingSelectors(strings[1])) ; |
| 126 return ""; | 145 return ""; |
| 127 } | 146 } |
| 128 | 147 |
| 129 DWORD WINAPI ClientThread(LPVOID param) | 148 DWORD WINAPI ClientThread(LPVOID param) |
| 130 { | 149 { |
| 131 HANDLE pipe = static_cast<HANDLE>(param); | 150 HANDLE pipe = static_cast<HANDLE>(param); |
| 132 | 151 |
| 133 try | 152 try |
| 134 { | 153 { |
| 135 std::string message = ReadMessage(pipe); | 154 std::string message = ReadMessage(pipe); |
| 136 std::vector<std::string> strings = UnmarshalStrings(message); | 155 std::vector<std::string> strings = UnmarshalStrings(message); |
| 137 WaitForSingleObject(filterEngineMutex, INFINITE); | |
|
Wladimir Palant
2013/05/16 11:52:16
Doesn't this duplicate the functionality of mutexe
Felix Dahlke
2013/05/23 12:31:20
Done.
| |
| 138 std::string response = HandleRequest(strings); | 156 std::string response = HandleRequest(strings); |
| 139 ReleaseMutex(filterEngineMutex); | |
| 140 WriteMessage(pipe, response); | 157 WriteMessage(pipe, response); |
| 141 } | 158 } |
| 142 catch (const std::exception& e) | 159 catch (const std::exception& e) |
| 143 { | 160 { |
| 144 LogException(e); | 161 LogException(e); |
| 145 } | 162 } |
| 146 | 163 |
| 164 // TODO: Keep the pipe open until the client disconnects | |
| 147 FlushFileBuffers(pipe); | 165 FlushFileBuffers(pipe); |
| 148 DisconnectNamedPipe(pipe); | 166 DisconnectNamedPipe(pipe); |
| 149 CloseHandle(pipe); | 167 CloseHandle(pipe); |
|
Wladimir Palant
2013/05/16 11:52:16
Opening a new connection for each calls sounds lik
Felix Dahlke
2013/05/17 09:11:36
I previously read that there is a limit to the num
Felix Dahlke
2013/05/23 12:31:20
Began to work on this, but it's a bit tricky and I
| |
| 150 return 0; | 168 return 0; |
| 151 } | 169 } |
| 152 } | 170 |
| 153 | 171 bool IsWindowsVistaOrLater() |
| 154 bool IsWindowsVistaOrLater() | 172 { |
|
Wladimir Palant
2013/05/16 11:52:16
Any reason why some functions are inside an empty
Felix Dahlke
2013/05/17 09:11:36
Forgot to move it there.
| |
| 155 { | 173 OSVERSIONINFOEX osvi; |
| 156 OSVERSIONINFOEX osvi; | 174 ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); |
| 157 ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); | 175 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); |
| 158 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); | 176 GetVersionEx(reinterpret_cast<LPOSVERSIONINFO>(&osvi)); |
| 159 GetVersionEx(reinterpret_cast<LPOSVERSIONINFO>(&osvi)); | 177 return osvi.dwMajorVersion >= 6; |
| 160 return osvi.dwMajorVersion >= 6; | 178 } |
| 161 } | 179 } |
| 162 | 180 |
| 163 std::wstring GetAppDataPath() | 181 std::wstring GetAppDataPath() |
| 164 { | 182 { |
| 165 wchar_t appDataPath[MAX_PATH]; | 183 std::wstring appDataPath; |
| 166 if (IsWindowsVistaOrLater()) | 184 if (IsWindowsVistaOrLater()) |
| 167 { | 185 { |
| 168 WCHAR* dataPath; | 186 WCHAR* pathBuffer; |
| 169 if (FAILED(SHGetKnownFolderPath(FOLDERID_LocalAppDataLow, 0, 0, &dataPath))) | 187 if (FAILED(SHGetKnownFolderPath(FOLDERID_LocalAppDataLow, 0, 0, &pathBuffer) )) |
|
Wladimir Palant
2013/05/16 11:52:16
I don't think that statically compiling against SH
Felix Dahlke
2013/05/23 12:31:20
I'll leave this to Oleksandr, since he's working o
Oleksandr
2013/05/23 12:38:11
We are not statically compiling against SHGetKnown
| |
| 170 throw std::runtime_error("Unable to find app data directory"); | 188 throw std::runtime_error("Unable to find app data directory"); |
| 171 wcscpy_s(appDataPath, dataPath); | 189 appDataPath.assign(pathBuffer); |
|
Wladimir Palant
2013/05/16 11:52:16
Why do we need two copy operations here? Convertin
Felix Dahlke
2013/05/17 09:11:36
I think that's because SHGetKnownFolderPath wants
Wladimir Palant
2013/05/17 10:35:02
Then maybe get rid of that assumption? :)
Declare
Felix Dahlke
2013/05/23 12:31:20
Done.
| |
| 172 CoTaskMemFree(dataPath); | 190 CoTaskMemFree(pathBuffer); |
| 173 } | 191 } |
| 174 else | 192 else |
| 175 { | 193 { |
| 176 if (!SHGetSpecialFolderPath(0, appDataPath, CSIDL_LOCAL_APPDATA, true)) | 194 std::auto_ptr<wchar_t> pathBuffer(new wchar_t[MAX_PATH]); |
| 195 if (!SHGetSpecialFolderPath(0, pathBuffer.get(), CSIDL_LOCAL_APPDATA, true)) | |
| 177 throw std::runtime_error("Unable to find app data directory"); | 196 throw std::runtime_error("Unable to find app data directory"); |
| 178 } | 197 appDataPath.assign(pathBuffer.get()); |
| 179 return std::wstring(appDataPath) + L"\\AdblockPlus"; | 198 } |
| 199 return appDataPath + L"\\AdblockPlus"; | |
| 180 } | 200 } |
| 181 | 201 |
| 182 std::auto_ptr<AdblockPlus::FilterEngine> CreateFilterEngine() | 202 std::auto_ptr<AdblockPlus::FilterEngine> CreateFilterEngine() |
| 183 { | 203 { |
| 184 // TODO: Pass appInfo in, which should be sent by the client | 204 // TODO: Pass appInfo in, which should be sent by the client |
| 185 AdblockPlus::JsEnginePtr jsEngine = AdblockPlus::JsEngine::New(); | 205 AdblockPlus::JsEnginePtr jsEngine = AdblockPlus::JsEngine::New(); |
| 186 std::string dataPath = ToString(GetAppDataPath()); | 206 std::string dataPath = ToUtf8String(GetAppDataPath()); |
| 187 dynamic_cast<AdblockPlus::DefaultFileSystem*>(jsEngine->GetFileSystem().get()) ->SetBasePath(dataPath); | 207 dynamic_cast<AdblockPlus::DefaultFileSystem*>(jsEngine->GetFileSystem().get()) ->SetBasePath(dataPath); |
| 188 std::auto_ptr<AdblockPlus::FilterEngine> filterEngine(new AdblockPlus::FilterE ngine(jsEngine)); | 208 std::auto_ptr<AdblockPlus::FilterEngine> filterEngine(new AdblockPlus::FilterE ngine(jsEngine)); |
| 189 int timeout = 5000; | |
| 190 while (!filterEngine->IsInitialized()) | |
|
Wladimir Palant
2013/05/16 11:52:16
TODO comment here please - we don't really want to
Felix Dahlke
2013/05/17 09:11:36
I presume that's not necessary anymore, now that y
Wladimir Palant
2013/05/17 10:35:02
Not pushed yet but - yes, once that review is done
Felix Dahlke
2013/05/23 12:31:20
Done.
| |
| 191 { | |
| 192 const int step = 10; | |
| 193 Sleep(step); | |
| 194 timeout -= step; | |
| 195 if (timeout <= 0) | |
| 196 throw std::runtime_error("Timeout while waiting for FilterEngine initializ ation"); | |
| 197 } | |
| 198 std::vector<AdblockPlus::SubscriptionPtr> subscriptions = filterEngine->FetchA vailableSubscriptions(); | 209 std::vector<AdblockPlus::SubscriptionPtr> subscriptions = filterEngine->FetchA vailableSubscriptions(); |
| 199 // TODO: Select a subscription based on the language, not just the first one. | 210 // TODO: Select a subscription based on the language, not just the first one. |
| 200 // This should ideally be done in libadblockplus. | 211 // This should ideally be done in libadblockplus. |
| 201 AdblockPlus::SubscriptionPtr subscription = subscriptions[0]; | 212 AdblockPlus::SubscriptionPtr subscription = subscriptions[0]; |
| 202 subscription->AddToList(); | 213 subscription->AddToList(); |
| 203 return filterEngine; | 214 return filterEngine; |
| 204 } | 215 } |
| 205 | 216 |
| 206 HANDLE CreatePipe(const std::wstring& pipeName) | 217 HANDLE CreatePipe(const std::wstring& pipeName) |
| 207 { | 218 { |
| 208 SECURITY_ATTRIBUTES sa; | 219 SECURITY_ATTRIBUTES sa; |
| 209 memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES)); | 220 memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES)); |
| 210 sa.nLength = sizeof(SECURITY_ATTRIBUTES); | 221 sa.nLength = sizeof(SECURITY_ATTRIBUTES); |
| 211 | 222 |
| 212 // Low mandatory label. See http://msdn.microsoft.com/en-us/library/bb625958.a spx | 223 // Low mandatory label. See http://msdn.microsoft.com/en-us/library/bb625958.a spx |
| 213 LPCWSTR LOW_INTEGRITY_SDDL_SACL_W = L"S:(ML;;NW;;;LW)"; | 224 LPCWSTR accessControlEntry = L"S:(ML;;NW;;;LW)"; |
| 214 PSECURITY_DESCRIPTOR securitydescriptor; | 225 PSECURITY_DESCRIPTOR securitydescriptor; |
| 215 ConvertStringSecurityDescriptorToSecurityDescriptor( | 226 ConvertStringSecurityDescriptorToSecurityDescriptor(accessControlEntry, SDDL_R EVISION_1, &securitydescriptor, 0); |
| 216 LOW_INTEGRITY_SDDL_SACL_W, SDDL_REVISION_1, &securitydescriptor, 0); | |
|
Wladimir Palant
2013/05/16 11:52:16
You are leaking this security descriptor, it needs
Felix Dahlke
2013/05/23 12:31:20
Done.
| |
| 217 | 227 |
| 218 sa.lpSecurityDescriptor = securitydescriptor; | 228 sa.lpSecurityDescriptor = securitydescriptor; |
| 219 sa.bInheritHandle = TRUE; | 229 sa.bInheritHandle = TRUE; |
| 220 | 230 |
| 221 return CreateNamedPipe(pipeName.c_str(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, | 231 HANDLE pipe = CreateNamedPipe(pipeName.c_str(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_ MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, |
| 222 PIPE_UNLIMITED_INSTANCES, bufferSize, bufferSize, 0, &s a); | 232 PIPE_UNLIMITED_INSTANCES, bufferSize, bufferSize , 0, &sa); |
| 233 LocalFree(securitydescriptor); | |
| 234 return pipe; | |
| 223 } | 235 } |
| 224 | 236 |
| 225 int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) | 237 int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) |
|
Wladimir Palant
2013/05/16 11:52:16
Second HINSTANCE parameter is hPrevInstance - you
Felix Dahlke
2013/05/23 12:31:20
Seems to be always 0 in Win32: http://blogs.msdn.c
Wladimir Palant
2013/05/23 14:25:01
Right, a bit of outdated knowledge on my end :-(
F
Felix Dahlke
2013/05/23 19:10:44
How about we just try to create the pipe initially
Wladimir Palant
2013/05/23 20:10:15
Yes, that's something I thought about as well. Thi
| |
| 226 { | 238 { |
| 227 filterEngine = CreateFilterEngine(); | 239 filterEngine = CreateFilterEngine(); |
| 228 filterEngineMutex = CreateMutex(0, false, 0); | |
| 229 | 240 |
| 230 for (;;) | 241 for (;;) |
| 231 { | 242 { |
| 232 HANDLE pipe = CreatePipe(pipeName); | 243 HANDLE pipe = CreatePipe(pipeName); |
| 233 if (pipe == INVALID_HANDLE_VALUE) | 244 if (pipe == INVALID_HANDLE_VALUE) |
| 234 { | 245 { |
| 235 LogLastError("CreateNamedPipe failed"); | 246 LogLastError("CreateNamedPipe failed"); |
| 236 return 1; | 247 return 1; |
| 237 } | 248 } |
| 238 | 249 |
| 239 if (!ConnectNamedPipe(pipe, 0)) | 250 if (!ConnectNamedPipe(pipe, 0)) |
| 240 { | 251 { |
| 241 LogLastError("Client failed to connect"); | 252 LogLastError("Client failed to connect"); |
| 242 CloseHandle(pipe); | 253 CloseHandle(pipe); |
| 243 continue; | 254 continue; |
| 244 } | 255 } |
| 245 | 256 |
| 246 // TODO: Count established connections, kill the engine when none are left | 257 // TODO: Count established connections, kill the engine when none are left |
| 247 | 258 |
| 248 AutoHandle thread(CreateThread(0, 0, ClientThread, static_cast<LPVOID>(pipe) , 0, 0)); | 259 AutoHandle thread(CreateThread(0, 0, ClientThread, static_cast<LPVOID>(pipe) , 0, 0)); |
| 249 if (!thread.get()) | 260 if (!thread.get()) |
| 250 { | 261 { |
| 251 LogLastError("CreateThread failed"); | 262 LogLastError("CreateThread failed"); |
| 252 return 1; | 263 return 1; |
| 253 } | 264 } |
| 254 } | 265 } |
| 255 | 266 |
| 256 return 0; | 267 return 0; |
| 257 } | 268 } |
|
Wladimir Palant
2013/05/16 11:52:16
IMHO, ReadMessage(), WriteMessage(), MarshalString
Felix Dahlke
2013/05/17 09:11:36
Same here, there's a TODO for that :)
| |
| LEFT | RIGHT |