/**
* @brief Windows-specific utility functions
* @author Supakorn "Jamie" Rassameemasmuang (jamievlin [at] outlook.com)
*/
#if defined(_WIN32)
#include "win32helpers.h"
#include "errormsg.h"
#include <shellapi.h>
using camp::reportError;
namespace camp::w32
{
bool checkShellExecuteResult(INT_PTR const shellExecResult, bool const reportWarning)
{
switch (shellExecResult)
{
// see
https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutea
// ERROR_FILE_NOT_FOUND and ERROR_PATH_NOT_FOUND shares the same error code as
// SE_ERR_FNF and SE_ERR_PNF, respectively
case 0:
case ERROR_BAD_FORMAT:
case SE_ERR_ACCESSDENIED:
case SE_ERR_ASSOCINCOMPLETE:
case SE_ERR_DDEBUSY:
case SE_ERR_DDEFAIL:
case SE_ERR_DDETIMEOUT:
case SE_ERR_DLLNOTFOUND:
case SE_ERR_FNF:
case SE_ERR_NOASSOC:
case SE_ERR_OOM:
case SE_ERR_PNF:
case SE_ERR_SHARE:
{
if (reportWarning)
{
DWORD const errorCode= GetLastError();
ostringstream msg;
msg << "Error code: 0x" << std::hex << errorCode << std::dec << "; message: " << getErrorMessage(errorCode);
camp::reportWarning(msg.str());
}
}
return false;
default:
return true;
}
}
void reportAndFailWithLastError(string const& message)
{
DWORD errorCode= GetLastError();
ostringstream msg;
msg << message << "; error code = 0x" << std::hex << errorCode << std::dec
<< "; Windows Message: " << getErrorMessage(errorCode);
reportError(msg);
}
void checkResult(BOOL result, string const& message)
{
if (!result)
{
reportAndFailWithLastError(message);
}
}
void checkLStatus(LSTATUS result, string const& message)
{
checkResult(result == ERROR_SUCCESS, message);
}
bool isProcessRunning(DWORD const& pid)
{
if (pid == 0)
{
return true; // system idle is always running
}
HandleRaiiWrapper const processHandle(OpenProcess(PROCESS_QUERY_INFORMATION, false, pid));
if (processHandle.getHandle() == nullptr)
{
// handle not in system, returns false
return false;
}
DWORD exitCode=999;
if (GetExitCodeProcess(processHandle.getHandle(), &exitCode))
{
if (exitCode == STILL_ACTIVE)
{
return true;
}
else
{
return false;
}
}
return false;
}
#pragma region RegKeyWrapper
RegKeyWrapper::RegKeyWrapper(HKEY const& regKey)
: key(regKey)
{
}
RegKeyWrapper::RegKeyWrapper() : key(nullptr)
{
}
RegKeyWrapper::~RegKeyWrapper()
{
closeExistingKey();
}
RegKeyWrapper::RegKeyWrapper(RegKeyWrapper&& other) noexcept
: key(std::exchange(other.key, nullptr))
{
}
RegKeyWrapper& RegKeyWrapper::operator=(RegKeyWrapper&& other) noexcept
{
if (this != &other)
{
closeExistingKey();
this->key = std::exchange(other.key, nullptr);
}
return *this;
}
HKEY RegKeyWrapper::getKey() const
{
return key;
}
void RegKeyWrapper::closeExistingKey()
{
if (this->key != nullptr)
{
RegCloseKey(this->key);
this->key = nullptr;
}
}
PHKEY RegKeyWrapper::put()
{
closeExistingKey();
return &(this->key);
}
void RegKeyWrapper::release()
{
this->key = nullptr;
}
#pragma endregion
#pragma region HandleRaiiWrapper
HandleRaiiWrapper::HandleRaiiWrapper(HANDLE const& handle)
: hd(handle)
{
}
HandleRaiiWrapper::~HandleRaiiWrapper()
{
if (hd)
{
if (!CloseHandle(hd))
{
cerr << "Warning: Cannot close handle" << endl;
}
}
}
HandleRaiiWrapper::HandleRaiiWrapper(HandleRaiiWrapper&& other) noexcept
: hd(std::exchange(other.hd, nullptr))
{
}
HANDLE HandleRaiiWrapper::getHandle() const
{
return hd;
}
LPHANDLE HandleRaiiWrapper::put()
{
if (hd)
{
w32::checkResult(CloseHandle(hd));
hd = nullptr;
}
return &hd;
}
#pragma endregion
string buildWindowsCmd(const mem::vector<string>& command)
{
ostringstream out;
for (auto it= command.begin(); it != command.end(); ++it)
{
out << '"' << *it << '"';
if (std::next(it) != command.end())
{
out << ' ';
}
}
return out.str();
}
string getErrorMessage(DWORD const& errorCode)
{
LPSTR messageOut= nullptr;
auto ret = FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr,
errorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPSTR>(&messageOut),
0,
nullptr
);
if (ret == 0)
{
return "Cannot determine error message";
}
string retString(messageOut);
LocalFree(messageOut);
return retString;
}
}// namespace camp::w32
#endif