检查 Steam 是否 运行 并且用户已登录

Check if Steam is running and user is logged in

简而言之,我想检查 Steam 是否 运行 以及用户是否已登录。我只能找到关于网络的文档 -api 这将是错误的开始点我想想。

我什至不需要代码示例,我只需要提示正确的方向和从哪里开始。我听说 Steam 本身有一个 OpenID 实现,但我不知道它是否是正确的起点。

感谢任何帮助!

我假设您正在将此用于游戏,如果我是正确的,您需要来自 Valve 的 Steamworks SDK。获得官方 SDK 的唯一方法是在 Steam 上通过绿灯流程。但是,您可以使用 https://steamworks.github.io/ 。希望对你有帮助。

我知道这是一个比较老的问题,但我自己在寻找答案时偶然发现了它。我找到了一种方法,虽然它是在 C++ 中,但是它可以完美地转换为 C#。

伪代码

string SteamExePath = RegistryKey("HKEY_CURRENT_USER\SOFTWARE\Valve\Steam\SteamExe");
while RegistryKey("HKEY_CURRENT_USER\SOFTWARE\Valve\Steam\ActiveProcess\ActiveUser") == 0
{
    RegisterForRegistryChange("HKEY_CURRENT_USER\SOFTWARE\Valve\Steam\ActiveProcess");

    StartProcess(SteamExePath);

    WaitForRegistryChange();
}

C++代码

Util.h

#pragma once

#include <memory>
#include <string>

#include "Shared.h"

#define EXCEPTION(message, ...) throw std::runtime_error(Shared::stringFormat(Shared::stringFormat("%s: %s", __FUNCTION__, message), __VA_ARGS__));
#define EXCEPTION_LAST_ERROR(message, ...) throw std::runtime_error(Shared::stringFormat(Shared::stringFormat("%s: %s\nSystem error code: %u", __FUNCTION__, message, GetLastError()), __VA_ARGS__));
#define EXCEPTION_LAST_ERROR2(message, lastError, ...) throw std::runtime_error(Shared::stringFormat(Shared::stringFormat("%s: %s\nSystem error code: %u", __FUNCTION__, message, lastError), __VA_ARGS__));

namespace Shared
{
    template<typename ... Args>
    std::string stringFormat(const std::string &format, Args ...args)
    {
        size_t size = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
        std::unique_ptr<char[]> buf(new char[size]);
        std::snprintf(buf.get(), size, format.c_str(), args...);

        return std::string(buf.get(), buf.get() + size - 1);
    }

    template<typename ... Args>
    std::wstring stringFormat(const std::wstring &format, Args ...args)
    {
        size_t size = std::swprintf(nullptr, 0, format.c_str(), args...) + 1;
        std::unique_ptr<wchar_t[]> buf(new wchar_t[size]);
        std::swprintf(buf.get(), size, format.c_str(), args...);

        return std::wstring(buf.get(), buf.get() + size - 1);
    }

    void getExecutionPath(std::wstring &path);
}

Process.h

#pragma once

#include <Windows.h>
#include <string>

namespace Shared
{
    class Process
    {
        public:
            Process(
                const std::wstring &path,
                const std::wstring &arguments,
                LPSECURITY_ATTRIBUTES processAttributes,
                LPSECURITY_ATTRIBUTES threadAttributes,
                bool inheritHandles, 
                DWORD creationFlags,
                LPVOID environment,
                const std::wstring &currentDirectory,
                const STARTUPINFOEXW &startupInfo);
            Process(
                const std::wstring &&path,
                const std::wstring &&arguments,
                LPSECURITY_ATTRIBUTES processAttributes,
                LPSECURITY_ATTRIBUTES threadAttributes,
                bool inheritHandles, 
                DWORD creationFlags,
                LPVOID environment,
                const std::wstring &&currentDirectory,
                const STARTUPINFOEXW &startupInfo);
            Process(
                const std::wstring &&path,
                const std::wstring &arguments,
                LPSECURITY_ATTRIBUTES processAttributes,
                LPSECURITY_ATTRIBUTES threadAttributes,
                bool inheritHandles, 
                DWORD creationFlags,
                LPVOID environment,
                const std::wstring &currentDirectory,
                const STARTUPINFOEXW &startupInfo);
            Process(
                const std::wstring &path,
                const std::wstring &&arguments,
                LPSECURITY_ATTRIBUTES processAttributes,
                LPSECURITY_ATTRIBUTES threadAttributes,
                bool inheritHandles, 
                DWORD creationFlags,
                LPVOID environment,
                const std::wstring &currentDirectory,
                const STARTUPINFOEXW &startupInfo);
            Process(
                const std::wstring &path,
                const std::wstring &arguments,
                LPSECURITY_ATTRIBUTES processAttributes,
                LPSECURITY_ATTRIBUTES threadAttributes,
                bool inheritHandles, 
                DWORD creationFlags,
                LPVOID environment,
                const std::wstring &&currentDirectory,
                const STARTUPINFOEXW &startupInfo);
            Process(
                const std::wstring &&path,
                const std::wstring &&arguments,
                LPSECURITY_ATTRIBUTES processAttributes,
                LPSECURITY_ATTRIBUTES threadAttributes,
                bool inheritHandles, 
                DWORD creationFlags,
                LPVOID environment,
                const std::wstring &currentDirectory,
                const STARTUPINFOEXW &startupInfo);
            Process(
                const std::wstring &path,
                const std::wstring &&arguments,
                LPSECURITY_ATTRIBUTES processAttributes,
                LPSECURITY_ATTRIBUTES threadAttributes,
                bool inheritHandles, 
                DWORD creationFlags,
                LPVOID environment,
                const std::wstring &&currentDirectory,
                const STARTUPINFOEXW &startupInfo);
            Process(
                const std::wstring &&path,
                const std::wstring &arguments,
                LPSECURITY_ATTRIBUTES processAttributes,
                LPSECURITY_ATTRIBUTES threadAttributes,
                bool inheritHandles, 
                DWORD creationFlags,
                LPVOID environment,
                const std::wstring &&currentDirectory,
                const STARTUPINFOEXW &startupInfo);
            Process(Process &&other);
            ~Process();

            void create();
            void terminate(UINT exitCode);
            bool awaitTermination(DWORD milliseconds, DWORD &exitCode);
            void resume();

            inline bool awaitTermination(DWORD milliseconds)
            {
                DWORD exitCode;

                return awaitTermination(milliseconds, exitCode);
            }

            inline bool isCreated() const
            {
                return this->created;
            }

            inline const std::wstring &getPath() const
            {
                return this->path;
            }

            inline const std::wstring &getArguments() const
            {
                return this->arguments;
            }

            inline const LPSECURITY_ATTRIBUTES getProcessAttributes() const
            {
                return this->processAttributes;
            }

            inline const LPSECURITY_ATTRIBUTES getThreadAttributes() const
            {
                return this->threadAttributes;
            }

            inline bool getInheritHandles() const
            {
                return this->inheritHandles;
            }

            inline DWORD getCreationFlags() const
            {
                return this->creationFlags;
            }

            inline const LPVOID getEnvironment() const
            {
                return this->environment;
            }

            inline const std::wstring &getCurrentDirectory() const
            {
                return this->currentDirectory;
            }

            inline const STARTUPINFOEXW &getStartupInfo() const
            {
                return this->startupInfo;
            }

            inline const PROCESS_INFORMATION &getProcessInformation() const
            {
                return this->processInformation;
            }

            inline DWORD getProcessId() const
            {
                return this->processInformation.dwProcessId;
            }

            inline DWORD getThreadId() const
            {
                return this->processInformation.dwThreadId;
            }

            inline HANDLE getProcessHandle() const
            {
                return this->processInformation.hProcess;
            }

            inline HANDLE getThreadHandle() const
            {
                return this->processInformation.hThread;
            }

        private:
            Process(const Process &other) = delete;
            Process &operator=(const Process &other) = delete;
            Process &operator=(const Process &&other) = delete;

            void init(LPSECURITY_ATTRIBUTES processAttributes, LPSECURITY_ATTRIBUTES threadAttributes);
            void cleanup();

            bool created;
            std::wstring path;
            std::wstring arguments;
            LPSECURITY_ATTRIBUTES processAttributes;
            LPSECURITY_ATTRIBUTES threadAttributes;
            bool inheritHandles;
            DWORD creationFlags;
            LPVOID environment;
            std::wstring currentDirectory;
            STARTUPINFOEXW startupInfo;
            PROCESS_INFORMATION processInformation;
    };
}

Process.cpp

#include "stdafx.h"
#include "Process.h"

#include "Util.h"

namespace Shared
{
    Process::Process(
        const std::wstring &path,
        const std::wstring &arguments,
        LPSECURITY_ATTRIBUTES processAttributes,
        LPSECURITY_ATTRIBUTES threadAttributes,
        bool inheritHandles,
        DWORD creationFlags,
        LPVOID environment,
        const std::wstring &currentDirectory,
        const STARTUPINFOEXW &startupInfo) :
        created(false),
        path(path),
        arguments(arguments),
        processAttributes(NULL),
        threadAttributes(NULL),
        inheritHandles(inheritHandles),
        creationFlags(creationFlags),
        environment(environment),
        currentDirectory(currentDirectory),
        startupInfo(startupInfo),
        processInformation()
    {
        init(processAttributes, threadAttributes);
    }

    Process::Process(
        const std::wstring &&path,
        const std::wstring &&arguments,
        LPSECURITY_ATTRIBUTES processAttributes,
        LPSECURITY_ATTRIBUTES threadAttributes,
        bool inheritHandles,
        DWORD creationFlags,
        LPVOID environment,
        const std::wstring &&currentDirectory,
        const STARTUPINFOEXW &startupInfo) :
        created(false),
        path(std::forward<const std::wstring>(path)),
        arguments(std::forward<const std::wstring>(arguments)),
        processAttributes(NULL),
        threadAttributes(NULL),
        inheritHandles(inheritHandles),
        creationFlags(creationFlags),
        environment(environment),
        currentDirectory(std::forward<const std::wstring>(currentDirectory)),
        startupInfo(startupInfo),
        processInformation()
    {
        init(processAttributes, threadAttributes);
    }

    Process::Process(
        const std::wstring &&path,
        const std::wstring &arguments,
        LPSECURITY_ATTRIBUTES processAttributes,
        LPSECURITY_ATTRIBUTES threadAttributes,
        bool inheritHandles,
        DWORD creationFlags,
        LPVOID environment,
        const std::wstring &currentDirectory,
        const STARTUPINFOEXW &startupInfo) :
        created(false),
        path(std::forward<const std::wstring>(path)),
        arguments(arguments),
        processAttributes(NULL),
        threadAttributes(NULL),
        inheritHandles(inheritHandles),
        creationFlags(creationFlags),
        environment(environment),
        currentDirectory(currentDirectory),
        startupInfo(startupInfo),
        processInformation()
    {
        init(processAttributes, threadAttributes);
    }

    Process::Process(
        const std::wstring &path,
        const std::wstring &&arguments,
        LPSECURITY_ATTRIBUTES processAttributes,
        LPSECURITY_ATTRIBUTES threadAttributes,
        bool inheritHandles,
        DWORD creationFlags,
        LPVOID environment,
        const std::wstring &currentDirectory,
        const STARTUPINFOEXW &startupInfo) :
        created(false),
        path(path),
        arguments(std::forward<const std::wstring>(arguments)),
        processAttributes(NULL),
        threadAttributes(NULL),
        inheritHandles(inheritHandles),
        creationFlags(creationFlags),
        environment(environment),
        currentDirectory(currentDirectory),
        startupInfo(startupInfo),
        processInformation()
    {
        init(processAttributes, threadAttributes);
    }

    Process::Process(
        const std::wstring &path,
        const std::wstring &arguments,
        LPSECURITY_ATTRIBUTES processAttributes,
        LPSECURITY_ATTRIBUTES threadAttributes,
        bool inheritHandles,
        DWORD creationFlags,
        LPVOID environment,
        const std::wstring &&currentDirectory,
        const STARTUPINFOEXW &startupInfo) :
        created(false),
        path(path),
        arguments(arguments),
        processAttributes(NULL),
        threadAttributes(NULL),
        inheritHandles(inheritHandles),
        creationFlags(creationFlags),
        environment(environment),
        currentDirectory(std::forward<const std::wstring>(currentDirectory)),
        startupInfo(startupInfo),
        processInformation()
    {
        init(processAttributes, threadAttributes);
    }

    Process::Process(
        const std::wstring &&path,
        const std::wstring &&arguments,
        LPSECURITY_ATTRIBUTES processAttributes,
        LPSECURITY_ATTRIBUTES threadAttributes,
        bool inheritHandles,
        DWORD creationFlags,
        LPVOID environment,
        const std::wstring &currentDirectory,
        const STARTUPINFOEXW &startupInfo) :
        created(false),
        path(std::forward<const std::wstring>(path)),
        arguments(std::forward<const std::wstring>(arguments)),
        processAttributes(NULL),
        threadAttributes(NULL),
        inheritHandles(inheritHandles),
        creationFlags(creationFlags),
        environment(environment),
        currentDirectory(currentDirectory),
        startupInfo(startupInfo),
        processInformation()
    {
        init(processAttributes, threadAttributes);
    }

    Process::Process(
        const std::wstring &path,
        const std::wstring &&arguments,
        LPSECURITY_ATTRIBUTES processAttributes,
        LPSECURITY_ATTRIBUTES threadAttributes,
        bool inheritHandles,
        DWORD creationFlags,
        LPVOID environment,
        const std::wstring &&currentDirectory,
        const STARTUPINFOEXW &startupInfo) :
        created(false),
        path(path),
        arguments(std::forward<const std::wstring>(arguments)),
        processAttributes(NULL),
        threadAttributes(NULL),
        inheritHandles(inheritHandles),
        creationFlags(creationFlags),
        environment(environment),
        currentDirectory(std::forward<const std::wstring>(currentDirectory)),
        startupInfo(startupInfo),
        processInformation()
    {
        init(processAttributes, threadAttributes);
    }

    Process::Process(
        const std::wstring &&path,
        const std::wstring &arguments,
        LPSECURITY_ATTRIBUTES processAttributes,
        LPSECURITY_ATTRIBUTES threadAttributes,
        bool inheritHandles,
        DWORD creationFlags,
        LPVOID environment,
        const std::wstring &&currentDirectory,
        const STARTUPINFOEXW &startupInfo) :
        created(false),
        path(std::forward<const std::wstring>(path)),
        arguments(arguments),
        processAttributes(NULL),
        threadAttributes(NULL),
        inheritHandles(inheritHandles),
        creationFlags(creationFlags),
        environment(environment),
        currentDirectory(std::forward<const std::wstring>(currentDirectory)),
        startupInfo(startupInfo),
        processInformation()
    {
        init(processAttributes, threadAttributes);
    }

    Process::Process(Process &&other) :
        created(other.created),
        path(other.path),
        arguments(other.arguments),
        processAttributes(other.processAttributes),
        threadAttributes(other.threadAttributes),
        inheritHandles(other.inheritHandles),
        creationFlags(other.creationFlags),
        environment(other.environment),
        currentDirectory(other.currentDirectory),
        startupInfo(other.startupInfo),
        processInformation(other.processInformation)
    {
        other.processAttributes = NULL;
        other.threadAttributes = NULL;
        other.processInformation.hProcess = NULL;
        other.processInformation.hThread = NULL;
    }

    Process::~Process()
    {
        if (this->processAttributes != NULL)
        {
            delete this->processAttributes->lpSecurityDescriptor;
        }

        if (this->threadAttributes != NULL)
        {
            delete this->threadAttributes->lpSecurityDescriptor;
        }

        delete this->processAttributes;
        delete this->threadAttributes;

        if (this->startupInfo.lpAttributeList != NULL)
        {
            DeleteProcThreadAttributeList(this->startupInfo.lpAttributeList);
        }

        if (this->created)
        {
            CloseHandle(this->processInformation.hProcess);
            CloseHandle(this->processInformation.hThread);
        }
    }

    void Process::create()
    {
        if (this->created)
        {
            EXCEPTION("Already created");
        }

        wchar_t *arguments = NULL;
        if (!this->arguments.empty())
        {
            std::size_t argumentsLength = this->arguments.length() + 1;
            arguments = new wchar_t[argumentsLength];
            ZeroMemory(arguments, argumentsLength * sizeof(wchar_t));
            wcscpy_s(arguments, argumentsLength, this->arguments.c_str());
        }

        if (CreateProcessW(this->path.empty() ? NULL : this->path.c_str(), arguments, this->processAttributes, this->threadAttributes, this->inheritHandles, this->creationFlags, this->environment, this->currentDirectory.empty() ? NULL : this->currentDirectory.c_str(), reinterpret_cast<LPSTARTUPINFOW>(&this->startupInfo), &this->processInformation) == FALSE)
        {
            delete[] arguments;

            EXCEPTION_LAST_ERROR("Failed CreateProcessW");
        }

        delete[] arguments;

        this->created = true;
    }

    void Process::terminate(UINT exitCode)
    {
        if (!this->created)
        {
            return;
        }

        if (TerminateProcess(this->processInformation.hProcess, exitCode) == FALSE)
        {
            EXCEPTION_LAST_ERROR("Failed TerminateProcess");
        }

        cleanup();
    }

    bool Process::awaitTermination(DWORD milliseconds, DWORD &exitCode)
    {
        if (!this->created)
        {
            EXCEPTION("Process not created");
        }

        DWORD waitResult = WaitForSingleObject(this->processInformation.hProcess, milliseconds);
        if (waitResult == WAIT_TIMEOUT)
        {
            return false;
        }
        else if (waitResult == WAIT_OBJECT_0)
        {
            DWORD eCode;
            if (GetExitCodeProcess(this->processInformation.hProcess, &eCode) == FALSE)
            {
                EXCEPTION_LAST_ERROR("Failed GetExitCodeProcess");
            }

            cleanup();

            exitCode = eCode;

            return true;
        }
        else
        {
            EXCEPTION("Failed WaitForSingleObject\nWait result: %u", waitResult);
        }
    }

    void Process::resume()
    {
        if (!this->created)
        {
            EXCEPTION("Process not created");
        }

        if (ResumeThread(this->processInformation.hThread) == -1)
        {
            EXCEPTION_LAST_ERROR("Failed ResumeThread");
        }
    }

    void Process::init(LPSECURITY_ATTRIBUTES processAttributes, LPSECURITY_ATTRIBUTES threadAttributes)
    {
        if (processAttributes != NULL)
        {
            PSECURITY_DESCRIPTOR securityDescriptor = NULL;
            if (processAttributes->lpSecurityDescriptor != NULL)
            {
                securityDescriptor = new SECURITY_DESCRIPTOR();
                memcpy(securityDescriptor, processAttributes->lpSecurityDescriptor, sizeof(SECURITY_DESCRIPTOR));
            }

            this->processAttributes = new SECURITY_ATTRIBUTES();
            memcpy(this->processAttributes, processAttributes, sizeof(SECURITY_ATTRIBUTES));
            this->processAttributes->lpSecurityDescriptor = securityDescriptor;
        }

        if (threadAttributes != NULL)
        {
            PSECURITY_DESCRIPTOR securityDescriptor = NULL;
            if (threadAttributes->lpSecurityDescriptor != NULL)
            {
                securityDescriptor = new SECURITY_DESCRIPTOR();
                memcpy(securityDescriptor, threadAttributes->lpSecurityDescriptor, sizeof(SECURITY_DESCRIPTOR));
            }

            this->threadAttributes = new SECURITY_ATTRIBUTES();
            memcpy(this->threadAttributes, threadAttributes, sizeof(SECURITY_ATTRIBUTES));
            this->threadAttributes->lpSecurityDescriptor = securityDescriptor;
        }

        this->creationFlags |= EXTENDED_STARTUPINFO_PRESENT;

        ZeroMemory(&this->processInformation, sizeof(PROCESS_INFORMATION));
    }

    void Process::cleanup()
    {
        if (CloseHandle(this->processInformation.hProcess) == FALSE || CloseHandle(this->processInformation.hThread) == FALSE)
        {
            EXCEPTION_LAST_ERROR("Failed CloseHandle");
        }

        ZeroMemory(&this->processInformation, sizeof(PROCESS_INFORMATION));

        this->created = false;
    }
}

RegistryKey.h

#pragma once

#include <Windows.h>
#include <string>

namespace Shared
{
    class RegistryKey
    {
        public:
            RegistryKey(HKEY key, const std::wstring &subKey, DWORD options, REGSAM samDesired);
            RegistryKey(HKEY key, const std::wstring &&subKey, DWORD options, REGSAM samDesired);
            RegistryKey(RegistryKey &&other);
            RegistryKey &operator=(RegistryKey &&other);
            ~RegistryKey();

            std::wstring getRegSZ(const std::wstring &subKey, const std::wstring &valueName) const;
            DWORD getRegDword(const std::wstring &valueName) const;
            void regNotifyChangeKeyValue(bool watchSubTree, DWORD notifyFilter, HANDLE eventHandle, bool asynchronous) const;

            inline HKEY getKey() const
            {
                return this->key;
            }

            inline const std::wstring &getSubKey() const
            {
                return this->subKey;
            }

            inline DWORD getOptions() const
            {
                return this->options;
            }

            inline REGSAM getSamDesired() const
            {
                return this->samDesired;
            }

        private:
            RegistryKey(const RegistryKey &other) = delete;
            RegistryKey &operator=(const RegistryKey &other) = delete;

            void init();
            void close();

            HKEY keyHandle;
            HKEY key;
            std::wstring subKey;
            DWORD options;
            REGSAM samDesired;
    };
}

RegistryKey.cpp

#include "stdafx.h"
#include "RegistryKey.h"

#include "Util.h"

namespace Shared
{
    RegistryKey::RegistryKey(HKEY key, const std::wstring &subKey, DWORD options, REGSAM samDesired) :
        keyHandle(NULL),
        key(key),
        subKey(subKey),
        options(options),
        samDesired(samDesired)
    {
        init();
    }

    RegistryKey::RegistryKey(HKEY key, const std::wstring &&subKey, DWORD options, REGSAM samDesired) :
        keyHandle(NULL),
        key(key),
        subKey(std::forward<const std::wstring>(subKey)),
        options(options),
        samDesired(samDesired)
    {
        init();
    }

    RegistryKey::RegistryKey(RegistryKey &&other) :
        keyHandle(other.keyHandle),
        key(other.key),
        subKey(other.subKey),
        options(other.options),
        samDesired(other.samDesired)
    {
        other.keyHandle = NULL;
    }

    RegistryKey &RegistryKey::operator=(RegistryKey &&other)
    {
        close();

        this->keyHandle = other.keyHandle;
        this->key = other.key;
        this->subKey = other.subKey;
        this->options = other.options;
        this->samDesired = other.samDesired;

        other.keyHandle = NULL;

        return (*this);
    }

    RegistryKey::~RegistryKey()
    {
        try
        {
            close();
        }
        catch (std::runtime_error)
        {

        }
    }

    std::wstring RegistryKey::getRegSZ(const std::wstring &subKey, const std::wstring &valueName) const
    {
        if ((this->samDesired & KEY_QUERY_VALUE) != KEY_QUERY_VALUE)
        {
            EXCEPTION("This registry key handle does not have KEY_QUERY_VALUE rights");
        }

        std::size_t bufferSize = MAX_PATH;
        wchar_t *buffer = new wchar_t[bufferSize];
        DWORD bufferByteSize = static_cast<DWORD>(bufferSize * sizeof(wchar_t));

        LSTATUS registryGetValueStatus = RegGetValueW(this->keyHandle, subKey.empty() ? NULL : subKey.c_str(), valueName.empty() ? NULL : valueName.c_str(), RRF_RT_REG_SZ, NULL, reinterpret_cast<LPBYTE>(buffer), &bufferByteSize);

        while (registryGetValueStatus != ERROR_SUCCESS)
        {
            delete[] buffer;

            if (registryGetValueStatus == ERROR_MORE_DATA)
            {
                bufferSize *= 2;
                buffer = new wchar_t[bufferSize];
                bufferByteSize = static_cast<DWORD>(bufferSize * sizeof(wchar_t));

                registryGetValueStatus = RegGetValueW(this->keyHandle, subKey.empty() ? NULL : subKey.c_str(), valueName.empty() ? NULL : valueName.c_str(), RRF_RT_REG_SZ, NULL, reinterpret_cast<LPBYTE>(buffer), &bufferByteSize);
            }
            else
            {
                EXCEPTION("Failed RegGetValueW\nLSTATUS: %d", registryGetValueStatus);
            }
        }

        std::wstring arkInstallPath(buffer);
        delete[] buffer;

        return arkInstallPath;
    }

    DWORD RegistryKey::getRegDword(const std::wstring &valueName) const
    {
        if ((this->samDesired & KEY_QUERY_VALUE) != KEY_QUERY_VALUE)
        {
            EXCEPTION("This registry key handle does not have KEY_QUERY_VALUE rights");
        }

        DWORD result;
        DWORD dataSize = sizeof(DWORD);
        LSTATUS status = RegQueryValueExW(this->keyHandle, valueName.empty() ? NULL : valueName.c_str(), NULL, NULL, reinterpret_cast<LPBYTE>(&result), &dataSize);
        if (status != ERROR_SUCCESS)
        {
            EXCEPTION("Failed RegQueryValueExW\nLSTATUS: %d", status);
        }

        return result;
    }

    void RegistryKey::regNotifyChangeKeyValue(bool watchSubTree, DWORD notifyFilter, HANDLE eventHandle, bool asynchronous) const
    {
        if ((this->samDesired & KEY_NOTIFY) != KEY_NOTIFY)
        {
            EXCEPTION("This registry key handle does not have KEY_NOTIFY  rights");
        }

        LSTATUS result = RegNotifyChangeKeyValue(this->keyHandle, watchSubTree ? TRUE : FALSE, notifyFilter, eventHandle, asynchronous ? TRUE : FALSE);
        if (result != ERROR_SUCCESS)
        {
            EXCEPTION("Failed RegNotifyChangeKeyValue\nLSTATUS: %d", result);
        }
    }

    void RegistryKey::init()
    {
        LSTATUS registryOpenStatus = RegOpenKeyExW(this->key, this->subKey.empty() ? NULL : this->subKey.c_str(), this->options, this->samDesired, &this->keyHandle);
        if (registryOpenStatus != ERROR_SUCCESS)
        {
            EXCEPTION("Failed RegOpenKeyExW\nLSTATUS: %d", registryOpenStatus);
        }
    }

    void RegistryKey::close()
    {
        if (this->keyHandle == NULL)
        {
            return;
        }

        LSTATUS registryCloseStatus = RegCloseKey(this->keyHandle);
        if (registryCloseStatus != ERROR_SUCCESS)
        {
            EXCEPTION("Failed RegCloseKey\nSystem error code: %d", registryCloseStatus);
        }

        this->keyHandle = NULL;
    }
}

SteamClient.h

#pragma once

#include <Windows.h>

namespace BattleyeInjector
{
    class SteamClient final
    {
        public:
            SteamClient();

            void start();
            void startAndAwaitLogin(int maxTryCount);

        private:
            DWORD getActiveUserId();
    };
}

SteamClient.cpp

#include "stdafx.h"
#include "SteamClient.h"

#include <string>

#include <RegistryKey.h>
#include <Process.h>
#include <Util.h>

namespace BattleyeInjector
{
    static const HKEY STEAM_KEY = HKEY_CURRENT_USER;

    static const std::wstring STEAM_INSTALL_PATH_SUB_KEY = L"SOFTWARE\Valve\Steam";
    static const std::wstring STEAM_INSTALL_PATH_KEY_NAME = L"SteamExe";

    static const std::wstring STEAM_ACTIVE_PROCESS_SUB_KEY = L"SOFTWARE\Valve\Steam\ActiveProcess";
    static const std::wstring STEAM_ACTIVE_USER_KEY_NAME = L"ActiveUser";

    SteamClient::SteamClient()
    {

    }

    void SteamClient::start()
    {
        Shared::RegistryKey registryKey(STEAM_KEY, STEAM_INSTALL_PATH_SUB_KEY, 0, KEY_READ);
        const std::wstring steamInstallPath = registryKey.getRegSZ(L"", STEAM_INSTALL_PATH_KEY_NAME);

        STARTUPINFOEXW startupInfo;
        ZeroMemory(&startupInfo, sizeof(STARTUPINFOEXW));

        startupInfo.StartupInfo.cb = sizeof(STARTUPINFOEXW);

        Shared::Process steamProcess(steamInstallPath, L"", NULL, NULL, false, 0, NULL, L"", startupInfo);
        steamProcess.create();
    }

    void SteamClient::startAndAwaitLogin(int maxTryCount)
    {
        if (maxTryCount <= 0)
        {
            EXCEPTION("maxTryCount is invalid");
        }

        if (getActiveUserId() != 0)
        {
            return;
        }

        HANDLE eventHandle = CreateEventW(NULL, TRUE, FALSE, NULL);
        if (eventHandle == NULL)
        {
            EXCEPTION_LAST_ERROR("Failed CreateEventW");
        }

        try
        {
            Shared::RegistryKey registryKey(STEAM_KEY, STEAM_ACTIVE_PROCESS_SUB_KEY, 0, KEY_READ);
            for (int x = 0; x < maxTryCount; x++)
            {
                registryKey.regNotifyChangeKeyValue(false, REG_NOTIFY_CHANGE_LAST_SET, eventHandle, true);

                start();

                DWORD waitResult = WaitForSingleObject(eventHandle, INFINITE);
                if (waitResult != WAIT_OBJECT_0)
                {
                    EXCEPTION("Failed WaitForSingleObject\nWaitResult: %u", waitResult);
                }

                if (getActiveUserId() != 0)
                {
                    return;
                }

                if (ResetEvent(eventHandle) == FALSE)
                {
                    EXCEPTION_LAST_ERROR("Failed ResetEvent");
                }
            }

            EXCEPTION("Failed await login to steam");
        }
        catch (...)
        {
            CloseHandle(eventHandle);

            throw;
        }
    }

    DWORD SteamClient::getActiveUserId()
    {
        Shared::RegistryKey registryKey(STEAM_KEY, STEAM_ACTIVE_PROCESS_SUB_KEY, 0, KEY_READ);

        return registryKey.getRegDword(STEAM_ACTIVE_USER_KEY_NAME);
    }
}