* Copyright (C) 2026 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef _WIN32
#include "process_handle.h"
#include "define_plus.h"
#include "../host_common.h"
#include <windows.h>
#include <tlhelp32.h>
#include <memory>
namespace Hdc {
struct ProcessHandle::ProcessHandleImpl {
PROCESS_INFORMATION* pi = nullptr;
~ProcessHandleImpl()
{
if (pi) {
if (pi->hThread) {
CloseHandle(pi->hThread);
}
if (pi->hProcess) {
CloseHandle(pi->hProcess);
}
delete pi;
}
}
bool IsAlive() const
{
if (!pi || !pi->hProcess) {
return false;
}
DWORD exitCode = 0;
return GetExitCodeProcess(pi->hProcess, &exitCode) && exitCode == STILL_ACTIVE;
}
int GetExitCode() const
{
if (!pi || !pi->hProcess) {
return -1;
}
DWORD exitCode = 0;
GetExitCodeProcess(pi->hProcess, &exitCode);
return static_cast<int>(exitCode);
}
bool IsValid() const
{
return pi && pi->hProcess;
}
};
std::string ProcessHandle::GetExecutablePathImpl()
{
std::string runPath = "";
std::unique_ptr<char[]> path(new (std::nothrow) char[BUF_SIZE_SMALL]);
if (path == nullptr) {
WRITE_LOG(LOG_WARN, "Failed to allocate memory for path");
return "";
}
size_t nPathSize = BUF_SIZE_SMALL;
int ret = uv_exepath(path.get(), &nPathSize);
if (ret < 0) {
constexpr int bufSize = 1024;
char buf[bufSize] = { 0 };
uv_err_name_r(ret, buf, bufSize);
WRITE_LOG(LOG_WARN, "uvexepath ret:%d error:%s", ret, buf);
return "";
}
char shortPath[MAX_PATH] = "";
std::string strPath = Base::UnicodeToUtf8(path.get(), true);
ret = GetShortPathName(strPath.c_str(), shortPath, MAX_PATH);
runPath = shortPath;
if (ret == 0) {
int err = GetLastError();
char buffer[1024] = { 0 };
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, err, 0, buffer, sizeof(buffer), nullptr);
WRITE_LOG(LOG_WARN, "GetShortPath errmsg:%s", buffer);
runPath = std::string(path.get()).substr(std::string(path.get()).find_last_of("/\\") + 1);
}
WRITE_LOG(LOG_DEBUG, "server shortpath:[%s] runPath:[%s]",
Hdc::MaskString(std::string(shortPath)).c_str(), Hdc::MaskString(runPath).c_str());
return runPath;
}
std::string ProcessHandle::GetParentProcessNameImpl()
{
std::string parentName;
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE) {
return parentName;
}
DWORD currentPid = GetCurrentProcessId();
DWORD parentPid = 0;
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hSnapshot, &pe32)) {
do {
if (pe32.th32ProcessID == currentPid) {
parentPid = pe32.th32ParentProcessID;
break;
}
} while (Process32Next(hSnapshot, &pe32));
}
if (parentPid == 0) {
CloseHandle(hSnapshot);
return parentName;
}
pe32.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hSnapshot, &pe32)) {
do {
if (pe32.th32ProcessID == parentPid) {
parentName = pe32.szExeFile;
break;
}
} while (Process32Next(hSnapshot, &pe32));
}
CloseHandle(hSnapshot);
return parentName;
}
bool ProcessHandle::BuildSubserverArgsImpl(char* buf, size_t bufSize, const char* listenString,
const char* serial, const char* port)
{
std::string logFileName = Base::GenerateSubserverLogFileName();
if (logFileName.empty()) {
return sprintf_s(buf, bufSize, "dummy -l 0 -s %s -m -N -i %s -o %s",
listenString, serial, port) >= 0;
}
return sprintf_s(buf, bufSize, "dummy -l %d -s %s -m -N -i %s -o %s -L %s",
Base::GetLogLevelByEnv(), listenString, serial, port, logFileName.c_str()) >= 0;
}
uint32_t ProcessHandle::GetCurrentPidImpl()
{
return GetCurrentProcessId();
}
ProcessHandle::ProcessHandle() : processImpl_(nullptr) {}
ProcessHandle::~ProcessHandle() = default;
ProcessHandle::ProcessHandle(ProcessHandle&& other) noexcept : processImpl_(std::move(other.processImpl_)) {}
ProcessHandle& ProcessHandle::operator=(ProcessHandle&& other) noexcept
{
if (this != &other) {
processImpl_ = std::move(other.processImpl_);
}
return *this;
}
std::unique_ptr<ProcessHandle> ProcessHandle::SpawnSubprocess(const std::string& path, const char* args)
{
auto handle = std::make_unique<ProcessHandle>();
handle->processImpl_ = std::make_unique<ProcessHandleImpl>();
handle->processImpl_->pi = new PROCESS_INFORMATION();
STARTUPINFO si = {};
si.cb = sizeof(STARTUPINFO);
#ifndef HDC_DEBUG
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
#endif
if (!CreateProcess(path.c_str(), const_cast<char*>(args), nullptr, nullptr, false,
CREATE_NEW_CONSOLE, nullptr, nullptr, &si, handle->processImpl_->pi)) {
WRITE_LOG(LOG_WARN, "CreateProcess failed with cmd:%s, args:%s, Error Code %d",
Hdc::MaskString(path).c_str(), args, GetLastError());
delete handle->processImpl_->pi;
handle->processImpl_->pi = nullptr;
return nullptr;
}
return handle;
}
bool ProcessHandle::IsAlive() const
{
return processImpl_ ? processImpl_->IsAlive() : false;
}
int ProcessHandle::GetExitCode() const
{
return processImpl_ ? processImpl_->GetExitCode() : -1;
}
bool ProcessHandle::IsValid() const
{
return processImpl_ && processImpl_->IsValid();
}
}
#endif