44 : m_iId(0), m_iExitCode(0), m_bHasExited(true), m_pProcessHandle(nullptr) {}
47 : m_iId(iId), m_sProcessName(sProcessName), m_iExitCode(0), m_bHasExited(false), m_pProcessHandle(pProcessHandle) {}
51 if (m_pProcessHandle !=
nullptr) {
52 CloseHandle((HANDLE)m_pProcessHandle);
61 std::wstring sCmd = L
"\"" + sWFileName + L
"\"";
63 sCmd += L
" " + sWArgs;
70 ZeroMemory(&si,
sizeof(si));
72 ZeroMemory(&pi,
sizeof(pi));
76 if (::CreateProcessW(NULL, (LPWSTR)sCmd.c_str(), NULL, NULL, FALSE, dwFlags, NULL, NULL, &si, &pi)) {
80 DWORD dwErr = ::GetLastError();
81 if (dwErr == ERROR_FILE_NOT_FOUND || dwErr == ERROR_PATH_NOT_FOUND) {
84 if (dwErr == ERROR_ACCESS_DENIED) {
90 static std::vector<std::string> ParsePosixArgs(
const ProcessStartInfo& info) {
91 std::vector<std::string> argStrings;
92 argStrings.push_back(info.FileName.GetRawString());
94 std::string sArgs = info.Arguments.GetRawString();
95 std::string sCurrentArg;
96 bool bInQuotes =
false;
98 for (
size_t i = 0; i < sArgs.length(); ++i) {
101 bInQuotes = !bInQuotes;
102 }
else if (c ==
' ' && !bInQuotes) {
103 if (!sCurrentArg.empty()) {
104 argStrings.push_back(sCurrentArg);
111 if (!sCurrentArg.empty()) argStrings.push_back(sCurrentArg);
116 auto argStrings = ParsePosixArgs(info);
117 std::vector<char*> argv;
118 for (
auto& s : argStrings) argv.push_back((
char*)s.c_str());
119 argv.push_back(NULL);
121 int err = posix_spawn(&pid, info.FileName.GetRawString(), NULL, NULL, argv.data(), environ);
122 if (err == 0)
return true;
123 if (err == ENOENT)
throw IO::FileNotFoundException(
"The system cannot find the file specified.");
131 PROCESS_INFORMATION pi;
133 iId =
static_cast<int>(pi.dwProcessId);
134 pHandle = (
void*)pi.hProcess;
135 ::CloseHandle(pi.hThread);
143 DWORD dwTimeout = (iMilliseconds == -1) ? INFINITE : (DWORD)iMilliseconds;
144 return (WaitForSingleObject((HANDLE)pHandle, dwTimeout) == WAIT_OBJECT_0);
148 if (!::TerminateProcess((HANDLE)pHandle, 1)) {
149 DWORD dwErr = ::GetLastError();
157 if (GetExitCodeProcess((HANDLE)pHandle, &dwCode) && dwCode != STILL_ACTIVE) {
158 iExitCode =
static_cast<int>(dwCode);
164 static bool StartProcessPlatform(
const ProcessStartInfo& info,
int& iId,
void*& pHandle,
bool& bExited) {
166 if (SpawnPosixProcess(info, pid)) {
167 iId =
static_cast<int>(pid);
168 pHandle = (
void*)(intptr_t)pid;
177 pid_t pid = (pid_t)(intptr_t)pHandle;
178 if (iMilliseconds == -1) {
179 if (waitpid(pid, &iStatus, 0) == pid) {
180 iExitCode = WIFEXITED(iStatus) ? WEXITSTATUS(iStatus) : (WIFSIGNALED(iStatus) ? -WTERMSIG(iStatus) : 0);
186 while (iElapsed < iMilliseconds) {
187 pid_t res = waitpid(pid, &iStatus, WNOHANG);
189 iExitCode = WIFEXITED(iStatus) ? WEXITSTATUS(iStatus) : (WIFSIGNALED(iStatus) ? -WTERMSIG(iStatus) : 0);
192 if (res != 0 && errno == ECHILD)
return true;
193 usleep(10000); iElapsed += 10;
199 pid_t pid = (pid_t)(intptr_t)pHandle;
200 if (kill(pid, SIGKILL) != 0) {
205 if (waitpid(pid, &iStatus, 0) == pid) {
206 iExitCode = WIFEXITED(iStatus) ? WEXITSTATUS(iStatus) : (WIFSIGNALED(iStatus) ? -WTERMSIG(iStatus) : 0);
212 pid_t res = waitpid((pid_t)(intptr_t)pHandle, &iStatus, WNOHANG);
214 iExitCode = WIFEXITED(iStatus) ? WEXITSTATUS(iStatus) : (WIFSIGNALED(iStatus) ? -WTERMSIG(iStatus) : 0);
217 return (res == -1 && errno == ECHILD);
222 if (m_objStartInfo.FileName.GetLength() == 0)
return false;
236 pProcess->SetStartInfo(objStartInfo);
238 if (pProcess->Start())
return pProcess;
250 if (m_bHasExited || m_pProcessHandle ==
nullptr)
return true;
272 if (m_bHasExited || m_pProcessHandle ==
nullptr)
return;
286 return static_cast<int>(getpid());
290 void Process::Refresh()
const {
291 if (m_bHasExited || m_pProcessHandle ==
nullptr)
return;
300 hOutProc = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION | SYNCHRONIZE, FALSE,
static_cast<DWORD
>(iProcessId));
301 if (hOutProc == NULL)
return false;
304 WCHAR szPath[MAX_PATH] = { 0 }; DWORD dwLen = MAX_PATH;
305 if (::QueryFullProcessImageNameW(hOutProc, 0, szPath, &dwLen)) {
306 std::wstring ws(szPath);
307 size_t pos = ws.find_last_of(L
"\\/");
308 std::wstring wsName = (pos != std::wstring::npos) ? ws.substr(pos + 1) : ws;
315 static bool QueryLinuxProcessNameById(
int iProcessId,
String& sOutName) {
317 std::string sPath =
"/proc/" + std::to_string(iProcessId) +
"/comm";
318 std::ifstream commFile(sPath);
322 if (commFile.is_open() && std::getline(commFile, sComm)) {
323 sOutName =
String(sComm.c_str());
333 HANDLE hSnapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
334 if (hSnapshot == INVALID_HANDLE_VALUE)
return;
337 PROCESSENTRY32W pe32; pe32.dwSize =
sizeof(PROCESSENTRY32W);
338 if (::Process32FirstW(hSnapshot, &pe32)) {
340 if (pe32.th32ProcessID == 0)
continue;
342 }
while (::Process32NextW(hSnapshot, &pe32));
346 ::CloseHandle(hSnapshot);
350 DIR* dir = ::opendir(
"/proc");
352 struct dirent* entry =
nullptr;
353 while ((entry = ::readdir(dir)) !=
nullptr) {
354 if (entry->d_type == DT_DIR) {
355 std::string dname = entry->d_name;
356 if (std::all_of(dname.begin(), dname.end(), ::isdigit)) {
357 std::ifstream commFile(
"/proc/" + dname +
"/comm");
359 if (commFile.is_open() && std::getline(commFile, sComm)) {
374 EnumerateLinuxProcesses(lstProcs);
377 for (
int i = 0; i < lstProcs.
GetCount(); ++i) arrProcs[i] = lstProcs[i];
383 for (
int i = 0; i < arrProcs.GetLength(); ++i) {
384 if (arrProcs[i]->GetId() == iProcessId) {
385 sOutName = arrProcs[i]->GetProcessName();
393 if (iProcessId <= 0)
throw ArgumentException(
"Process ID must be greater than zero.");
414 if (sCandidate.
Equals(sTarget))
return true;
424 for (
int i = 0; i < arrAll.
GetLength(); ++i) {
426 lstMatches.
Add(arrAll[i]);
430 for (
int i = 0; i < lstMatches.
GetCount(); ++i) arrResult[i] = lstMatches[i];
Defines the exception thrown when an invalid argument is provided to a method.
The exception that is thrown when an attempt to access a file that does not exist on disk fails.
Defines the exception thrown when a method call is invalid for the object's current state.
Represents a strongly typed list of objects that can be accessed by index mirroring ....
Provides access to local and remote processes and enables you to start and stop local system processe...
Utility routines for high-performance UTF-8, UTF-16, and wide-character string conversions.
The exception that is thrown when the operating system denies access because of an I/O error or a spe...
ArgumentException(const String &sMessage)
Initializes a new instance of the ArgumentException class with a specified error message.
Provides methods for creating, manipulating, searching, and sorting arrays, thereby serving as the ba...
int GetLength() const
Gets the total number of elements in all dimensions of the Array.
Represents a strongly typed list of objects accessible by index.
int GetCount() const
Gets the number of elements contained in the List.
void Add(const T &item)
Adds an object to the end of the List.
static int GetCurrentProcessId()
Gets the process identifier of the calling process.
bool Start()
Starts (or reuses) the process resource that is specified by the StartInfo property.
static Array< SmartPointer< Process > > GetProcesses()
Creates an array of new Process components and associates them with all active system processes.
String GetProcessName() const
Gets the name of the process.
static SmartPointer< Process > GetProcessById(int iProcessId)
Returns a Process component given the identifier of a process on the local computer.
void WaitForExit()
Instructs the Process component to wait indefinitely for the associated process to exit.
static Array< SmartPointer< Process > > GetProcessesByName(const String &sProcessName)
Creates an array of new Process components and associates them with all processes sharing the specifi...
void Kill()
Immediately stops the associated process.
bool GetHasExited() const
Gets a value indicating whether the associated process has been terminated.
static SmartPointer< Process > GetCurrentProcess()
Gets a new Process component and associates it with the currently active process.
Specifies a set of values that are used when you start a process.
The exception that is thrown when an attempt to access a file that does not exist on disk fails.
static std::wstring Utf8ToWChar(const char *pUtf8Str)
static std::string WCharToUtf8(const wchar_t *pWStr)
InvalidOperationException(const String &sMessage)
Initializes a new instance of the InvalidOperationException class with a specified error message.
A unified smart pointer that supports both unique and shared ownership semantics.
static SmartPointer< T > NewShared()
Creates a Shared SmartPointer, default constructing T.
friend class SmartPointer
Represents text as a sequence of UTF-8 code units with culture-invariant operations.
String Substring(int iStartIndex) const
bool EndsWith(char ch, bool bIgnoreCase) const
String()
Initializes a new instance of the String class to an empty string.
static bool Equals(const String &sStr1, const String &sStr2)
const char * GetRawString() const
UnauthorizedAccessException()
Initializes a new instance of the UnauthorizedAccessException class with a default message.
static void KillProcessPlatform(void *pHandle)
static bool WaitForExitPlatform(void *pHandle, int iMilliseconds)
static bool CreateWin32Process(const ProcessStartInfo &info, PROCESS_INFORMATION &pi)
static std::wstring BuildCommandLine(const ProcessStartInfo &info)
static bool MatchProcessName(const String &sCandidate, const String &sTarget)
static bool RefreshProcessPlatform(void *pHandle, int &iExitCode)
static bool FindProcessInSnapshot(int iProcessId, String &sOutName)
static void EnumerateWin32Processes(Collections::Generic::List< SmartPointer< Process > > &lstProcs)
static bool QueryProcessNameById(int iProcessId, String &sOutName, HANDLE &hOutProc)
static bool StartProcessPlatform(const ProcessStartInfo &info, int &iId, void *&pHandle, bool &bExited)