diff --git a/Include/xsapi-c/leaderboard_c.h b/Include/xsapi-c/leaderboard_c.h
index 1169164c..aa95cabc 100644
--- a/Include/xsapi-c/leaderboard_c.h
+++ b/Include/xsapi-c/leaderboard_c.h
@@ -166,12 +166,12 @@ typedef struct XblLeaderboardRow
uint32_t rank;
///
- /// The global rank of the player.
+ /// The global rank of the player. If globalrank is 0, then the user has no global rank.
///
uint32_t globalRank;
///
- /// UTF-8 encoded values for each column in the leaderboard row for the player.
+ /// UTF-8 encoded JSON values for each column in the leaderboard row for the player.
///
_Field_z_ const char** columnValues;
diff --git a/Include/xsapi-c/services_c.h b/Include/xsapi-c/services_c.h
index 3109c4b9..d2d0c741 100644
--- a/Include/xsapi-c/services_c.h
+++ b/Include/xsapi-c/services_c.h
@@ -34,4 +34,6 @@
#include
#include
#include
-#include
\ No newline at end of file
+#if XSAPI_NOTIFICATION_SERVICE
+#include
+#endif
\ No newline at end of file
diff --git a/Include/xsapi-cpp/impl/notification.hpp b/Include/xsapi-cpp/impl/notification.hpp
index 28e6d70a..cb464c04 100644
--- a/Include/xsapi-cpp/impl/notification.hpp
+++ b/Include/xsapi-cpp/impl/notification.hpp
@@ -4,7 +4,8 @@
#pragma once
#include "public_utils.h"
-NAMESPACE_MICROSOFT_XBOX_SERVICES_NOTIFICATION_CPP_BEGIN
+NAMESPACE_MICROSOFT_XBOX_SERVICES_NOTIFICATION_CPP_BEGIN
+#if XSAPI_NOTIFICATION_SERVICE
notification_service::notification_service(_In_ XblContextHandle contextHandle)
{
XblContextDuplicateHandle(contextHandle, &m_xblContext);
@@ -12,6 +13,9 @@ notification_service::notification_service(_In_ XblContextHandle contextHandle)
notification_service::~notification_service()
{
+#if !XSAPI_UNIT_TESTS
+ unsubscribe_from_notifications().wait();
+#endif
XblContextCloseHandle(m_xblContext);
}
@@ -48,32 +52,32 @@ inline invite_notification_event_args::invite_notification_event_args(_In_ const
{
}
-const string_t& invite_notification_event_args::invited_xbox_user_id() const
+string_t invite_notification_event_args::invited_xbox_user_id() const
{
return Utils::StringTFromUint64(m_gameInviteArgs.invitedXboxUserId);
}
-const string_t& invite_notification_event_args::sender_xbox_user_id() const
+string_t invite_notification_event_args::sender_xbox_user_id() const
{
return Utils::StringTFromUint64(m_gameInviteArgs.senderXboxUserId);
}
-const string_t& invite_notification_event_args::sender_gamertag() const
+string_t invite_notification_event_args::sender_gamertag() const
{
return Utils::StringTFromUtf8(m_gameInviteArgs.senderGamertag);
}
-const string_t& invite_notification_event_args::invite_handle_id() const
+string_t invite_notification_event_args::invite_handle_id() const
{
return Utils::StringTFromUtf8(m_gameInviteArgs.inviteHandleId);
}
-const string_t& invite_notification_event_args::invite_protocol() const
+string_t invite_notification_event_args::invite_protocol() const
{
return Utils::StringTFromUtf8(m_gameInviteArgs.inviteProtocol);
}
-const utility::datetime& invite_notification_event_args::expiration() const
+utility::datetime invite_notification_event_args::expiration() const
{
return Utils::DatetimeFromTimeT(m_gameInviteArgs.expiration);
}
@@ -88,42 +92,42 @@ inline achievement_unlocked_notification_event_args::achievement_unlocked_notifi
{
}
-const string_t& achievement_unlocked_notification_event_args::name() const
+string_t achievement_unlocked_notification_event_args::name() const
{
return Utils::StringTFromUtf8(m_achievementUnlock.achievementName);
}
-const string_t achievement_unlocked_notification_event_args::id() const
+string_t achievement_unlocked_notification_event_args::id() const
{
return Utils::StringTFromUtf8(m_achievementUnlock.achievementId);
}
-const string_t& achievement_unlocked_notification_event_args::description() const
+string_t achievement_unlocked_notification_event_args::description() const
{
return Utils::StringTFromUtf8(m_achievementUnlock.achievementDescription);
}
-const string_t& achievement_unlocked_notification_event_args::icon_url() const
+string_t achievement_unlocked_notification_event_args::icon_url() const
{
return Utils::StringTFromUtf8(m_achievementUnlock.achievementIcon);
}
-const uint64_t achievement_unlocked_notification_event_args::gamerscore() const
+uint64_t achievement_unlocked_notification_event_args::gamerscore() const
{
return m_achievementUnlock.gamerscore;
}
-const string_t& achievement_unlocked_notification_event_args::deeplink() const
+string_t achievement_unlocked_notification_event_args::deeplink() const
{
return Utils::StringTFromUtf8(m_achievementUnlock.deepLink);
}
-const string_t& achievement_unlocked_notification_event_args::xbox_user_id() const
+string_t achievement_unlocked_notification_event_args::xbox_user_id() const
{
return Utils::StringTFromUint64(m_achievementUnlock.xboxUserId);
}
-const utility::datetime& achievement_unlocked_notification_event_args::unlockTime() const
+utility::datetime achievement_unlocked_notification_event_args::unlockTime() const
{
return Utils::DatetimeFromTimeT(m_achievementUnlock.timeUnlocked);
}
@@ -144,7 +148,6 @@ pplx::task> notification_service::subscribe_to_notificati
)
{
auto xblContext = m_xblContext;
- void* context = m_xblContext;
m_inviteHandler = multiplayerInviteHandler;
m_achievementUnlockedHandler = achievementUnlockHandler;
@@ -158,7 +161,7 @@ pplx::task> notification_service::subscribe_to_notificati
auto service = static_cast(context);
service->game_invite_handler()(resultInviteArgs);
},
- context
+ shared_from_this().get()
);
delete(asyncWrapper);
@@ -171,7 +174,7 @@ pplx::task> notification_service::subscribe_to_notificati
auto service = static_cast(context);
service->achievement_unlock_handler()(achievementUnlockArgs);
},
- context
+ shared_from_this().get()
);
return asyncWrapper->Task(S_OK);
@@ -200,4 +203,5 @@ pplx::task> notification_service::unsubscribe_from_notifi
return asyncWrapper->Task(S_OK);
}
#endif
+#endif
NAMESPACE_MICROSOFT_XBOX_SERVICES_NOTIFICATION_CPP_END
\ No newline at end of file
diff --git a/Include/xsapi-cpp/impl/xbox_live_context.hpp b/Include/xsapi-cpp/impl/xbox_live_context.hpp
index 298031e9..07945f3a 100644
--- a/Include/xsapi-cpp/impl/xbox_live_context.hpp
+++ b/Include/xsapi-cpp/impl/xbox_live_context.hpp
@@ -11,8 +11,9 @@
#include "xsapi-cpp/xbox_live_context.h"
#include "xsapi-cpp/events.h"
+#if XSAPI_NOTIFICATION_SERVICE
#include "xsapi-cpp/notification_service.h"
-
+#endif
NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN
xbox_live_context::xbox_live_context(_In_ XblUserHandle user)
@@ -21,11 +22,12 @@ xbox_live_context::xbox_live_context(_In_ XblUserHandle user)
if (FAILED(hr)) throw std::runtime_error("XblContextCreateHandle failed");
XblSetApiType(XblApiType::XblCPPApi);
+#if XSAPI_NOTIFICATION_SERVICE
// Unlike the rest of the services, notification_service needs to maintain state
// That is because of the differences between C-APIs for subscribing for RTA events
// and the C++ subscribe_to_notifications call
m_notificationService = std::make_shared(m_handle);
-
+#endif
}
xbox_live_context::xbox_live_context(_In_ XblContextHandle xboxLiveContextHandle)
@@ -34,10 +36,12 @@ xbox_live_context::xbox_live_context(_In_ XblContextHandle xboxLiveContextHandle
if (FAILED(hr)) throw std::runtime_error("XblContextCreateHandle failed");
XblSetApiType(XblApiType::XblCPPApi);
+#if XSAPI_NOTIFICATION_SERVICE
// Unlike the rest of the services, notification_service needs to maintain state
// That is because of the differences between C-APIs for subscribing for RTA events
// and the C++ subscribe_to_notifications call
m_notificationService = std::make_shared(m_handle);
+#endif
}
xbox_live_context::~xbox_live_context()
@@ -52,6 +56,13 @@ XblUserHandle xbox_live_context::user()
return userHandle;
}
+XblContextHandle xbox_live_context::handle()
+{
+ XblContextHandle contextHandle = nullptr;
+ XblContextDuplicateHandle(m_handle, &contextHandle);
+ return contextHandle;
+}
+
string_t xbox_live_context::xbox_live_user_id()
{
stringstream_t ss;
@@ -137,7 +148,7 @@ presence::presence_service xbox_live_context::presence_service()
return presence::presence_service(m_handle);
}
-#if HC_PLATFORM == HC_PLATFORM_WIN32
+#if XSAPI_NOTIFICATION_SERVICE
std::shared_ptr xbox_live_context::notification_service()
{
return m_notificationService;
diff --git a/Include/xsapi-cpp/notification_service.h b/Include/xsapi-cpp/notification_service.h
index 3141b70b..8ab82e22 100644
--- a/Include/xsapi-cpp/notification_service.h
+++ b/Include/xsapi-cpp/notification_service.h
@@ -16,12 +16,12 @@ class xbox_live_context;
class invite_notification_event_args
{
public:
- inline const string_t& invited_xbox_user_id() const;
- inline const string_t& sender_xbox_user_id() const;
- inline const string_t& sender_gamertag() const;
- inline const string_t& invite_handle_id() const;
- inline const string_t& invite_protocol() const;
- inline const utility::datetime& expiration() const;
+ inline string_t invited_xbox_user_id() const;
+ inline string_t sender_xbox_user_id() const;
+ inline string_t sender_gamertag() const;
+ inline string_t invite_handle_id() const;
+ inline string_t invite_protocol() const;
+ inline utility::datetime expiration() const;
inline const multiplayer::multiplayer_session_reference session_reference() const;
///
@@ -36,14 +36,14 @@ class invite_notification_event_args
class achievement_unlocked_notification_event_args
{
public:
- inline const string_t& name() const;
- inline const string_t id() const;
- inline const string_t& description() const;
- inline const string_t& icon_url() const;
- inline const uint64_t gamerscore() const;
- inline const string_t& deeplink() const;
- inline const string_t& xbox_user_id() const;
- inline const utility::datetime& unlockTime() const;
+ inline string_t name() const;
+ inline string_t id() const;
+ inline string_t description() const;
+ inline string_t icon_url() const;
+ inline uint64_t gamerscore() const;
+ inline string_t deeplink() const;
+ inline string_t xbox_user_id() const;
+ inline utility::datetime unlockTime() const;
achievement_unlocked_notification_event_args(_In_ const XblAchievementUnlockEvent& achievementUnlockEvent);
diff --git a/Include/xsapi-cpp/xbox_live_context.h b/Include/xsapi-cpp/xbox_live_context.h
index fbd2bf90..f735b9e6 100644
--- a/Include/xsapi-cpp/xbox_live_context.h
+++ b/Include/xsapi-cpp/xbox_live_context.h
@@ -17,7 +17,9 @@
#include "xsapi-cpp/matchmaking.h"
#include "xsapi-cpp/user_statistics.h"
#include "xsapi-cpp/string_verify.h"
+#if XSAPI_NOTIFICATION_SERVICE
#include "xsapi-cpp/notification_service.h"
+#endif
NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN
@@ -45,6 +47,14 @@ class xbox_live_context
///
inline XblUserHandle user();
+ ///
+ /// Returns a copy of the associated Xbox Live context handle.
+ ///
+ ///
+ /// It is the caller's responsibility to close the returned handle.
+ ///
+ inline XblContextHandle handle();
+
///
/// Returns the current user's Xbox Live User ID.
///
@@ -126,7 +136,7 @@ class xbox_live_context
///
inline presence::presence_service presence_service();
-#if HC_PLATFORM == HC_PLATFORM_WIN32
+#if XSAPI_NOTIFICATION_SERVICE
///
/// A service for receiving notifications.
///
@@ -151,7 +161,9 @@ class xbox_live_context
private:
XblContextHandle m_handle = nullptr;
+#if XSAPI_NOTIFICATION_SERVICE
std::shared_ptr m_notificationService;
+#endif
};
NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END
diff --git a/Source/Services/Common/xbox_live_context.cpp b/Source/Services/Common/xbox_live_context.cpp
index 31b262fe..86e6602e 100644
--- a/Source/Services/Common/xbox_live_context.cpp
+++ b/Source/Services/Common/xbox_live_context.cpp
@@ -13,7 +13,9 @@
#include "xbox_live_app_config_internal.h"
#include "xbox_live_context_settings_internal.h"
#include "title_storage_internal.h"
+#if XSAPI_NOTIFICATION_SERVICE
#include "notification_internal.h"
+#endif
using namespace xbox::services;
using namespace xbox::services::system;
@@ -280,10 +282,12 @@ std::shared_ptr XblContext::PresenceService()
return m_presenceService;
}
+#if XSAPI_NOTIFICATION_SERVICE
std::shared_ptr XblContext::NotificationService()
{
return m_notificationService;
}
+#endif
std::shared_ptr XblContext::MultiplayerActivityService() noexcept
{
diff --git a/Source/Services/Common/xbox_live_context_internal.h b/Source/Services/Common/xbox_live_context_internal.h
index 4594cdaa..c82fa60d 100644
--- a/Source/Services/Common/xbox_live_context_internal.h
+++ b/Source/Services/Common/xbox_live_context_internal.h
@@ -18,7 +18,9 @@
#include "string_service_internal.h"
#include "social_internal.h"
#include "multiplayer_activity_internal.h"
+#if XSAPI_NOTIFICATION_SERVICE
#include "notification_internal.h"
+#endif
NAMESPACE_MICROSOFT_XBOX_SERVICES_MATCHMAKING_CPP_BEGIN
namespace legacy
@@ -100,10 +102,12 @@ struct XblContext : public std::enable_shared_from_this, public xbox
///
std::shared_ptr PresenceService();
+#if XSAPI_NOTIFICATION_SERVICE
///
/// A service used for delivering notifications.
///
std::shared_ptr NotificationService();
+#endif
///
/// A service for storing data in the cloud.
@@ -161,7 +165,7 @@ struct XblContext : public std::enable_shared_from_this, public xbox
std::shared_ptr m_notificationService;
#elif HC_PLATFORM == HC_PLATFORM_ANDROID || HC_PLATFORM == HC_PLATFORM_IOS
std::shared_ptr m_notificationService;
-#else
+#elif XSAPI_NOTIFICATION_SERVICE
std::shared_ptr m_notificationService;
#endif
diff --git a/Source/Services/Leaderboard/leaderboard_row.cpp b/Source/Services/Leaderboard/leaderboard_row.cpp
index 586ed68b..c30f9dbd 100644
--- a/Source/Services/Leaderboard/leaderboard_row.cpp
+++ b/Source/Services/Leaderboard/leaderboard_row.cpp
@@ -136,7 +136,10 @@ const xsapi_internal_vector& LeaderboardRow::ColumnValues
int rank = 0;
int globalRank = 0;
RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(json, "rank", rank, true));
- RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(json, "globalrank", globalRank, false));
+ if (json.IsObject() && json.HasMember("globalrank") && !json["globalrank"].IsNull())
+ {
+ RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(json, "globalrank", globalRank, false));
+ }
xsapi_internal_vector values;
if (json.IsObject() && json.HasMember("value") && !json["value"].IsNull())
{
diff --git a/Source/Services/MultiplayerActivity/multiplayer_activity_api.cpp b/Source/Services/MultiplayerActivity/multiplayer_activity_api.cpp
index 8ad6906b..6d47df35 100644
--- a/Source/Services/MultiplayerActivity/multiplayer_activity_api.cpp
+++ b/Source/Services/MultiplayerActivity/multiplayer_activity_api.cpp
@@ -4,10 +4,15 @@
#include "pch.h"
#include "xbox_live_context_internal.h"
#include "multiplayer_activity_internal.h"
+#if XSAPI_NOTIFICATION_SERVICE
#include "notification_internal.h"
+#endif
using namespace xbox::services::multiplayer_activity;
+
+#if XSAPI_NOTIFICATION_SERVICE
using namespace xbox::services::notification;
+#endif
STDAPI XblMultiplayerActivityUpdateRecentPlayers(
_In_ XblContextHandle xblContextHandle,
diff --git a/Source/Services/Notification/RTA/notification_subscription.cpp b/Source/Services/Notification/RTA/notification_subscription.cpp
index 1a4cffba..62124706 100644
--- a/Source/Services/Notification/RTA/notification_subscription.cpp
+++ b/Source/Services/Notification/RTA/notification_subscription.cpp
@@ -108,7 +108,7 @@ void NotificationSubscription::OnEvent(
}
else if (data.HasMember("KickNotification"))
{
- XalUserGetTokenAndSignatureArgs args;
+ XalUserGetTokenAndSignatureArgs args{};
args.forceRefresh = true;
args.url = "https://xboxlive.com/";
args.method = "GET";
diff --git a/Source/Services/RealTimeActivityManager/real_time_activity_connection.cpp b/Source/Services/RealTimeActivityManager/real_time_activity_connection.cpp
index 17336397..920fc8c4 100644
--- a/Source/Services/RealTimeActivityManager/real_time_activity_connection.cpp
+++ b/Source/Services/RealTimeActivityManager/real_time_activity_connection.cpp
@@ -620,8 +620,10 @@ void Connection::ConnectCompleteHandler(WebsocketResult result) noexcept
std::unique_lock lock{ sharedThis->m_lock };
if ((std::chrono::system_clock::now() - sharedThis->m_connectTime).count() >= CONNECTION_TIMEOUT_MS)
{
+ auto socket = sharedThis->m_websocket;
+ lock.unlock();
// Disconnect so that auto-reconnect logic kicks in
- sharedThis->m_websocket->Disconnect();
+ socket->Disconnect();
}
}
},
diff --git a/Tests/ApiExplorer/APIs/apis_xblc_leaderboard.cpp b/Tests/ApiExplorer/APIs/apis_xblc_leaderboard.cpp
index 948dd03c..3a94dc0a 100644
--- a/Tests/ApiExplorer/APIs/apis_xblc_leaderboard.cpp
+++ b/Tests/ApiExplorer/APIs/apis_xblc_leaderboard.cpp
@@ -96,6 +96,7 @@ int XblLeaderboardGetLeaderboardAsync_Lua(lua_State *L)
for (auto column = 0u; column < leaderboard->rows[row].columnValuesCount; ++column)
{
+ // Each column value is in JSON format
rowText << leaderboard->rows[row].columnValues[column] << "\t";
}
LogToFile(rowText.str().data()); // CODE SNIP SKIP
diff --git a/Tests/ApiExplorer/Shared/mem_hook.cpp b/Tests/ApiExplorer/Shared/mem_hook.cpp
index 35b892f5..2b44ae7b 100644
--- a/Tests/ApiExplorer/Shared/mem_hook.cpp
+++ b/Tests/ApiExplorer/Shared/mem_hook.cpp
@@ -5,7 +5,7 @@
#define TRACK_UNHOOKED_ALLOCS 1
-#if HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM == HC_PLATFORM_GDK
+#if HC_PLATFORM == HC_PLATFORM_WIN32 || (HC_PLATFORM == HC_PLATFORM_GDK && !_GAMING_XBOX)
#include
#include
#include
@@ -382,7 +382,7 @@ void ApiRunerMemHook::LogUnhookedStats()
bool ApiRunerMemHook::IsStackInXSAPI(StackInfo& stackInfo)
{
-#if HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM == HC_PLATFORM_GDK
+#if HC_PLATFORM == HC_PLATFORM_WIN32 || (HC_PLATFORM == HC_PLATFORM_GDK && !_GAMING_XBOX)
GetStackTrace(stackInfo);
bool foundInXsapi = false;
@@ -420,7 +420,7 @@ bool ApiRunerMemHook::IsStackInXSAPI(StackInfo& stackInfo)
void ApiRunerMemHook::GetStackTrace(StackInfo &stackInfo)
{
-#if HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM == HC_PLATFORM_GDK
+#if HC_PLATFORM == HC_PLATFORM_WIN32 || (HC_PLATFORM == HC_PLATFORM_GDK && !_GAMING_XBOX)
void* stack[TRACE_MAX_STACK_FRAMES] = { 0 };
WORD numberOfFrames = CaptureStackBackTrace(0, TRACE_MAX_STACK_FRAMES, stack, NULL);
stackInfo.stackSize = numberOfFrames < 64 ? numberOfFrames : 64;
@@ -459,7 +459,7 @@ void ApiRunerMemHook::GetStackTrace(StackInfo &stackInfo)
#endif
}
-#if HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM == HC_PLATFORM_GDK
+#if HC_PLATFORM == HC_PLATFORM_WIN32 || (HC_PLATFORM == HC_PLATFORM_GDK && !_GAMING_XBOX)
bool ApiRunerMemHook::IsStackFramesInsideTestCode(StackInfo* pStackInfo)
{
for (int i = 0; i < pStackInfo->stackSize; i++)