enderalse/source/fs.dll/skse64/skse64_loader_common/Steam.cpp

196 lines
4.0 KiB
C++

#include "Steam.h"
#include "skse64_loader_common/LoaderError.h"
#include <tlhelp32.h>
#include <string>
std::string GetRegKey(HKEY root, const char * path, char * value)
{
std::string result;
HKEY key;
UInt32 err = RegOpenKeyEx(root, path, 0, KEY_READ, &key);
if(!err)
{
UInt32 dataLen = 0;
// lol race condition
err = RegQueryValueEx(key, value, NULL, NULL, NULL, &dataLen);
if(!err)
{
result.resize(dataLen);
err = RegQueryValueEx(key, value, NULL, NULL, (BYTE *)&result[0], &dataLen);
if(!err)
{
// trim null terminator
if(result.length() > 0)
result.resize(result.length() - 1);
}
else
{
_ERROR("GetRegKey: error getting value (%08X)", err);
}
}
else
{
_ERROR("GetRegKey: error querying value length (%08X)", err);
}
RegCloseKey(key);
}
else
{
_ERROR("GetRegKey: registry key not found (%08X)", err);
}
return result;
}
std::string GetSteamRoot(void)
{
return GetRegKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Valve\\Steam", "InstallPath");
}
std::string GetSteamClientDLLPath(void)
{
return GetRegKey(HKEY_CURRENT_USER, "SOFTWARE\\Valve\\Steam\\ActiveProcess", "SteamClientDll");
}
bool SteamCheckPassive(void)
{
bool result = false;
HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(snap != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32 proc;
proc.dwSize = sizeof(proc);
if(Process32First(snap, &proc))
{
do
{
if(!_stricmp(proc.szExeFile, "steam.exe"))
{
_MESSAGE("found steam");
result = true;
break;
}
}
while(Process32Next(snap, &proc));
}
else
{
_ERROR("SteamCheck: Module32First failed (%d)", GetLastError());
result = true;
}
CloseHandle(snap);
}
else
{
_ERROR("SteamCheck: CreateToolhelp32Snapshot failed (%d)", GetLastError());
result = true; // if for whatever reason we can't scan, assume steam is running
}
return result;
}
static bool SteamCheckActive(void)
{
bool result = false;
HMODULE steamAPI = LoadLibrary("steam_api.dll");
if(steamAPI)
{
typedef bool (* _SteamAPI_IsSteamRunning)(void);
_SteamAPI_IsSteamRunning SteamAPI_IsSteamRunning = NULL;
// this just checks HKCU\Software\Valve\Steam\ActiveProcess\pid
// to see if it's running, however process IDs can be reused and it doesn't clean the registry key
// on exit
SteamAPI_IsSteamRunning = (_SteamAPI_IsSteamRunning)GetProcAddress(steamAPI, "SteamAPI_IsSteamRunning");
if(SteamAPI_IsSteamRunning)
{
UInt32 startTime = GetTickCount();
const UInt32 kSteamTimeout = 10 * 1000; // 10 seconds
while((GetTickCount() - startTime) >= kSteamTimeout)
{
if(SteamAPI_IsSteamRunning())
{
result = true;
break;
}
Sleep(100);
}
if(!result)
{
_ERROR("timed out waiting for steam boot");
}
}
else
{
_ERROR("couldn't get steam API ptr");
}
FreeLibrary(steamAPI);
}
else
{
_ERROR("couldn't load steam API DLL (%08X)", GetLastError());
}
return result;
}
bool SteamLaunch(void)
{
std::string steamRoot = GetSteamRoot();
_MESSAGE("steam root = %s", steamRoot.c_str());
if(steamRoot.empty())
return false;
std::string steamEXEPath = steamRoot + "\\Steam.exe";
STARTUPINFO startupInfo = { 0 };
PROCESS_INFORMATION procInfo = { 0 };
startupInfo.cb = sizeof(startupInfo);
if(!CreateProcess(
steamEXEPath.c_str(),
NULL, // no args
NULL, // default process security
NULL, // default thread security
FALSE, // don't inherit handles
0, // no options
NULL, // no new environment block
steamRoot.c_str(), // new cwd
&startupInfo, &procInfo))
{
PrintLoaderError("Launching Steam failed (%08X).", GetLastError());
return false;
}
// this doesn't do anything useful
// bool result = SteamCheckActive();
// this is an ugly hack. wait for steam to start pumping messages
WaitForInputIdle(procInfo.hProcess, INFINITE);
// and then you know some more just because even then it isn't ready
Sleep(1000 * 5);
// clean up
CloseHandle(procInfo.hProcess);
CloseHandle(procInfo.hThread);
return true;
}