> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# XStoreQueryAssociatedProductsAsync

> XStoreQueryAssociatedProductsAsync

# XStoreQueryAssociatedProductsAsync

获取用户可以在当前游戏中购买的产品的应用商店列表信息。

## 语法

```cpp theme={null}
HRESULT XStoreQueryAssociatedProductsAsync(  
         const XStoreContextHandle storeContextHandle,  
         XStoreProductKind productKinds,  
         uint32_t maxItemsToRetrievePerPage,  
         XAsyncBlock* async  
)  
```

### 参数

*storeContextHandle*   \_In\_\
类型：XStoreContextHandle

由 [XStoreCreateContext](/zh-CN/reference/system/xstore/functions/xstorecreatecontext.md) 返回的用户的应用商店上下文句柄。

*productKinds*   \_In\_\
类型：[XStoreProductKind](/zh-CN/reference/system/xstore/enums/xstoreproductkind.md)

要返回的产品类型。

*maxItemsToRetrievePerPage*   \_In\_\
类型：uint32\_t

每页要检索的最大项数。
每页返回的项数可能从 0 到 `maxItemsToRetrievePerPage` 之间变化。
有关详细信息，请参阅[分页](#paging)。

*async*   \_Inout\_\
类型：[XAsyncBlock\*](/zh-CN/reference/system/xasync/structs/xasyncblock.md)

定义正在执行的异步工作的 [XAsyncBlock](/zh-CN/reference/system/xasync/structs/xasyncblock.md)。
使用 [XAsyncBlock](/zh-CN/reference/system/xasync/structs/xasyncblock.md) 轮询调用状态并检索调用结果。
有关详细信息，请参阅 [XAsyncBlock](/zh-CN/reference/system/xasync/structs/xasyncblock.md)。

### 返回值

类型：HRESULT

HRESULT 成功或错误代码。

## 备注

要获取应用商店列表信息和此函数的执行结果，请在调用此函数后调用 [XStoreQueryAssociatedProductsResult](/zh-CN/reference/system/xstore/functions/xstorequeryassociatedproductsresult.md)。
[XStoreQueryAssociatedProductsResult](/zh-CN/reference/system/xstore/functions/xstorequeryassociatedproductsresult.md) 包含一个可通过调用 [XStoreEnumerateProductsQuery](/zh-CN/reference/system/xstore/functions/xstoreenumerateproductsquery.md) 进行枚举的 `XStoreProductQueryHandle`。

你无法预先知道此查询返回的产品数量。

此 API 仅返回用户可以在 Microsoft Store 中浏览或在游戏中购买的产品。
结果不包括任何被隐藏、已过期或已从应用商店中移除的产品。
如果需要此类产品的详细信息，请使用 [XStoreQueryProductsAsync](/zh-CN/reference/system/xstore/functions/xstorequeryproductsasync.md) 并传入该产品的应用商店 ID。

## 分页

此函数跨多个页面返回产品（每页最多 `maxItemsToRetrievePerPage` 项）。
使用 [XStoreProductsQueryHasMorePages](/zh-CN/reference/system/xstore/functions/xstoreproductsqueryhasmorepages.md) 和 [XStoreProductsQueryNextPageAsync](/zh-CN/reference/system/xstore/functions/xstoreproductsquerynextpageasync.md)/[XStoreProductsQueryNextPageResult](/zh-CN/reference/system/xstore/functions/xstoreproductsquerynextpageresult.md) 来处理所有分页结果。
分页只有在 `XStoreProductsQueryHasMorePages` 返回 false 时才算完成。

> [!NOTE]
>
> 沙盒和 RETAIL 之间的分页行为可能有所不同。
> 在沙盒中，项会累积至 `maxItemsToRetrievePerPage`，然后才会返回一页。
> 在 RETAIL 中，通常每页返回 0-1 项。
>
> 对于使用此 API 的所有游戏，在发布前实现并测试分页功能非常重要。
>
> 要在沙盒中测试分页行为，请将 `maxItemsToRetrievePerPage` 暂时设置为小于发布到你的沙盒中的产品数量的值。
> 要在游戏发布前在 RETAIL 中进行测试，请使用 Partner Center 中"定价和可用性"页面上的**启用私有受众**选项来发布产品。
> 要在游戏发布后在 RETAIL 中进行测试，请使用包外部测试。

以下代码演示了如何跨多个页面检索产品查询结果。

请确保通过分页递归传递查询句柄，以避免泄漏。

```cpp theme={null}
struct QueryContext
{
    uint32_t count = 0;  // used to accumulate count of products returned across pages
    XStoreProductQueryHandle handle = nullptr;  // handle to reuse for paged operations
};

void CleanupProductQuery(XAsyncBlock* async)
{
    if (!async) return;

    auto* ctx = static_cast<QueryContext*>(async->context);
    if (ctx)
    {
        if (ctx->handle)
        {
            XStoreCloseProductsQueryHandle(ctx->handle);
            ctx->handle = nullptr;
        }

        delete ctx;
        async->context = nullptr;
    }

    delete async;
}

bool CALLBACK ProductEnumerationCallback(const XStoreProduct* product, void* context)
{
    // Use result of query
    auto* ctx = static_cast<QueryContext*>(context);

    // Empty results are possible and should be skipped
    if (product)
    {
        printf("%s %s %u\n", product->title, product->storeId, product->productKind);
        ctx->count++;
    }

    return true;
}

void CALLBACK QueryAssociatedProductsCallback(XAsyncBlock* async)
{
    auto* ctx = static_cast<QueryContext*>(async->context);

    HRESULT hr = XStoreQueryAssociatedProductsResult(async, &ctx->handle);
    if (FAILED(hr)) { CleanupProductQuery(async); return; }

    hr = XStoreEnumerateProductsQuery(ctx->handle, ctx, ProductEnumerationCallback);
    if (FAILED(hr)) { CleanupProductQuery(async); return; }

    // Check if there are more pages to process
    if (XStoreProductsQueryHasMorePages(ctx->handle))
    {
        QueryNextPage(async);
        return;
    }

    printf("Enumeration complete, %u products found\n", ctx->count);
    CleanupProductQuery(async);
}

void QueryAssociatedProducts(XStoreContextHandle storeContextHandle, XTaskQueueHandle taskQueueHandle)
{
    auto async = new XAsyncBlock{};
    async->context = new QueryContext{ 0, nullptr };
    async->queue = taskQueueHandle;
    async->callback = QueryAssociatedProductsCallback;

    XStoreProductKind typeFilter =
        XStoreProductKind::Consumable |
        XStoreProductKind::Durable |
        XStoreProductKind::Game |
        XStoreProductKind::Pass |
        XStoreProductKind::UnmanagedConsumable;

    HRESULT hr = XStoreQueryAssociatedProductsAsync(
        storeContextHandle,
        typeFilter,
        25,          // Products per page (25 is a good default, can set lower to verify paging in sandbox)
        async);

    if (FAILED(hr))
    {
        CleanupProductQuery(async);
    }
}

// In RETAIL, content will be returned across multiple pages.
// Paging is not complete until XStoreProductsQueryHasMorePages returns false.
void QueryNextPage(XAsyncBlock *async)
{
    async->callback = [](XAsyncBlock* async)
    {
        auto* ctx = static_cast<QueryContext*>(async->context);

        XStoreProductQueryHandle next = nullptr;
        HRESULT hr = XStoreProductsQueryNextPageResult(async, &next);
        if (FAILED(hr)) { CleanupProductQuery(async); return; }

        // Safe swap: avoids leaks if 'next' is a new handle, avoids double-close if identical
        if (next && next != ctx->handle)
        {
            if (ctx->handle) XStoreCloseProductsQueryHandle(ctx->handle);
            ctx->handle = next;
        }
        else
        {
            ctx->handle = next; // covers null or same-handle cases
        }

        hr = XStoreEnumerateProductsQuery(ctx->handle, ctx, ProductEnumerationCallback);
        if (FAILED(hr)) { CleanupProductQuery(async); return; }

        // Check if there are more pages to process
        if (XStoreProductsQueryHasMorePages(ctx->handle))
        {
            QueryNextPage(async);
            return;
        }

        printf("Enumeration complete, %u products found\n", ctx->count);
        CleanupProductQuery(async);
    };

    auto* ctx = static_cast<QueryContext*>(async->context);
    HRESULT hr = XStoreProductsQueryNextPageAsync(ctx->handle, async);
    if (FAILED(hr))
    {
        CleanupProductQuery(async);
    }
}

```

## 要求

**头文件：** XStore.h（包含于 XGameRuntime.h 中）

**库：** xgameruntime.lib

**支持的平台：** Windows、XBOX One 系列主机和 XBOX Series 主机

## 概念文档

* [在游戏中实现游戏内购买](https://learn.microsoft.com/gaming/gdk/docs/gdk-dev/pc-dev/tutorials/pc-e2e-guide/e2e-services/e2e-in-game-purchases)
* [基本应用商店操作](/zh-CN/publishing/xstore-commerce/xstore-basic-operations.md)
* [向玩家授予附加内容的访问权限](/zh-CN/publishing/xstore-commerce/xstore-granting-access.md)
* [GDK 商务系统概述](/zh-CN/publishing/xstore-commerce/xstore-overview.md)
* [Microsoft Store API 的细粒度速率限制](/zh-CN/publishing/xstore-commerce/xstore-fgrl.md)
* [应用商店开发权益工具 (DevEntitlementTool.exe)](/zh-CN/tools/tools-services/live-dev-entitlements-tool.md)

## 另请参阅

[XStore](/zh-CN/reference/system/xstore/xstore_members.md)\
[XStoreQueryAssociatedProductsResult](/zh-CN/reference/system/xstore/functions/xstorequeryassociatedproductsresult.md)\
[XStoreEnumerateProductsQuery](/zh-CN/reference/system/xstore/functions/xstoreenumerateproductsquery.md)\
[XStoreProductsQueryHasMorePages](/zh-CN/reference/system/xstore/functions/xstoreproductsqueryhasmorepages.md)\
[XStoreProductsQueryNextPageAsync](/zh-CN/reference/system/xstore/functions/xstoreproductsquerynextpageasync.md)\
[基本应用商店操作](/zh-CN/publishing/xstore-commerce/xstore-basic-operations.md)\
[向玩家授予附加内容的访问权限](/zh-CN/publishing/xstore-commerce/xstore-granting-access.md)


## Related topics

- [XStoreQueryAssociatedProductsResult](/zh-CN/reference/system/xstore/functions/xstorequeryassociatedproductsresult.md)
- [XStoreQueryProductForPackageAsync](/zh-CN/reference/system/xstore/functions/xstorequeryproductforpackageasync.md)
- [XStoreQueryProductsAsync](/zh-CN/reference/system/xstore/functions/xstorequeryproductsasync.md)
- [XStoreProductQueryCallback](/zh-CN/reference/system/xstore/functions/xstoreproductquerycallback.md)
- [XStoreEnumerateProductsQuery](/zh-CN/reference/system/xstore/functions/xstoreenumerateproductsquery.md)
