Created
December 21, 2019 21:18
-
-
Save Andon13/b83227a2fa315b8a87aa6c09dedd0ec2 to your computer and use it in GitHub Desktop.
Wrap SteamAPI Using a Transient AppID
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _CRT_SECURE_NO_WARNINGS | |
// add headers that you want to pre-compile here | |
#include <Windows.h> | |
BOOL | |
APIENTRY | |
DllMain ( HMODULE hModule, | |
DWORD ul_reason_for_call, | |
LPVOID lpReserved ) | |
{ | |
switch (ul_reason_for_call) | |
{ | |
case DLL_PROCESS_ATTACH: | |
case DLL_THREAD_ATTACH: | |
case DLL_THREAD_DETACH: | |
case DLL_PROCESS_DETACH: | |
break; | |
} | |
return TRUE; | |
} | |
#include "../SKIF/steam/steam_api.h" | |
#include <string> | |
const wchar_t* | |
SK_GetSteamDir (void) | |
{ | |
static | |
wchar_t wszSteamPath [MAX_PATH + 2] = { }; | |
DWORD len = MAX_PATH; | |
LSTATUS status = | |
RegGetValueW ( HKEY_CURRENT_USER, | |
LR"(SOFTWARE\Valve\Steam\)", | |
L"SteamPath", | |
RRF_RT_REG_SZ, | |
nullptr, | |
wszSteamPath, | |
(LPDWORD)&len ); | |
if (status == ERROR_SUCCESS) | |
return wszSteamPath; | |
else | |
return nullptr; | |
} | |
constexpr int | |
__stdcall | |
SK_GetBitness (void) | |
{ | |
#ifdef _M_AMD64 | |
return 64; | |
#endif | |
return 32; | |
} | |
#define SK_RunLHIfBitness(b,l,r) SK_GetBitness () == (b) ? (l) : (r) | |
class SKIF_TempAppId { | |
public: | |
~SKIF_TempAppId (void) | |
{ | |
cleanup (); | |
} | |
void cleanup (void) | |
{ | |
if (fAppId != nullptr) | |
{ | |
fclose (fAppId); | |
fAppId = nullptr; | |
DeleteFileW (L"steam_appid.txt"); | |
} | |
} | |
bool set (int32 appid) | |
{ | |
SetEnvironmentVariableA ( | |
"SteamGameId", | |
std::to_string (appid).c_str () | |
); | |
cleanup (); | |
fAppId = | |
_wfsopen (L"steam_appid.txt", L"w", _SH_DENYNO); | |
if (fAppId != nullptr) | |
{ | |
fputws ( | |
std::to_wstring (appid).c_str (), | |
fAppId | |
); | |
fflush (fAppId); | |
} | |
return true; | |
} | |
protected: | |
private: | |
FILE* fAppId = nullptr; | |
} appid_override; | |
bool | |
SK_Steam_LoadOverlay (int32 appid = -1) | |
{ | |
return false; | |
if (appid != -1) | |
{ | |
appid_override.set (appid); | |
} | |
static HMODULE | |
hModOverlay = nullptr; | |
if (hModOverlay != nullptr) | |
return true; | |
const wchar_t* wszSteamPath = | |
SK_GetSteamDir (); | |
if (wszSteamPath == nullptr) | |
return false; | |
wchar_t wszOverlayDLL [MAX_PATH + 2] = { }; | |
lstrcatW ( wszOverlayDLL, wszSteamPath ); | |
lstrcatW ( wszOverlayDLL, | |
SK_RunLHIfBitness ( 64, LR"(/GameOverlayRenderer64.dll)", | |
LR"(/GameOverlayRenderer.dll)" ) ); | |
hModOverlay = | |
LoadLibraryW (wszOverlayDLL); | |
return hModOverlay != nullptr; | |
} | |
using SteamAPI_Shutdown_pfn = void (S_CALLTYPE*)(void); | |
using SteamAPI_RunCallbacks_pfn = void (S_CALLTYPE*)(void); | |
using SteamAPI_GetHSteamPipe_pfn = HSteamPipe (S_CALLTYPE*)(void); | |
using SteamAPI_GetHSteamUser_pfn = HSteamUser (S_CALLTYPE*)(void); | |
using SteamInternal_CreateInterface_pfn = void* (S_CALLTYPE*)(const char*); | |
#include <stdexcept> | |
#include <concurrent_unordered_map.h> | |
typedef HSteamPipe HVaporPipe; | |
typedef HSteamUser HVaporUser; | |
class SK_VaporCtx; | |
#define DeclVaporMap(x) concurrency::concurrent_unordered_map < \ | |
x, std::unique_ptr <SK_VaporCtx> > | |
static DeclVaporMap | |
(HVaporPipe) | |
__VaporPipes; | |
extern "C" | |
__declspec (dllexport) | |
HVaporPipe | |
vaporCreatePipeForAppID ( const wchar_t* wszPipeDll, | |
UINT32 appid ); | |
static bool | |
VaporInternal_ChangeAppID ( SK_VaporCtx* pCtx, | |
uint32_t appid ); | |
class SK_VaporCtx { | |
public: | |
~SK_VaporCtx (void) | |
{ | |
Shutdown (); | |
} | |
const wchar_t* GetDllName (void) const { | |
return | |
dll_name.c_str (); | |
} | |
HVaporPipe GetPipe (void) const { | |
return | |
pipe; | |
} | |
void Shutdown (void) | |
{ | |
if ( hModSteamAPI != nullptr && | |
InterlockedCompareExchange (&init_, FALSE, TRUE) == TRUE ) | |
{ | |
ISteamClient* pClient = (ISteamClient *) | |
_CreateInterface (STEAMCLIENT_INTERFACE_VERSION); | |
pClient->ReleaseUser (pipe, user); | |
user = NULL; | |
if (pClient->BReleaseSteamPipe (pipe)) | |
{ | |
pipe = NULL; | |
pClient->BShutdownIfAllPipesClosed (); | |
} | |
_Shutdown (); | |
while (! FreeLibrary (hModSteamAPI)) | |
; | |
hModSteamAPI = nullptr; | |
} | |
} | |
bool InitSafe (const wchar_t* wszPipeDll = nullptr, uint32_t appid = 0) | |
{ | |
hModSteamAPI = | |
LoadLibraryW ( wszPipeDll == nullptr ? | |
SK_RunLHIfBitness ( 64, L"steam_api64.dll", | |
L"steam_api.dll" ) | |
: wszPipeDll ); | |
wchar_t wszName [MAX_PATH + 2] = { }; | |
GetModuleFileNameW ( | |
hModSteamAPI, wszName, | |
MAX_PATH ); | |
if (hModSteamAPI != 0) | |
{ | |
dll_name = wszName; | |
using SteamAPI_InitSafe_pfn = bool (S_CALLTYPE*)(void); | |
SteamAPI_InitSafe_pfn | |
SteamAPI_InitSafe = | |
(SteamAPI_InitSafe_pfn) GetProcAddress ( | |
hModSteamAPI, | |
"SteamAPI_Init" ); | |
if (SteamAPI_InitSafe != nullptr) | |
{ | |
if (SteamAPI_InitSafe ()) | |
{ | |
_CreateInterface = (SteamInternal_CreateInterface_pfn) | |
GetProcAddress (hModSteamAPI, "SteamInternal_CreateInterface"); | |
_Shutdown = (SteamAPI_Shutdown_pfn) | |
GetProcAddress (hModSteamAPI, "SteamAPI_Shutdown"); | |
_RunCallbacks = (SteamAPI_RunCallbacks_pfn) | |
GetProcAddress (hModSteamAPI, "SteamAPI_RunCallbacks"); | |
_GetHSteamUser = (SteamAPI_GetHSteamUser_pfn) | |
GetProcAddress (hModSteamAPI, "SteamAPI_GetHSteamUser"); | |
_GetHSteamPipe = (SteamAPI_GetHSteamPipe_pfn) | |
GetProcAddress (hModSteamAPI, "SteamAPI_GetHSteamPipe"); | |
} | |
} | |
else { | |
return false; | |
} | |
client = (ISteamClient *) | |
_CreateInterface (STEAMCLIENT_INTERFACE_VERSION); | |
if (client != nullptr) | |
{ | |
pipe = client->CreateSteamPipe ( ); | |
user = client->ConnectToGlobalUser (pipe); | |
utils = | |
client->GetISteamUtils ( pipe, | |
STEAMUTILS_INTERFACE_VERSION ); | |
ugc = | |
client->GetISteamUGC ( user, pipe, | |
STEAMUGC_INTERFACE_VERSION ); | |
remote_storage = | |
client->GetISteamRemoteStorage ( user, pipe, | |
STEAMREMOTESTORAGE_INTERFACE_VERSION ); | |
WriteRelease (&init_, TRUE); | |
} | |
return | |
ReadAcquire (&init_); | |
} | |
return false; | |
} | |
void RunCallbacks (void) | |
{ | |
if (ReadAcquire (&init_) != FALSE) | |
{ | |
_RunCallbacks (); | |
} | |
} | |
ISteamClient* Client (void) { return client; } | |
ISteamUGC* UGC (void) { return ugc; } | |
ISteamUtils* Utils (void) { return utils; } | |
ISteamRemoteStorage* RemoteStorage (void) { return remote_storage; } | |
protected: | |
HMODULE hModSteamAPI = nullptr; | |
std::wstring dll_name = L""; | |
SteamAPI_Shutdown_pfn | |
_Shutdown = nullptr; | |
SteamAPI_GetHSteamUser_pfn | |
_GetHSteamUser = nullptr; | |
SteamAPI_GetHSteamPipe_pfn | |
_GetHSteamPipe = nullptr; | |
SteamAPI_RunCallbacks_pfn | |
_RunCallbacks = nullptr; | |
SteamInternal_CreateInterface_pfn | |
_CreateInterface = nullptr; | |
HSteamPipe pipe = NULL; | |
HSteamUser user = NULL; | |
ISteamUGC* ugc = nullptr; | |
ISteamUtils* utils = nullptr; | |
ISteamClient* client = nullptr; | |
ISteamRemoteStorage* remote_storage = nullptr; | |
volatile LONG init_ = FALSE; | |
private: | |
} vapor_ctx; // Uses the game's AppID | |
static bool | |
VaporInternal_ChangeAppID (SK_VaporCtx* pCtx, uint32_t appid) | |
{ | |
bool bRet = false; | |
if (pCtx == nullptr) | |
return bRet; | |
std::wstring dll = | |
pCtx->GetDllName (); | |
pCtx->Shutdown ( ); | |
appid_override.set ( appid ); | |
bRet = | |
pCtx->InitSafe ( dll.c_str (), | |
appid ); | |
appid_override.cleanup ( ); | |
return | |
bRet; | |
}; | |
extern "C" | |
__declspec (dllexport) | |
void | |
vaporSetAppID (UINT32 appid) | |
{ | |
SK_Steam_LoadOverlay ( appid ); | |
VaporInternal_ChangeAppID ( &vapor_ctx, appid ); | |
} | |
extern "C" | |
__declspec (dllexport) | |
bool | |
vaporSetAppIDForPipe (UINT32 appid, HVaporPipe hPipe) | |
{ | |
auto vapor_ctx_record = | |
__VaporPipes.find (hPipe); | |
if (vapor_ctx_record != __VaporPipes.cend ()) | |
{ | |
auto vapor_ctx = | |
vapor_ctx_record->second.get (); | |
SK_Steam_LoadOverlay ( appid); | |
VaporInternal_ChangeAppID (vapor_ctx, appid); | |
if ( vapor_ctx->Utils () != nullptr && | |
vapor_ctx->Utils ()->GetAppID () == appid ) | |
{ | |
return true; | |
} | |
} | |
return false; | |
} | |
extern "C" | |
__declspec (dllexport) | |
HVaporPipe | |
vaporCreatePipeForAppID ( const wchar_t* wszPipeDll, | |
UINT32 appid ) | |
{ | |
HVaporPipe pipe = 0; | |
SK_VaporCtx* pCtx = | |
new SK_VaporCtx (); | |
if (pCtx->InitSafe (wszPipeDll, appid)) | |
{ | |
__VaporPipes [pCtx->GetPipe ()] = | |
std::unique_ptr < | |
SK_VaporCtx > | |
( pCtx ); | |
return | |
pCtx->GetPipe (); | |
} | |
return 0; | |
} | |
extern "C" | |
__declspec (dllexport) | |
ISteamRemoteStorage* | |
RemoteStorage (void) | |
{ | |
return | |
vapor_ctx.RemoteStorage (); | |
} | |
extern "C" | |
__declspec (dllexport) | |
ISteamUGC* | |
UGC (void) | |
{ | |
return | |
vapor_ctx.UGC (); | |
} | |
extern "C" | |
__declspec (dllexport) | |
ISteamUtils* | |
Utils (void) | |
{ | |
return | |
vapor_ctx.Utils (); | |
} | |
extern "C" | |
__declspec (dllexport) | |
ISteamClient* | |
Client (void) | |
{ | |
return | |
vapor_ctx.Client (); | |
} | |
extern "C" | |
__declspec (dllexport) | |
void | |
RunCallbacks (void) | |
{ | |
vapor_ctx.RunCallbacks (); | |
} | |
extern "C" | |
__declspec (dllexport) | |
ISteamRemoteStorage* | |
vaporRemoteStorage (HVaporPipe pipe) | |
{ | |
auto vapor_ctx_rec = | |
__VaporPipes.find (pipe); | |
if (vapor_ctx_rec != __VaporPipes.cend ()) | |
{ | |
return | |
vapor_ctx_rec->second->RemoteStorage (); | |
} | |
return nullptr; | |
} | |
extern "C" | |
__declspec (dllexport) | |
ISteamUGC* | |
vaporUGC (HVaporPipe pipe) | |
{ | |
auto vapor_ctx_rec = | |
__VaporPipes.find (pipe); | |
if (vapor_ctx_rec != __VaporPipes.cend ()) | |
{ | |
return | |
vapor_ctx_rec->second->UGC (); | |
} | |
return nullptr; | |
} | |
extern "C" | |
__declspec (dllexport) | |
ISteamUtils* | |
vaporUtils (HVaporPipe pipe) | |
{ | |
auto vapor_ctx_rec = | |
__VaporPipes.find (pipe); | |
if (vapor_ctx_rec != __VaporPipes.cend ()) | |
{ | |
return | |
vapor_ctx_rec->second->Utils (); | |
} | |
return nullptr; | |
} | |
extern "C" | |
__declspec (dllexport) | |
ISteamClient* | |
vaporClient (HVaporPipe pipe) | |
{ | |
auto vapor_ctx_rec = | |
__VaporPipes.find (pipe); | |
if (vapor_ctx_rec != __VaporPipes.cend ()) | |
{ | |
return | |
vapor_ctx_rec->second->Client (); | |
} | |
return nullptr; | |
} | |
extern "C" | |
__declspec (dllexport) | |
void | |
vaporRunCallbacks (HVaporPipe pipe) | |
{ | |
auto vapor_ctx_rec = | |
__VaporPipes.find (pipe); | |
if (vapor_ctx_rec != __VaporPipes.cend ()) | |
{ | |
vapor_ctx_rec->second->RunCallbacks (); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment