Skip to content

Instantly share code, notes, and snippets.

@Andon13
Created December 21, 2019 21:18
Show Gist options
  • Save Andon13/b83227a2fa315b8a87aa6c09dedd0ec2 to your computer and use it in GitHub Desktop.
Save Andon13/b83227a2fa315b8a87aa6c09dedd0ec2 to your computer and use it in GitHub Desktop.
Wrap SteamAPI Using a Transient AppID
#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