1
2
3 #include "subprocess_windows.h"
4
5 #include <windows.h>
6 #include <winbase.h>
7 #include <shlwapi.h>
8 #include <iostream>
9 #include <sstream>
10
WinImpl()11 WinImpl::WinImpl():
12 m_pid(0),
13 m_running(false),
14 m_subprocessHandle(INVALID_HANDLE_VALUE),
15 m_waitingThreadHandle(INVALID_HANDLE_VALUE)
16 {
17 InitializeCriticalSection(&m_criticalSection);
18 }
19
~WinImpl()20 WinImpl::~WinImpl()
21 {
22 kill();
23 WaitForSingleObject(m_waitingThreadHandle, INFINITE);
24 CloseHandle(m_subprocessHandle);
25 DeleteCriticalSection(&m_criticalSection);
26 }
27
waitForPID(void * _self)28 DWORD WINAPI WinImpl::waitForPID(void* _self)
29 {
30 WinImpl* self = static_cast<WinImpl*>(_self);
31 WaitForSingleObject(self->m_subprocessHandle, INFINITE);
32
33 EnterCriticalSection(&self->m_criticalSection);
34 self->m_running = false;
35 LeaveCriticalSection(&self->m_criticalSection);
36
37 return 0;
38 }
39
toWideChar(const std::string & value,size_t min_size=0)40 std::unique_ptr<wchar_t[]> toWideChar(const std::string& value, size_t min_size = 0)
41 {
42 size_t size = MultiByteToWideChar(CP_UTF8, 0,
43 value.c_str(), -1, nullptr, 0);
44 auto wdata = std::unique_ptr<wchar_t[]>(new wchar_t[size>min_size?size:min_size]);
45 auto ret = MultiByteToWideChar(CP_UTF8, 0,
46 value.c_str(), -1, wdata.get(), size);
47 if (0 == ret) {
48 std::ostringstream oss;
49 oss << "Cannot convert to wchar : " << GetLastError();
50 throw std::runtime_error(oss.str());
51 }
52 if (size < min_size) {
53 memset(wdata.get() + size, 0, min_size-size);
54 }
55 return wdata;
56 }
57
58
run(commandLine_t & commandLine)59 void WinImpl::run(commandLine_t& commandLine)
60 {
61 STARTUPINFOW startInfo = {0};
62 PROCESS_INFORMATION procInfo;
63 startInfo.cb = sizeof(startInfo);
64 std::wostringstream oss;
65 for(auto& item: commandLine) {
66 auto witem = toWideChar(item, MAX_PATH);
67 PathQuoteSpacesW(witem.get());
68 oss << witem.get() << " ";
69 }
70 auto wCommandLine = oss.str();
71 if (CreateProcessW(
72 NULL,
73 const_cast<wchar_t*>(wCommandLine.c_str()),
74 NULL,
75 NULL,
76 false,
77 CREATE_NO_WINDOW,
78 NULL,
79 NULL,
80 &startInfo,
81 &procInfo))
82 {
83 m_pid = procInfo.dwProcessId;
84 m_subprocessHandle = procInfo.hProcess;
85 CloseHandle(procInfo.hThread);
86 m_running = true;
87 m_waitingThreadHandle = CreateThread(NULL, 0, &waitForPID, this, 0, NULL);
88 }
89 }
90
kill()91 bool WinImpl::kill()
92 {
93 return TerminateProcess(m_subprocessHandle, 0);
94 }
95
isRunning()96 bool WinImpl::isRunning()
97 {
98 EnterCriticalSection(&m_criticalSection);
99 bool ret = m_running;
100 LeaveCriticalSection(&m_criticalSection);
101 return ret;
102 }
103