> ## 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.

# Administración y licencias de contenido descargable (DLC)

> Use productos duraderos como contenido descargable (DLC) en su título: configuración en Partner Center, comprobaciones de licencias, administración de la instalación y código de derechos en tiempo de ejecución.

El contenido descargable (DLC) consiste en un producto que, al comprarse, proporciona al usuario un paquete descargable. Los DLC deben licenciarse y montarse de forma independiente antes de que se pueda acceder a su contenido.

Los paquetes de DLC se pueden licenciar según el comportamiento de uso compartido de contenido de cada dispositivo, como se describe en el [Modelo de uso compartido de productos para juegos](/publishing/xstore-commerce/xstore-product-sharing).

Partner Center también admite productos duraderos que no tienen paquetes. Un producto duradero sin paquete es adecuado para productos de solo licencia, que habilitan contenido ya instalado con el juego base. Estos tipos de productos de solo licencia ahorran los pasos de crear paquetes vacíos que, de otro modo, los usuarios tendrían que descargar. Para obtener más información, consulte [Cómo usar un producto duradero sin paquete](/publishing/xstore-commerce/xstore-dwob).

## Flujo de trabajo de desarrollo para DLC

Consulte la documentación de paquetes de contenido descargable (DLC) para obtener más información sobre cómo configurar el contenido DLC, incluido cómo establecer la asociación con el juego base mediante el archivo MicrosoftGame.config.

Hay tres maneras de instalar un DLC:

1. [Implementación de DLC suelto](#1-loose-dlc-deployment)
2. [Instalación local del paquete de DLC](#2-locally-install-dlc-package)
3. [Instalación del paquete de DLC desde la Store](#3-install-dlc-package-from-store)

### 1. Implementación de DLC suelto

Instale el directorio que apunta al archivo MicrosoftGame.config y a los archivos de recursos del DLC suelto:

**XBOX:**

```cmd theme={null}
> xbapp deploy <DLC directory>

Package Full Name: 41336MicrosoftATG.DLC1_2020.10.14.0_neutral__dspnxghe87tn0
The operation completed successfully.
```

**PC:**

```cmd theme={null}
> wdapp register <DLC directory>  

Registered 41336MicrosoftATG.DLC1_2020.10.14.0_x64__dspnxghe87tn0
Copied temporary generated AppXManifest.xml file to C:\Users\<ntuser>\AppData\Local\Temp\41336MicrosoftATG.DLC1_2020.10.14.0_x64__dspnxghe87tn0_AppXManifest.xml
The operation completed successfully.
```

### 2. Instalación local del paquete de DLC

Instale el archivo .xvc/.msixvc creado por makepkg:

**XBOX:**

```cmd theme={null}
> xbapp install <xvc package>  

12:16:21.800 Registered for streaming: 41336MicrosoftATG.DLC1_2020.10.14.0_neutral__dspnxghe87tn0_xs.xvc
12:16:22.645 Launch   0.00% Package   0.00%
12:16:32.650 Launch 100.00% Package 100.00%
12:16:32.651 Streaming install finished

The operation completed successfully.
```

**PC:**

```cmd theme={null}
> wdapp install <.msixvc package>  

Starting installation. See the Microsoft Store app for further details.
Launch   100% Package   100%
Installed 100%.
Installed 41336MicrosoftATG.DLC1_2020.10.14.0_x64__dspnxghe87tn0
```

### 3. Instalación del paquete de DLC desde la Store

Con una cuenta de prueba con la sesión iniciada en el sandbox de desarrollo, busque la página del producto de DLC en la aplicación Store, o acceda a ella mediante un vínculo directo, e instálelo.

## Validación de la instalación del DLC

**XBOX:**

```cmd theme={null}
> xbapp listdlc

Registered DLC by Package Full Name:

   41336MicrosoftATG.DLC1_2020.10.14.0_neutral__dspnxghe87tn0

The operation completed successfully.
```

**PC:**

```cmd theme={null}
> wdapp listdlc

Registered DLC packages by Package Full Name:

41336MicrosoftATG.DLC1_2020.10.14.0_x64__dspnxghe87tn0

The operation completed successfully.
```

En PC, también es posible ver el DLC instalado para un título determinado mediante `get-appxpackage` en PowerShell; observe la sección **Dependencies**:

```cmd theme={null}
> get-appxpackage 41336MicrosoftATG.DownloadableContent

Name              : 41336MicrosoftATG.DownloadableContent
Publisher         : CN=A4954634-DF4B-47C7-AB70-D3215D246AF1
Architecture      : X64
ResourceId        :
Version           : 2020.10.14.0
PackageFullName   : 41336MicrosoftATG.DownloadableContent_2020.10.14.0_x64__dspnxghe87tn0
InstallLocation   : E:\Repos\ATG\gx_dev\Samples\Live\DownloadableContent\Gaming.Desktop.x64\Debug
IsFramework       : False
PackageFamilyName : 41336MicrosoftATG.DownloadableContent_dspnxghe87tn0
PublisherId       : dspnxghe87tn0
IsResourcePackage : False
IsBundle          : False
IsDevelopmentMode : True
NonRemovable      : False
Dependencies      : {41336MicrosoftATG.DLC1_2020.10.14.0_x64__dspnxghe87tn0}
IsPartiallyStaged : False
SignatureKind     : None
Status            : Ok
```

**SignatureKind** indica qué tipo de paquete está instalado: *None* para un paquete compilado e instalado localmente, *Store* para un paquete instalado desde la Store.

## Compra e instalación de DLC

Consulte el artículo [Operaciones básicas de la Store](/publishing/xstore-commerce/xstore-basic-operations) para comprender cómo enumerar el catálogo y ofrecer la posibilidad de comprar complementos. Se puede determinar que los productos de complemento son DLC examinando `[XStoreProduct](/reference/system/xstore/xstore_members).hasDigitalDownload`.

Si un DLC se compra desde la Store, el DLC se pone en cola para descargarse.

Si un DLC se compra mediante [XStoreShowPurchaseUiAsync](/reference/system/xstore/xstore_members), el DLC no se pone en cola para la descarga. En su lugar, el juego debe solicitar la descarga manualmente siguiendo el código. De forma opcional, se puede crear un monitor para hacer el seguimiento del progreso.

El **identificador de paquete** es una cadena opaca que identifica un paquete específico. El identificador es único por paquete, pero distinto en cada instancia iniciada del juego. Por lo tanto, no almacene ni reutilice el identificador más allá de la sesión actual.

Puede usar los métodos siguientes para obtener el identificador de paquete de un paquete, según el escenario:

* Después de llamar a [XStoreDownloadAndInstallPackagesAsync](/reference/system/xstore/xstore_members) para descargar e instalar paquetes, puede obtener los identificadores de paquete de esos paquetes llamando a [XStoreDownloadAndInstallPackagesResult](/reference/system/xstore/xstore_members).
* Puede obtener los identificadores de paquete de los paquetes ya descargados e instalados llamando a [XPackageEnumeratePackages](/reference/system/xstore/xstore_members) y, a continuación, recuperando el identificador de paquete de la estructura [XPackageDetails](/reference/system/xstore/xstore_members) que se devuelve a la función de devolución de llamada [XPackageEnumerationCallback](/reference/system/xstore/xstore_members) para cada paquete enumerado.
* Puede obtener el identificador de paquete del juego actual llamando a [XPackageGetCurrentProcessPackageIdentifier](/reference/system/xstore/xstore_members).

```cpp theme={null}
void StartDownload()
{
    auto async = new XAsyncBlock{};
    async->queue = m_asyncQueue;
    async->context = this;
    async->callback = [](XAsyncBlock* asyncBlockInner)
    {
        uint32_t count = 0;
        HRESULT hr = XStoreDownloadAndInstallPackagesResultCount(asyncBlockInner, &count);

        std::vector<char[XPACKAGE_IDENTIFIER_MAX_LENGTH]> packageIds(count);

        XStoreDownloadAndInstallPackagesResult(asyncBlockInner, count, packageIds.data());

        for(auto packageId : packageIds)
        {
            hr = XPackageCreateInstallationMonitor(
                packageId,  
                0,  
                nullptr,  
                1000,  
                m_asyncQueue,
                &m_pimHandle);

            if(SUCCEEDED(hr))
            {
                XTaskQueueRegistrationToken callbackToken;

                XPackageRegisterInstallationProgressChanged(
                    m_pimHandle,
                    this,
                    [](void* context, XPackageInstallationMonitorHandle pimHandle)
                    {
                        XPackageInstallationProgress progress;
                        XPackageGetInstallationProgress(pimHandle, &progress);

                        if(!progress.completed)
                        {
                            printf("%llu%% installed\n", static_cast<double>(progress.installedBytes) / static_cast<double>(progress.totalBytes);
                        }
                        else
                        {
                            XPackageCloseInstallationMonitorHandle(pimHandle);
                        }
                    }, &callbackToken);

                // Persist callbackToken to unregister upon completion
            }
        }

        delete asyncBlockInner;
    }

    const char* storeIds[] =  
    {
        "9PLNMXRKNM4C",  
        "9PLNMXRKNM5D"
    };

    HRESULT hr = XStoreDownloadAndInstallPackagesAsync(storeContext, storeIds, ARRAYSIZE(storeIds), async);

    if (FAILED(hr))
    {
        delete async;
        return;
    }
}
```

## Enumeración de paquetes de DLC

Independientemente de cómo se instalen los DLC, el juego necesita enumerar los DLC instalados antes de usarlos. La enumeración de los DLC instalados es donde se obtiene el identificador de paquete.

```cpp theme={null}
bool CALLBACK DlcCallback(void* context, const XPackageDetails* details)
{
    printf("DLC found: name: %s packageId: %s\n", details->displayName, details->packageIdentifier);

    return true;
}

void RefreshInstalledPackages()
{
    HRESULT hr = XPackageEnumeratePackages(
        XPackageKind::Content,  
        XPackageEnumerationScope::ThisAndRelated,  
        this,  
        DlcCallback);
}
```

## Detección de que un paquete de DLC está instalado

```cpp theme={null}
void RegisterPackageInstalledEvent()
{
    XPackageRegisterPackageInstalled(
        m_asyncQueue,
        this,  
        [](void *context, const XPackageDetails *package)
        {
            printf("Package Installed event received: %s\n", package->displayName);
        },  
        &m_packageInstallToken);
}
```

Consulte la sección [Solución de problemas](/publishing/xstore-commerce/xstore-troubleshooting) si no se llega al ejemplo de código. El evento debe desencadenarse independientemente del método con el que se instale el paquete de DLC.

## Adquisición de la licencia para el DLC

En desarrollo, consulte las notas en [Prueba de licencias de DLC en desarrollo](#testing-dlc-licensing-in-development).

El juego base necesita adquirir la licencia del DLC para determinar si debe dar al usuario acceso a su contenido.

Los juegos suelen usar licencias restrictivas, en las que, después de que el juego adquiere la licencia de un paquete, el acceso al paquete queda bloqueado para ese dispositivo y esa instancia del producto. El juego debe liberar la licencia antes de que otra instancia o dispositivo pueda adquirir los derechos de acceso y la licencia. Hable con su representante de cuenta de Microsoft para asegurarse de que su juego esté configurado para usar licencias restrictivas (no se configura en Partner Center). Para obtener más información, consulte [Licencias abiertas y restrictivas](/publishing/xstore-commerce/xstore-open-restrictive-licensing).

Dado que el juego debe liberar la licencia, el juego es responsable de hacer el seguimiento de todas las licencias de DLC que adquiere y de liberarlas cuando ya no se necesiten o al finalizar. Si el juego no libera una licencia, la licencia se libera automáticamente después de un período de tiempo de espera.

```cpp theme={null}
void CALLBACK AcquireLicenseForPackageCallback(XAsyncBlock* async)
{
    XStoreLicenseHandle licenseHandle = nullptr;

    HRESULT hr = XStoreAcquireLicenseForPackageResult(
        async,
        &licenseHandle);

    if (FAILED(hr))
    {
        printf("Failed retrieve the license handle: 0x%x\n", hr);
        return;
    }

    bool isValid = XStoreIsLicenseValid(licenseHandle);

    printf("isValid: %s\n", isValid ? "true" : "false");

    hr = XStoreRegisterPackageLicenseLost(licenseHandle, m_asyncQueue, context,
       [](void *context)  
       {
           // Check if the license lost corresponded to any mounted DLC
           // If so, it is up to the game to determine an appropriate time
           // to unmount the DLC, e.g. after the current match is completed
       });

    delete async;
}

void AcquireLicenseForPackage(const char* packageIdentifier)
{
    auto async = new XAsyncBlock{};
    async->context = this;
    async->queue = m_asyncQueue;
    async->callback = AcquireLicenseForPackageCallback;

    HRESULT hr = XStoreAcquireLicenseForPackageAsync(
        m_storeContext,
        packageIdentifier,
        async);

    if (FAILED(hr))
    {
        delete async;
        return;
    }
}
```

## Determinación del origen de la licencia del DLC

Mediante [XStoreCanAcquireLicenseForPackageAsync](/reference/system/xstore/xstore_members) o [XStoreCanAcquireLicenseForStoreIdAsync](/reference/system/xstore/xstore_members) (según el tipo de identificador), es posible determinar si el DLC es

1. Licenciable, para poder presentar opciones de compra en caso contrario
2. Licenciable por disco o por licencia digital

```cpp theme={null}
void PreviewLicense(const char* storeId)
{
    auto async = new XAsyncBlock{};
    async->queue = m_asyncQueue;
    async->callback = [](XAsyncBlock* async)
    {
        XStoreCanAcquireLicenseResult result;

        HRESULT hr = XStoreCanAcquireLicenseForStoreIdResult(
            async,
            &result);

        if (FAILED(hr))
        {
            printf("Error calling XStoreCanAcquireLicenseForStoreIdResult: 0x%x\n", hr);
        }
        else
        {
            // Status = 1 Licensable and
            // a. licensableSku = "DISC" if disc licensed
            // b. licensableSku = "0010" or similar if digital licensed
            printf("Status: %u LicensableSku: %s\n", result.status, result.licensableSku);
        }

        delete async;
    };

    HRESULT hr = XStoreCanAcquireLicenseForStoreIdAsync(
        m_xStoreContext,
        storeId,
        async);

    if (FAILED(hr))
    {
        delete async;

        printf("Error calling XStoreCanAcquireLicenseForStoreIdAsync: 0x%x", hr);
        return;
    }
}
```

## Montaje y desmontaje del DLC

Una vez que la licencia del DLC se adquiere correctamente, el contenido del DLC se puede montar y se puede acceder a él.

```cpp theme={null}

void CALLBACK MountPackageCallback(XAsyncBlock* async)
{
    XPackageMountHandle mountHandle = {};

    HRESULT hr = XPackageMountWithUiResult(async, &mountHandle);

    if (SUCCEEDED(hr))
    {
        // Access DLC goodness
    }
    else
    {
        XStoreCloseLicenseHandle(license);
        printf("Error mounting package: 0x%x\n", hr);
    }

    delete async;
};

void MountPackage(const char* packageIdentifier)
{
    auto async = new XAsyncBlock{};
    async->queue = m_asyncQueue;
    async->context = context;
    async->callback = MountPackageCallback;

    HRESULT hr = XPackageMountWithUiAsync(packageIdentifier, async);

    if (FAILED(hr))
    {
        printf("XPackageMountWithUiAsync failed : 0x%x\n", hr);
        delete async;
    }
}
```

Al desmontar, libere todos los tokens e identificadores:

```cpp theme={null}
void UnmountPackage(XPackageMountHandle mountHandle, XStoreLicenseHandle license, XTaskQueueRegistrationToken licenseLostToken)
{
    XStoreUnregisterPackageLicenseLost(license, licenseLostToken, false);

    XPackageCloseMountHandle(mountHandle);

    XStoreCloseLicenseHandle(license);
}
```

## Desinstalación del DLC

Use [XPackageUninstallPackage](/reference/system/xstore/xstore_members) para desinstalar un paquete de DLC. El paquete debe desmontarse primero.

## Smart Delivery y DLC

Es posible que los títulos de XBOX Series X/S licencien y monten DLC creado para el título de XBOX One. Normalmente, este escenario se produce cuando el paquete de DLC no contiene datos que use el juego. La única manera de comprobarlo es si el identificador `AllowedProduct` del DLC de ERA en su package.appxmanifest, que es un GUID, coincide con el Product ID de XBOX heredado asignado al producto en Partner Center.

Si no es así, es posible que el título se haya migrado desde el XBOX Developer Portal (XDP) ya retirado, y solo funcione con paquetes descargados de la Store, dado que la versión de XBOX Series X/S está asignada al Product ID de XBOX One. Para fines de desarrollo, consulte la nota en la sección [Solución de problemas](/publishing/xstore-commerce/xstore-troubleshooting).

## DLC de productos diferentes

Es posible enumerar y usar DLC de un producto diferente. Para el título que desea usar un DLC de otro producto, asigne una relación de tipo "Can sell and use" al producto de DLC en la sección **Product relationship setup** de Partner Center. La selección de productos disponibles se limita a la cuenta del publicador.

## Prueba de licencias de DLC en desarrollo

Para obtener más información, consulte [Habilitación de las pruebas de licencias](/publishing/xstore-commerce/xstore-licensing-setup).

Los paquetes de DLC locales deben crearse con un parámetro /contentid.

Cada paquete de DLC debe tener su EKBID sustituido con respecto a los valores predeterminados.

## Documentación de referencia de la API

* [XStore (contenido de la API)](/reference/system/xstore/xstore_members)
  * Funciones
    * [XStoreShowPurchaseUiAsync](/reference/system/xstore/xstore_members)
    * [XStoreDownloadAndInstallPackagesAsync](/reference/system/xstore/xstore_members)
    * [XStoreDownloadAndInstallPackagesResult](/reference/system/xstore/xstore_members)
    * [XStoreCanAcquireLicenseForPackageAsync](/reference/system/xstore/xstore_members)
    * [XStoreCanAcquireLicenseForStoreIdAsync](/reference/system/xstore/xstore_members)
  * Estructuras
    * [xstoreproduct](/reference/system/xstore/xstore_members)
* [XPackage (contenido de la API)](/reference/system/xstore/xstore_members)
  * Funciones
    * [XPackageEnumeratePackages](/reference/system/xstore/xstore_members)
    * [XPackageEnumerationCallback](/reference/system/xstore/xstore_members)
    * [XPackageGetCurrentProcessPackageIdentifier](/reference/system/xstore/xstore_members)
    * [XPackageUninstallPackage](/reference/system/xstore/xstore_members)
  * Estructuras
    * [XPackageDetails](/reference/system/xstore/xstore_members)

## Consulte también

[Información general sobre comercio](/publishing/xstore-commerce/xstore-commerce-overview)

[Habilitación de las pruebas de licencias](/publishing/xstore-commerce/xstore-licensing-setup)

[Cómo usar un producto duradero sin paquete](/publishing/xstore-commerce/xstore-dwob)

[Referencia de la API XStore](/reference/system/xstore/xstore_members)


## Related topics

- [Habilitación de las pruebas de licencias](/es/publishing/xstore-commerce/xstore-licensing-setup.md)
- [XPackageDetails](/es/reference/system/xpackage/structs/xpackagedetails.md)
- [Cómo usar un producto duradero sin paquete](/es/publishing/xstore-commerce/xstore-dwob.md)
- [Concesión de acceso a los jugadores al contenido de complemento](/es/publishing/xstore-commerce/xstore-granting-access.md)
- [XPersistentLocalStorageMountForPackage](/es/reference/system/xpersistentlocalstorage/functions/xpersistentlocalstoragemountforpackage.md)
