Files
yttrium-virtio-gpu/NetKVM/ProtocolService/CProcessRunner.h
T
Yuri Benditovich 237430ba4a netkvm: add new files to protocol project
Introduced classes for running processes and pnp operations.

Signed-off-by: Yuri Benditovich <[email protected]>
2021-04-01 15:11:46 +03:00

226 lines
5.9 KiB
C++

#pragma once
class CPipe
{
public:
CPipe(bool ForRead = true)
{
SECURITY_ATTRIBUTES a = {};
a.nLength = sizeof(a);
a.bInheritHandle = true;
CreatePipe(&m_hRead, &m_hWrite, &a, 0);
SetHandleInformation(ForRead ? m_hRead : m_hWrite, HANDLE_FLAG_INHERIT, 0);
}
~CPipe()
{
if (m_hRead)
CloseHandle(m_hRead);
if (m_hWrite)
CloseHandle(m_hWrite);
}
HANDLE ReadHandle()
{
return m_hRead;
}
HANDLE WriteHandle()
{
return m_hWrite;
}
void CloseWrite()
{
if (m_hWrite)
{
CloseHandle(m_hWrite);
m_hWrite = NULL;
}
}
protected:
HANDLE m_hRead = NULL;
HANDLE m_hWrite = NULL;
};
class CProcessRunner
{
public:
// WaitTime = 0 starts the process as orphan, without waiting for termination
// WaitTime < INFINITE gives a possibility to do some action when the
// process is running and decide when to kill it
CProcessRunner(bool Redirect = true, ULONG WaitTime = INFINITE) :
m_Redirect(Redirect),
m_WaitTime(WaitTime)
{
Clean();
if (!m_WaitTime)
{
m_Redirect = false;
}
}
void Terminate()
{
if (pi.hProcess)
{
TerminateProcess(pi.hProcess, 0);
}
}
void RunProcess(CString& CommandLine)
{
Clean();
si.cb = sizeof(si);
if (m_Redirect)
{
si.hStdOutput = m_StdOut.WriteHandle();
si.hStdError = m_StdErr.WriteHandle();
si.hStdInput = m_StdIn.ReadHandle();
si.dwFlags |= STARTF_USESTDHANDLES;
}
if (CreateProcess(NULL, CommandLine.GetBuffer(), NULL, NULL, m_Redirect, CREATE_SUSPENDED, NULL, _T("."), &si, &pi))
{
if (m_Redirect)
{
m_StdOut.CloseWrite();
m_StdErr.CloseWrite();
}
ResumeThread(pi.hThread);
while (m_WaitTime && WaitForSingleObject(pi.hProcess, m_WaitTime) == WAIT_TIMEOUT)
{
if (ShouldTerminate())
{
Terminate();
}
}
Flush();
ULONG exitCode;
if (!GetExitCodeProcess(pi.hProcess, &exitCode))
{
exitCode = GetLastError();
}
PostProcess(exitCode);
}
if (pi.hProcess) CloseHandle(pi.hProcess);
if (pi.hThread) CloseHandle(pi.hThread);
Clean();
}
const CString& StdOutResult() const { return m_StdOutResult; }
const CString& StdErrResult() const { return m_StdErrResult; }
protected:
STARTUPINFO si;
PROCESS_INFORMATION pi;
CPipe m_StdOut;
CPipe m_StdErr;
CPipe m_StdIn;
CString m_StdOutResult;
CString m_StdErrResult;
void Clean()
{
memset(&si, 0, sizeof(si));
memset(&pi, 0, sizeof(pi));
}
ULONG m_WaitTime;
bool m_Redirect;
virtual bool ShouldTerminate()
{
return false;
}
virtual void PostProcess(ULONG ExitCode)
{
UNREFERENCED_PARAMETER(ExitCode);
}
CString Flush(HANDLE h)
{
CString s;
ULONG err;
BYTE buffer[128];
do
{
ULONG avail = 0;
ULONG got = 0;
bool b = PeekNamedPipe(h, buffer, sizeof(buffer), &got, &avail, NULL);
if (!b) {
err = GetLastError();
Sleep(10);
}
if (!b || !avail)
break;
got = 0;
avail = min(avail, sizeof(buffer));
if (!ReadFile(h, buffer, avail, &got, NULL))
{
err = GetLastError();
Sleep(10);
}
if (!got)
break;
for (ULONG i = 0; i < got; ++i)
{
s += buffer[i];
}
} while (true);
return s;
}
void Flush()
{
if (!m_Redirect)
return;
m_StdOutResult += Flush(m_StdOut.ReadHandle());
m_StdErrResult += Flush(m_StdErr.ReadHandle());
}
};
class CWmicQueryRunner : public CProcessRunner
{
public:
void Run()
{
CString cmd = TEXT("wmic /namespace:\\\\root\\wmi path NetKvm_Standby get /value");
RunProcess(cmd);
}
CAtlArray<CString>& Devices() { return m_Devices; }
protected:
CAtlArray<CString> m_Devices;
void PostProcess(ULONG ExitCode) override
{
Log("WMIC query done, result 0x%X", ExitCode);
if (!m_StdOutResult.IsEmpty())
{
CAtlArray<CString> tokens;
Log("STDOUT:%S", m_StdOutResult.GetString());
int position = 0;
while (position >= 0)
{
CString s = m_StdOutResult.Tokenize(TEXT("\r\n"), position);
if (s.IsEmpty())
continue;
tokens.Add(s);
}
for (UINT i = 0; i < tokens.GetCount(); ++i)
{
Log("Token[%d]:%S", i, tokens[i].GetString());
}
for (UINT i = 2; i < tokens.GetCount(); i += 3)
{
if (tokens[i].Find(TEXT("value=1")) >= 0)
{
CString pattern = TEXT("Name=");
CString s = tokens[i - 1];
INT n = s.Find(pattern);
if (n > 0)
{
s.Delete(0, n + pattern.GetLength());
if (!s.IsEmpty())
{
Log("Added \"%S\" for further action", s.GetString());
m_Devices.Add(s);
}
}
}
}
}
if (!m_StdErrResult.IsEmpty()) {
Log("STDERR:%S", m_StdErrResult.GetString());
}
}
};