> ## 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](/ko/reference/system/xstore/functions/xstorecreatecontext.md)가 반환한 사용자의 스토어 컨텍스트 핸들입니다.

*productKinds*   \_In\_\
형식: [XStoreProductKind](/ko/reference/system/xstore/enums/xstoreproductkind.md)

반환할 제품의 유형입니다.

*maxItemsToRetrievePerPage*   \_In\_\
형식: uint32\_t

페이지당 검색할 최대 항목 수입니다.
페이지당 반환되는 항목 수는 0에서 `maxItemsToRetrievePerPage`까지 다양할 수 있습니다.
자세한 내용은 [페이징](#paging)을 참조하세요.

*async*   \_Inout\_\
형식: [XAsyncBlock\*](/ko/reference/system/xasync/structs/xasyncblock.md)

수행 중인 비동기 작업을 정의하는 [XAsyncBlock](/ko/reference/system/xasync/structs/xasyncblock.md)입니다.
[XAsyncBlock](/ko/reference/system/xasync/structs/xasyncblock.md)을 사용하여 호출의 상태를 폴링하고 호출 결과를 검색합니다.
자세한 내용은 [XAsyncBlock](/ko/reference/system/xasync/structs/xasyncblock.md)을 참조하세요.

### 반환 값

형식: HRESULT

HRESULT 성공 또는 오류 코드입니다.

## 설명

이 함수의 스토어 목록 정보와 실행 결과를 얻으려면 이 함수를 호출한 후 [XStoreQueryAssociatedProductsResult](/ko/reference/system/xstore/functions/xstorequeryassociatedproductsresult.md)를 호출합니다.
[XStoreQueryAssociatedProductsResult](/ko/reference/system/xstore/functions/xstorequeryassociatedproductsresult.md)에는 [XStoreEnumerateProductsQuery](/ko/reference/system/xstore/functions/xstoreenumerateproductsquery.md)를 호출하여 열거하는 `XStoreProductQueryHandle`이 포함되어 있습니다.

이 쿼리에서 반환하는 제품 수를 미리 알 수는 없습니다.

이 API는 사용자가 Microsoft Store에서 검색하거나 게임 내에서 구매할 수 있는 제품만 반환합니다.
결과에는 스토어에서 숨겨져 있거나 만료되거나 제거된 제품은 포함되지 않습니다.
이러한 제품의 세부 정보가 필요한 경우 [XStoreQueryProductsAsync](/ko/reference/system/xstore/functions/xstorequeryproductsasync.md)를 사용하고 제품의 스토어 ID를 전달합니다.

## 페이징

이 함수는 여러 페이지에 걸쳐 제품을 반환합니다(단일 페이지에 최대 `maxItemsToRetrievePerPage` 항목).
[XStoreProductsQueryHasMorePages](/ko/reference/system/xstore/functions/xstoreproductsqueryhasmorepages.md)와 [XStoreProductsQueryNextPageAsync](/ko/reference/system/xstore/functions/xstoreproductsquerynextpageasync.md)/[XStoreProductsQueryNextPageResult](/ko/reference/system/xstore/functions/xstoreproductsquerynextpageresult.md)를 사용하여 페이징된 모든 결과를 처리합니다.
페이징은 `XStoreProductsQueryHasMorePages`가 false를 반환할 때까지 완료되지 않습니다.

> [!NOTE]
>
> 페이징은 샌드박스와 RETAIL 간에 다르게 동작할 수 있습니다.
> 샌드박스에서는 페이지가 반환되기 전에 항목이 `maxItemsToRetrievePerPage`까지 누적됩니다.
> RETAIL에서는 페이지당 0-1개의 항목이 반환되는 것이 일반적입니다.
>
> 이 API를 사용하는 모든 게임은 릴리스 전에 페이징을 구현하고 테스트하는 것이 중요합니다.
>
> 샌드박스에서 페이징 동작을 테스트하려면 `maxItemsToRetrievePerPage`를 샌드박스에 게시된 제품 수보다 작은 값으로 일시적으로 설정합니다.
> 게임 릴리스 전에 RETAIL에서 테스트하려면 파트너 센터의 '가격 및 가용성' 페이지에서 **비공개 대상 그룹 사용** 옵션을 사용하여 제품을 게시합니다.
> 게임 릴리스 후 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 콘솔

## 개념 설명서

* [Implement in-game purchases in your game](https://learn.microsoft.com/gaming/gdk/docs/gdk-dev/pc-dev/tutorials/pc-e2e-guide/e2e-services/e2e-in-game-purchases)
* [Basic store operations](/ko/publishing/xstore-commerce/xstore-basic-operations.md)
* [Granting players access to add-on content](/ko/publishing/xstore-commerce/xstore-granting-access.md)
* [GDK Commerce Systems Overview](/ko/publishing/xstore-commerce/xstore-overview.md)
* [Fine Grained Rate Limiting for Microsoft Store APIs](/ko/publishing/xstore-commerce/xstore-fgrl.md)
* [Store Development Entitlements Tool (DevEntitlementTool.exe)](/ko/tools/tools-services/live-dev-entitlements-tool.md)

## 참고 항목

[XStore](/ko/reference/system/xstore/xstore_members.md)\
[XStoreQueryAssociatedProductsResult](/ko/reference/system/xstore/functions/xstorequeryassociatedproductsresult.md)\
[XStoreEnumerateProductsQuery](/ko/reference/system/xstore/functions/xstoreenumerateproductsquery.md)\
[XStoreProductsQueryHasMorePages](/ko/reference/system/xstore/functions/xstoreproductsqueryhasmorepages.md)\
[XStoreProductsQueryNextPageAsync](/ko/reference/system/xstore/functions/xstoreproductsquerynextpageasync.md)\
[Basic store operations](/ko/publishing/xstore-commerce/xstore-basic-operations.md)\
[Granting players access to add-on content](/ko/publishing/xstore-commerce/xstore-granting-access.md)


## Related topics

- [XStoreQueryAssociatedProductsResult](/ko/reference/system/xstore/functions/xstorequeryassociatedproductsresult.md)
- [XStoreQueryAssociatedProductsForStoreIdAsync](/ko/reference/system/xstore/functions/xstorequeryassociatedproductsforstoreidasync.md)
- [XStoreQueryProductForPackageAsync](/ko/reference/system/xstore/functions/xstorequeryproductforpackageasync.md)
- [XStoreQueryProductsAsync](/ko/reference/system/xstore/functions/xstorequeryproductsasync.md)
- [XStoreProductQueryCallback](/ko/reference/system/xstore/functions/xstoreproductquerycallback.md)
