[steam] Avoid crash taking screenshots after Steam client is closed

This commit is contained in:
David Capello 2020-06-11 14:51:28 -03:00
parent 2f472f0760
commit c8999af6d6
3 changed files with 97 additions and 1 deletions

View File

@ -48,6 +48,10 @@
#include "ui/intern.h"
#include "ui/ui.h"
#ifdef ENABLE_STEAM
#include "steam/steam.h"
#endif
#include <algorithm>
#include <list>
#include <vector>
@ -366,6 +370,11 @@ void defer_invalid_rect(const gfx::Rect& rc)
// Manager event handler.
bool CustomizedGuiManager::onProcessMessage(Message* msg)
{
#ifdef ENABLE_STEAM
if (auto steamAPI = steam::SteamAPI::instance())
steamAPI->runCallbacks();
#endif
switch (msg->type()) {
case kCloseDisplayMessage: {

View File

@ -19,12 +19,34 @@
namespace steam {
typedef uint32_t HSteamPipe;
typedef uint32_t HSteamUser;
typedef uint32_t ScreenshotHandle;
typedef void* ISteamScreenshots;
enum {
// Last callback received from Steam client when it's Steam is closed
kSteamServersDisconnected = 103,
kSteamUndocumentedLastCallback = 1009,
};
struct CallbackMsg_t {
HSteamUser steamUser;
int callback;
uint8_t* pubParam;
int cubParam;
};
// Steam main API
typedef bool __cdecl (*SteamAPI_Init_Func)();
typedef void __cdecl (*SteamAPI_Shutdown_Func)();
typedef HSteamPipe __cdecl (*SteamAPI_GetHSteamPipe_Func)();
// Steam callbacks
typedef void __cdecl (*SteamAPI_ManualDispatch_Init_Func)();
typedef void __cdecl (*SteamAPI_ManualDispatch_RunFrame_Func)(HSteamPipe);
typedef bool __cdecl (*SteamAPI_ManualDispatch_GetNextCallback_Func)(HSteamPipe, CallbackMsg_t*);
typedef void __cdecl (*SteamAPI_ManualDispatch_FreeLastCallback_Func)(HSteamPipe);
// ISteamScreenshots
typedef ISteamScreenshots* __cdecl (*SteamAPI_SteamScreenshots_v003_Func)();
@ -67,6 +89,21 @@ public:
return;
}
// Get functions to dispatch callbacks manually
auto SteamAPI_ManualDispatch_Init = GETPROC(SteamAPI_ManualDispatch_Init);
SteamAPI_ManualDispatch_RunFrame = GETPROC(SteamAPI_ManualDispatch_RunFrame);
SteamAPI_ManualDispatch_GetNextCallback = GETPROC(SteamAPI_ManualDispatch_GetNextCallback);
SteamAPI_ManualDispatch_FreeLastCallback = GETPROC(SteamAPI_ManualDispatch_FreeLastCallback);
auto SteamAPI_GetHSteamPipe = GETPROC(SteamAPI_GetHSteamPipe);
if (SteamAPI_ManualDispatch_Init &&
SteamAPI_ManualDispatch_RunFrame &&
SteamAPI_ManualDispatch_GetNextCallback &&
SteamAPI_ManualDispatch_FreeLastCallback &&
SteamAPI_GetHSteamPipe) {
SteamAPI_ManualDispatch_Init();
m_pipe = SteamAPI_GetHSteamPipe();
}
LOG("STEAM: Steam initialized\n");
m_initialized = true;
}
@ -81,13 +118,44 @@ public:
SteamAPI_Shutdown();
}
base::unload_dll(m_steamLib);
unloadLib();
}
bool initialized() const {
return m_initialized;
}
void runCallbacks() {
if (!m_pipe)
return;
ASSERT(SteamAPI_ManualDispatch_RunFrame);
ASSERT(SteamAPI_ManualDispatch_GetNextCallback);
ASSERT(SteamAPI_ManualDispatch_FreeLastCallback);
SteamAPI_ManualDispatch_RunFrame(m_pipe);
CallbackMsg_t msg;
if (SteamAPI_ManualDispatch_GetNextCallback(m_pipe, &msg)) {
//TRACEARGS("SteamAPI_ManualDispatch_GetNextCallback", msg.callback);
bool disconnected = false;
if (msg.callback == kSteamServersDisconnected ||
msg.callback == kSteamUndocumentedLastCallback) {
disconnected = true;
}
SteamAPI_ManualDispatch_FreeLastCallback(m_pipe);
// If the Steam client is closed, we have to unload the DLL and
// don't use the pipe or any Steam API at all, in other case we
// would crash.
if (disconnected) {
LOG("STEAM: Disconnected\n");
unloadLib();
}
}
}
bool writeScreenshot(void* rgbBuffer,
uint32_t sizeInBytes,
int width, int height) {
@ -112,8 +180,21 @@ public:
}
private:
void unloadLib() {
base::unload_dll(m_steamLib);
m_steamLib = nullptr;
m_initialized = false;
m_pipe = 0;
}
bool m_initialized = false;
base::dll m_steamLib = nullptr;
// To handle callbacks manually
HSteamPipe m_pipe = 0;
SteamAPI_ManualDispatch_RunFrame_Func SteamAPI_ManualDispatch_RunFrame = nullptr;
SteamAPI_ManualDispatch_GetNextCallback_Func SteamAPI_ManualDispatch_GetNextCallback = nullptr;
SteamAPI_ManualDispatch_FreeLastCallback_Func SteamAPI_ManualDispatch_FreeLastCallback = nullptr;
};
SteamAPI* g_instance = nullptr;
@ -144,6 +225,11 @@ bool SteamAPI::initialized() const
return m_impl->initialized();
}
void SteamAPI::runCallbacks()
{
m_impl->runCallbacks();
}
bool SteamAPI::writeScreenshot(void* rgbBuffer,
uint32_t sizeInBytes,
int width, int height)

View File

@ -19,6 +19,7 @@ public:
~SteamAPI();
bool initialized() const;
void runCallbacks();
bool writeScreenshot(void* rgbBuffer,
uint32_t sizeInBytes,