summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/env.cpp228
-rw-r--r--src/env.h58
-rw-r--r--src/spawn.cpp92
3 files changed, 301 insertions, 77 deletions
diff --git a/src/env.cpp b/src/env.cpp
index 1aaaa8ef..78b5dc96 100644
--- a/src/env.cpp
+++ b/src/env.cpp
@@ -213,6 +213,234 @@ QString set(const QString& n, const QString& v)
}
+Service::Service(QString name)
+ : Service(std::move(name), StartType::None, Status::None)
+{
+}
+
+Service::Service(QString name, StartType st, Status s)
+ : m_name(std::move(name)), m_startType(st), m_status(s)
+{
+}
+
+const QString& Service::name() const
+{
+ return m_name;
+}
+
+bool Service::isValid() const
+{
+ return (m_startType != StartType::None) && (m_status != Status::None);
+}
+
+Service::StartType Service::startType() const
+{
+ return m_startType;
+}
+
+Service::Status Service::status() const
+{
+ return m_status;
+}
+
+QString Service::toString() const
+{
+ return QString("service '%1', start=%2, status=%3")
+ .arg(m_name)
+ .arg(env::toString(m_startType))
+ .arg(env::toString(m_status));
+}
+
+
+QString toString(Service::StartType st)
+{
+ using ST = Service::StartType;
+
+ switch (st)
+ {
+ case ST::None:
+ return "none";
+
+ case ST::Disabled:
+ return "disabled";
+
+ case ST::Enabled:
+ return "enabled";
+
+ default:
+ return QString("unknown %1").arg(static_cast<int>(st));
+ }
+}
+
+QString toString(Service::Status st)
+{
+ using S = Service::Status;
+
+ switch (st)
+ {
+ case S::None:
+ return "none";
+
+ case S::Stopped:
+ return "stopped";
+
+ case S::Running:
+ return "running";
+
+ default:
+ return QString("unknown %1").arg(static_cast<int>(st));
+ }
+}
+
+Service::StartType getServiceStartType(SC_HANDLE s, const QString& name)
+{
+ DWORD needed = 0;
+
+ if (!QueryServiceConfig(s, NULL, 0, &needed)) {
+ const auto e = GetLastError();
+
+ if (e != ERROR_INSUFFICIENT_BUFFER) {
+ log::error(
+ "QueryServiceConfig() for size for '{}' failed, {}",
+ name, GetLastError());
+
+ return Service::StartType::None;
+ }
+ }
+
+ const auto size = needed;
+ MallocPtr<QUERY_SERVICE_CONFIG> config(
+ static_cast<QUERY_SERVICE_CONFIG*>(std::malloc(size)));
+
+ if (!QueryServiceConfig(s, config.get(), size, &needed)) {
+ const auto e = GetLastError();
+
+ log::error(
+ "QueryServiceConfig() for '{}' failed", name, formatSystemMessage(e));
+
+ return Service::StartType::None;
+ }
+
+
+ switch (config->dwStartType)
+ {
+ case SERVICE_AUTO_START: // fall-through
+ case SERVICE_BOOT_START:
+ case SERVICE_DEMAND_START:
+ case SERVICE_SYSTEM_START:
+ {
+ return Service::StartType::Enabled;
+ }
+
+ case SERVICE_DISABLED:
+ {
+ return Service::StartType::Disabled;
+ }
+
+ default:
+ {
+ log::error(
+ "unknown service start type {} for '{}'",
+ config->dwStartType, name);
+
+ return Service::StartType::None;
+ }
+ }
+}
+
+Service::Status getServiceStatus(SC_HANDLE s, const QString& name)
+{
+ DWORD needed = 0;
+
+ if (!QueryServiceStatusEx(s, SC_STATUS_PROCESS_INFO, NULL, 0, &needed)) {
+ const auto e = GetLastError();
+
+ if (e != ERROR_INSUFFICIENT_BUFFER) {
+ log::error(
+ "QueryServiceStatusEx() for size for '{}' failed, {}",
+ name, GetLastError());
+
+ return Service::Status::None;
+ }
+ }
+
+ const auto size = needed;
+ MallocPtr<SERVICE_STATUS_PROCESS> status(
+ static_cast<SERVICE_STATUS_PROCESS*>(std::malloc(size)));
+
+ const auto r = QueryServiceStatusEx(
+ s, SC_STATUS_PROCESS_INFO, reinterpret_cast<BYTE*>(status.get()),
+ size, &needed);
+
+ if (!r) {
+ const auto e = GetLastError();
+
+ log::error(
+ "QueryServiceStatusEx() failed for '{}', {}",
+ name, formatSystemMessage(e));
+
+ return Service::Status::None;
+ }
+
+
+ switch (status->dwCurrentState)
+ {
+ case SERVICE_START_PENDING: // fall-through
+ case SERVICE_CONTINUE_PENDING:
+ case SERVICE_RUNNING:
+ {
+ return Service::Status::Running;
+ }
+
+ case SERVICE_STOPPED: // fall-through
+ case SERVICE_STOP_PENDING:
+ case SERVICE_PAUSE_PENDING:
+ case SERVICE_PAUSED:
+ {
+ return Service::Status::Stopped;
+ }
+
+ default:
+ {
+ log::error(
+ "unknown service status {} for '{}'",
+ status->dwCurrentState, name);
+
+ return Service::Status::None;
+ }
+ }
+}
+
+Service getService(const QString& name)
+{
+ // service manager
+ const LocalPtr<SC_HANDLE> scm(OpenSCManager(
+ NULL, NULL, SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG));
+
+ if (!scm) {
+ const auto e = GetLastError();
+ log::error("OpenSCManager() failed, {}", formatSystemMessage(e));
+ return Service(name);
+ }
+
+ // service
+ const LocalPtr<SC_HANDLE> s(OpenService(
+ scm.get(), name.toStdWString().c_str(),
+ SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG));
+
+ if (!s) {
+ const auto e = GetLastError();
+ log::error("OpenService() failed for '{}', {}", name, formatSystemMessage(e));
+ return Service(name);
+ }
+
+ const auto startType = getServiceStartType(s.get(), name);
+ const auto status = getServiceStatus(s.get(), name);
+
+ return {name, startType, status};
+}
+
+
// returns the filename of the given process or the current one
//
std::wstring processFilename(HANDLE process=INVALID_HANDLE_VALUE)
diff --git a/src/env.h b/src/env.h
index 7bdc9b85..1760c7fe 100644
--- a/src/env.h
+++ b/src/env.h
@@ -93,6 +93,24 @@ struct MallocFreer
template <class T>
using MallocPtr = std::unique_ptr<T, MallocFreer>;
+
+// used by LocalPtr, calls LocalFree() as the deleter
+//
+template <class T>
+struct LocalFreer
+{
+ using pointer = T;
+
+ void operator()(T p)
+ {
+ ::LocalFree(p);
+ }
+};
+
+template <class T>
+using LocalPtr = std::unique_ptr<T, LocalFreer<T>>;
+
+
// creates a console in the constructor and destroys it in the destructor,
// also redirects standard streams
//
@@ -172,6 +190,46 @@ QString addPath(const QString& s);
QString setPath(const QString& s);
+class Service
+{
+public:
+ enum class StartType
+ {
+ None = 0,
+ Disabled,
+ Enabled
+ };
+
+ enum class Status
+ {
+ None = 0,
+ Stopped,
+ Running
+ };
+
+
+ explicit Service(QString name);
+ Service(QString name, StartType st, Status s);
+
+ bool isValid() const;
+
+ const QString& name() const;
+ StartType startType() const;
+ Status status() const;
+
+ QString toString() const;
+
+private:
+ QString m_name;
+ StartType m_startType;
+ Status m_status;
+};
+
+
+Service getService(const QString& name);
+QString toString(Service::StartType st);
+QString toString(Service::Status st);
+
enum class CoreDumpTypes
{
Mini = 1,
diff --git a/src/spawn.cpp b/src/spawn.cpp
index 64766adf..551a5adb 100644
--- a/src/spawn.cpp
+++ b/src/spawn.cpp
@@ -428,7 +428,6 @@ void startBinaryAdmin(const SpawnParameters& sp)
restartAsAdmin();
}
-
bool checkBinary(QWidget* parent, const SpawnParameters& sp)
{
if (!sp.binary.exists()) {
@@ -557,9 +556,9 @@ bool checkSteam(
log::debug("checking steam");
if (!steamAppID.isEmpty()) {
- ::SetEnvironmentVariableW(L"SteamAPPId", steamAppID.toStdWString().c_str());
+ env::set("SteamAPPId", steamAppID);
} else {
- ::SetEnvironmentVariableW(L"SteamAPPId", settings.steam().appID().toStdWString().c_str());
+ env::set("SteamAPPId", settings.steam().appID());
}
if (!gameRequiresSteam(gameDirectory, settings)) {
@@ -584,7 +583,7 @@ bool checkSteam(
// double-check that Steam is started
ss = getSteamStatus();
if (!ss.running) {
- log::error("steam is still not running, continuing and hoping for the best");
+ log::error("steam is still not running, hoping for the best");
return true;
}
} else if (c == QDialogButtonBox::No) {
@@ -615,90 +614,29 @@ bool checkSteam(
return true;
}
-bool checkService()
+bool checkEventLogService()
{
- SC_HANDLE serviceManagerHandle = NULL;
- SC_HANDLE serviceHandle = NULL;
- LPSERVICE_STATUS_PROCESS serviceStatus = NULL;
- LPQUERY_SERVICE_CONFIG serviceConfig = NULL;
- bool serviceRunning = true;
-
- DWORD bytesNeeded;
-
- try {
- serviceManagerHandle = OpenSCManager(NULL, NULL, SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG);
- if (!serviceManagerHandle) {
- log::warn("failed to open service manager (query status) (error {})", GetLastError());
- throw 1;
- }
-
- serviceHandle = OpenService(serviceManagerHandle, L"EventLog", SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG);
- if (!serviceHandle) {
- log::warn("failed to open EventLog service (query status) (error {})", GetLastError());
- throw 2;
- }
-
- if (QueryServiceConfig(serviceHandle, NULL, 0, &bytesNeeded)
- || (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
- log::warn("failed to get size of service config (error {})", GetLastError());
- throw 3;
- }
-
- DWORD serviceConfigSize = bytesNeeded;
- serviceConfig = (LPQUERY_SERVICE_CONFIG)LocalAlloc(LMEM_FIXED, serviceConfigSize);
- if (!QueryServiceConfig(serviceHandle, serviceConfig, serviceConfigSize, &bytesNeeded)) {
- log::warn("failed to query service config (error {})", GetLastError());
- throw 4;
- }
-
- if (serviceConfig->dwStartType == SERVICE_DISABLED) {
- log::error("Windows Event Log service is disabled!");
- serviceRunning = false;
- }
-
- if (QueryServiceStatusEx(serviceHandle, SC_STATUS_PROCESS_INFO, NULL, 0, &bytesNeeded)
- || (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
- log::warn("failed to get size of service status (error {})", GetLastError());
- throw 5;
- }
-
- DWORD serviceStatusSize = bytesNeeded;
- serviceStatus = (LPSERVICE_STATUS_PROCESS)LocalAlloc(LMEM_FIXED, serviceStatusSize);
- if (!QueryServiceStatusEx(serviceHandle, SC_STATUS_PROCESS_INFO, (LPBYTE)serviceStatus, serviceStatusSize, &bytesNeeded)) {
- log::warn("failed to query service status (error {})", GetLastError());
- throw 6;
- }
+ const auto s = env::getService("EventLog");
- if (serviceStatus->dwCurrentState != SERVICE_RUNNING) {
- log::error("Windows Event Log service is not running");
- serviceRunning = false;
- }
- }
- catch (int) {
- serviceRunning = false;
+ if (!s.isValid()) {
+ log::error("cannot determine the status of the EventLog, continuing");
+ return true;
}
- if (serviceStatus) {
- LocalFree(serviceStatus);
- }
- if (serviceConfig) {
- LocalFree(serviceConfig);
- }
- if (serviceHandle) {
- CloseServiceHandle(serviceHandle);
- }
- if (serviceManagerHandle) {
- CloseServiceHandle(serviceManagerHandle);
+ if (s.status() == env::Service::Status::Running) {
+ log::debug("{}", s.toString());
+ return true;
+ } else {
+ log::error("{}", s.toString());
+ return false;
}
-
- return serviceRunning;
}
bool checkEnvironment(QWidget* parent, const SpawnParameters& sp)
{
// Check if the Windows Event Logging service is running. For some reason, this seems to be
// critical to the successful running of usvfs.
- if (!checkService()) {
+ if (!checkEventLogService()) {
if (QuestionBoxMemory::query(parent, QString("eventLogService"), sp.binary.fileName(),
QObject::tr("Windows Event Log Error"),
QObject::tr("The Windows Event Log service is disabled and/or not running. This prevents"