XStoreQueryAssociatedProductsForStoreIdAsync

Gets store listing information for the products that can be purchased from the product specified by the Store ID.

Syntax

HRESULT XStoreQueryAssociatedProductsForStoreIdAsync(   
         const XStoreContextHandle storeContextHandle,   
         const char* storeId, 
         XStoreProductKind productKinds,   
         uint32_t maxItemsToRetrievePerPage,   
         XAsyncBlock* async   
)   

Parameters

storeContextHandle   _In_
Type: XStoreContextHandle

The store context handle for the user returned by XStoreCreateContext.

storeId   _In_
Type: const char*

The ID for the product for which the associated products are retrieved.

productKinds   _In_
Type: XStoreProductKind

The type of products to return.

maxItemsToRetrievePerPage   _In_
Type: uint32_t

The maximum number of items to retrieve per page. Passing more than 25 items per page will result in multiple service round trips being required for each page.

async   _Inout_
Type: XAsyncBlock*

An XAsyncBlock defining the asynchronous work being done. The XAsyncBlock can be used to poll for the call's status and retrieve call results. See XAsyncBlock for more information.

Return value

Type: HRESULT

HRESULT success or error code.

Remarks

To retrieve the store listing information as well as the execution result of this function call XStoreQueryAssociatedProductsForStoreIdResult after calling this function. XStoreQueryAssociatedProductsForStoreIdResult contains a XStoreProductQueryHandle that will be enumerated by calling XStoreEnumerateProductsQuery.

Important

A product query may be returned over multiple pages even if the number of results are less than maxItemsToRetrievePerPage. You must check for additional product entries and read it by calling XStoreProductsQueryHasMorePages and XStoreProductsQueryNextPageAsync respectively.

There is no way to know the number of products that will be returned by this query upfront.

The API can be used to find out the add-ons that are associated with a product with a specific Store ID. This is especially useful for franchise game hubs because a franchise game hub can enumerate the add-ons for multiple games, but it cannot tell which main game these add-ons are associated with.

Usage scenarios examples:

  • Developers run XPackageEnumeratePackages to enumerate the XPackageKind::Game products, then for one of these games, they run XStoreQueryAssociatedProductsForStoreIdAsync using the storeId obtained from the XPackageDetails. Developers run XPackageEnumeratePackages for XPackageKind::Content and the results from this and from XStoreQueryAssociatedProductsForStoreIdAsync are cross-referenced so that the developer now knows which are the add-ons installed for the specific game.

  • Developers run XStoreQueryAssociatedProductsAsync, they get the whole list of products associated with the current game, then using the Store ID from XStoreProduct for a specific game, they can run XStoreQueryAssociatedProductsForStoreIdAsync and find out which are the DLCs associated with it.

The following code snippet shows an example of querying the associated products of a specific product given by its Store ID:

bool CALLBACK EnumerateProductsQueryCallback(const XStoreProduct* product, void* context) 
{ 
    printf("Product:\r\n"); 
    printf("\tstoreId    : %s\r\n", product->storeId); 
    printf("\tproductKind: %s\r\n", product->productKind); 
 
    // Return true to keep enumerating, false to stop 
    return true; 
} 
 
void ProcessResults(XStoreProductQueryHandle queryHandle, XTaskQueueHandle taskQueueHandle) 
{ 
    HRESULT hr = XStoreEnumerateProductsQuery( 
        queryHandle, 
        nullptr, 
        EnumerateProductsQueryCallback); 
 
    if (FAILED(hr)) 
    { 
        printf("Failed enumerate the product query handle: 0x%x\r\n", hr); 
        XStoreCloseProductsQueryHandle(queryHandle); 
        return; 
    } 
 
    bool hasMorePages = XStoreProductsQueryHasMorePages(queryHandle); 
    if (hasMorePages) 
    { 
        auto asyncInner = std::make_unique<XAsyncBlock>(); 
        ZeroMemory(asyncInner.get(), sizeof(*asyncInner)); 
        asyncInner->queue = taskQueueHandle; 
        asyncInner->callback = ProductsQueryNextPageCallback; 
 
        hr = XStoreProductsQueryNextPageAsync( 
            queryHandle, 
            asyncInner.get()); 
 
        if (FAILED(hr)) 
        { 
            printf("Failed to get next page of products: 0x%x\r\n", hr); 
            XStoreCloseProductsQueryHandle(queryHandle); 
            return; 
        } 
    } 
 
    XStoreCloseProductsQueryHandle(queryHandle); 
} 
 
void CALLBACK QueryAssociatedProductsCallback(XAsyncBlock* asyncBlock) 
{ 
    XStoreProductQueryHandle queryHandle = nullptr; 
 
    HRESULT hr = XStoreQueryAssociatedProductsForStoreIdResult( 
        asyncBlock, 
        &queryHandle); 
 
    if (FAILED(hr)) 
    { 
        printf("Failed to retrieve the product query handle: 0x%x\r\n", hr); 
        return; 
    } 
 
    XTaskQueueHandle taskQueueHandle = reinterpret_cast<XTaskQueueHandle>(asyncBlock->context); 
    ProcessResults(queryHandle, taskQueueHandle); 
} 
 
void CALLBACK ProductsQueryNextPageCallback(XAsyncBlock* asyncBlock) 
{ 
    XStoreProductQueryHandle queryHandle = nullptr; 
 
    HRESULT hr = XStoreProductsQueryNextPageResult( 
        asyncBlock, 
        &queryHandle); 
 
    if (FAILED(hr)) 
    { 
        printf("Failed to retrieve the product query handle: 0x%x\r\n", hr); 
        return; 
    } 
 
    XTaskQueueHandle taskQueueHandle = reinterpret_cast<XTaskQueueHandle>(asyncBlock->context); 
    ProcessResults(queryHandle, taskQueueHandle); 
} 
 
void QueryAssociatedProductsForStoreId(XStoreContextHandle storeContextHandle, XTaskQueueHandle taskQueueHandle, char* storeId) 
{ 
    auto asyncBlock = std::make_unique<XAsyncBlock>(); 
    ZeroMemory(asyncBlock.get(), sizeof(*asyncBlock)); 
    asyncBlock->queue = taskQueueHandle; 
    asyncBlock->context = taskQueueHandle; 
    asyncBlock->callback = QueryAssociatedProductsCallback; 
 
    XStoreProductKind allProductKinds = 
        XStoreProductKind::Consumable | 
        XStoreProductKind::Durable | 
        XStoreProductKind::Game | 
        XStoreProductKind::Pass | 
        XStoreProductKind::UnmanagedConsumable; 
 
    HRESULT hr = XStoreQueryAssociatedProductsForStoreIdAsync( 
        storeContextHandle, 

        storeId, 
        allProductKinds, 
        25,     // Max items per page 
        asyncBlock.get()); 
 
    if (FAILED(hr)) 
    { 
        printf("Failed to get associated products for %s: 0x%x\r\n", storeId, hr); 
        return; 
    } 
    
    if(FAILED(XAsyncGetStatus(asyncBlock, true))) 
    { 
        printf("XStoreQueryAssociatedProductsForStoreIdAsync failed for %s\r\n", storeId); 
        return; 
    } 
} 

Requirements

Header: XStore.h (included in XGameRuntime.h)

Library: xgameruntime.lib

Supported platforms: Windows, Xbox One family consoles and Xbox Series consoles

See also

XStore
XStoreQueryAssociatedProductsForStoreIdResult
XStoreEnumerateProductsQuery
XStoreProductsQueryHasMorePages
XStoreProductsQueryNextPageAsync