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

# SDK do PlayFab Services - Event Pipeline

> Envie eventos de telemetria e do PlayStream em lotes com o pipeline de eventos do SDK do PlayFab Services: tipos de autenticação, configuração, compactação GZIP e manipuladores.

O Event Pipeline é um recurso que faz parte do SDK do PlayFab Services, e sua principal finalidade é permitir que os desenvolvedores de jogos enviem eventos para serem armazenados no PlayFab Insights. Ele permite que o desenvolvedor especifique o tamanho do lote, a frequência de envio e outros aspectos de uma solução de telemetria adequada.

Ele ajuda a aliviar essa carga do desenvolvedor de jogos e cuida de todos esses aspectos em nome dele. Há suporte para pipelines de eventos configuráveis. Um título pode conter um ou mais desses pipelines, e cada um pode ser configurado com suas próprias propriedades.

Vamos examinar alguns dos conceitos básicos do pipeline.

## Tipos de pipeline

O tipo de pipeline está diretamente relacionado ao tipo de eventos que um pipeline emite. Há dois tipos diferentes de pipeline que um desenvolvedor pode instanciar:

* **Telemetry Event Pipeline**: só pode emitir eventos de telemetria e usa a API REST [Write Telemetry Events](https://learn.microsoft.com/en-us/rest/api/playfab/events/play-stream-events/write-telemetry-events).

* **PlayStream Event Pipeline**: só pode emitir eventos do PlayStream e usa a API REST [Write Events](https://learn.microsoft.com/en-us/rest/api/playfab/events/play-stream-events/write-events).

Você pode ter vários pipelines com tipos e configurações diferentes, mas **não pode** alterar o tipo do pipeline após a criação. Alterar o tipo exige instanciar o pipeline novamente.

## Tipos de autenticação

Outra parte importante da criação do pipeline é o tipo de autenticação. Há dois mecanismos de autenticação com suporte para os eventos do PlayFab—a autenticação de entidade e a autenticação por chave de telemetria.

A autenticação de entidade é usada quando o desenvolvedor de jogos quer vincular seus eventos a uma entidade específica para agregação ou análise posterior. Por exemplo, o desenvolvedor de jogos pode registrar eventos relacionados às ações do jogador para fazer análises de comportamento posteriores dos jogadores do título que permitam a segmentação.

A autenticação por chave de telemetria é usada quando o desenvolvedor de jogos quer registrar eventos que não precisam necessariamente estar vinculados a uma entidade. Por exemplo, antes de haver um jogador conectado, o título pode começar a enviar eventos relacionados ao desempenho ou a métricas específicas que deseja coletar para análise posterior. Isso pode ser feito sem a necessidade de passar pelo processo normal de autenticação de entidade.

**Combinações de tipo de autenticação/tipo de evento com suporte**

| | **Autenticação de entidade** | **Autenticação por chave de telemetria** |
| - | :-: | :-: |
| **Eventos de telemetria** | Válida | Válida |
| **Eventos do PlayStream** | Válida | Inválida |

### Autenticação de entidade

Este tipo de autenticação é o método de autenticação normal e mais comum do PlayFab. Ele está estreitamente relacionado a uma entidade específica e exige que você chame as APIs de login correspondentes do PlayFab para obter um token de entidade a ser usado em todas as chamadas subsequentes. A lista a seguir representa os diferentes tipos de entidade que podem ser usados com a autenticação de entidade.

* **namespace**: a entidade namespace representa a identidade do jogador entre títulos e o escopo de dados compartilhados. A Publisher ID identifica o namespace.
* **title**: a entidade title representa as informações globais com escopo nesse título.
* **master\_player\_account**: `master_player_account` é uma entidade de jogador compartilhada por todos os títulos de um namespace.
* **title\_player\_account**: para a maioria dos desenvolvedores, title\_player\_account representa o jogador da forma mais tradicional.
* **character**: a entidade character é uma subentidade de title\_player\_account.
* **group**: a entidade group é um contêiner para outras entidades. No momento, ela é limitada a jogadores e personagens.

Para obter mais informações sobre os diferentes tipos de entidade, consulte [Tipos de entidade internos](/pt-BR/services/playfab/live-service-management/game-configuration/entities/available-built-in-entity-types).

Além disso, a entidade do pipeline pode ser atualizada após a criação do pipeline fornecendo um **PFEntityHandle** válido. Assim, o desenvolvedor de jogos pode adicionar uma entidade para começar a vincular seus eventos a ela (*consulte a seção [Mudando para a autenticação de entidade ou atualizando a entidade](#switching-to-entity-auth-or-updating-entity)*) ou até removê-la, caso queira registrar coisas que não estão relacionadas a uma entidade (*consulte a seção [Mudando para a autenticação por chave de telemetria](#switching-to-telemetry-key-auth)*).

Se houver uma entidade no pipeline, ela sempre terá precedência sobre a autenticação por chave de telemetria.

### Autenticação por chave de telemetria

A autenticação por chave de telemetria não exige um token de entidade; portanto, ela não está vinculada a nenhuma entidade específica.

Se a autenticação por chave de telemetria for usada, um struct **PFEventPipelineTelemetryKeyConfig** será necessário durante a criação do pipeline. Há duas partes principais nesse struct:

1. Uma chave de telemetria, que consiste em uma cadeia de caracteres criada e gerenciada pelo PlayFab Game Manager.

2. Um **PFServiceConfigHandle**, que informa ao SDK qual é a configuração de serviço correta a ser usada para carregar os eventos. O identificador de configuração de serviço é criado durante a inicialização do SDK chamando [**PFServiceConfigCreateHandle**](/pt-BR/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfigcreatehandle).

Se o desenvolvedor quiser usar uma chave de telemetria, é importante fornecê-la na criação do pipeline, pois não há como adicionar uma chave de telemetria depois que o pipeline for instanciado.

Vale mencionar que **a autenticação por chave de telemetria só está disponível para eventos de telemetria**; ela não dá suporte a eventos do PlayStream.

## Configuração do Event Pipeline

Como mencionado anteriormente, o pipeline de eventos tem algumas propriedades configuráveis que podem ser fornecidas após a criação do pipeline por meio do parâmetro de struct **PFEventPipelineConfig**.

As propriedades configuráveis são:

* **maxEventsPerBatch**: o número máximo de eventos agrupados em lote antes de gravá-los no PlayFab.
* **maxWaitTimeInSeconds**: o tempo máximo que o pipeline aguarda antes de enviar um lote incompleto.
* **pollDelayInMs**: quanto tempo o pipeline aguardará para ler novamente o buffer de eventos depois de esvaziá-lo.
* **compressionLevel**: define o nível de compactação usado no algoritmo de compactação. Para obter mais detalhes sobre a compactação, consulte *[Compactação GZIP](#gzip-compression)*.
* **retryOnDisconnect**: o pipeline de eventos tentará enviar novamente os eventos que falharam devido à perda de conexão. Disponível apenas para o Telemetry Event Pipeline.
* **bufferSize**: o limite da quantidade de eventos no buffer do pipeline.

### Valores padrão

| Propriedade | Pipeline de telemetria | Pipeline do PlayStream |
| - | - | - |
| **maxEventsPerBatch** | 5 | 5 |
| **maxWaitTimeInSeconds** | 3 | 3 |
| **pollDelayInMs** | 3000 | 10 |
| **compressionLevel** | Nenhum (desabilitado) | Nenhum (desabilitado) |
| **retryOnDisconnect** | true | N/A |
| **bufferSize** | 1024 | 1024 |

Caso [**PFEventPipelineConfig**](/pt-BR/services/playfab/api-references/c/pfeventpipeline/structs/pfeventpipelineconfig) tenha apenas algumas propriedades especificadas, as que estiverem vazias serão substituídas e usarão os valores padrão.

Para ver um exemplo de como qualquer uma dessas propriedades pode ser atualizada no pipeline de eventos, consulte *[Atualizar a configuração do pipeline](#update-pipeline-configuration)*.

<a id="gzip-compression" />

#### **Compactação GZIP**

O Event Pipeline oferece a opção de compactar os payloads do corpo usando o padrão de compactação GZIP.

O nível de compactação desejado pode ser especificado dentro do struct **PFEventPipelineConfig**, que faz parte dos parâmetros da API [**PFEventPipelineUpdateConfiguration**](/pt-BR/services/playfab/api-references/c/pfeventpipeline/functions/pfeventpipelineupdateconfiguration).

Um nível de compactação mais baixo obtém menos compactação, mas tem a maior velocidade, e um nível de compactação mais alto obtém taxas de compactação melhores, mas tem a menor velocidade de compactação. A diferença nas taxas de compactação depende inteiramente do tipo de dados enviados. Dependendo do tamanho e da aleatoriedade dos dados, as taxas de compactação podem ser as mesmas mesmo em níveis diferentes.

**Compensações:**

Usar a compactação aumenta o tempo de CPU devido à complexidade adicional de executar um algoritmo de compactação, mas, por outro lado, o payload do corpo na rede diminui drasticamente. Portanto, dependendo das necessidades e dos recursos do jogo, cabe ao desenvolvedor de jogos decidir se a compactação deve ser usada.

Com base em validação interna, há um aumento médio de 20% no tempo de CPU e uma redução média de 91% no tamanho do payload do corpo. Essas porcentagens podem variar muito dependendo do tamanho do payload e da complexidade dos dados compactados.

## Manipuladores de eventos

Como parte da criação do pipeline, os desenvolvedores de jogos podem fornecer dois manipuladores de eventos opcionais, que são invocados quando os eventos são carregados.

No entanto, se o desenvolvedor de jogos quiser uma experiência do tipo "disparar e esquecer", poderá omitir os manipuladores de eventos.

Os manipuladores de eventos que podem ser fornecidos são os seguintes:

* [**PFEventPipelineBatchUploadSucceededEventHandler**](/pt-BR/services/playfab/api-references/c/pfeventpipeline/functions/pfeventpipelinebatchuploadsucceededeventhandler): como o nome sugere, recebe todos os eventos carregados com êxito no PlayFab.

* [**PFEventPipelineBatchUploadFailedEventHandler**](/pt-BR/services/playfab/api-references/c/pfeventpipeline/functions/pfeventpipelinebatchuploadfailedeventhandler): receberá todos os eventos com falha depois de passarem pela lógica de nova tentativa do pipeline.

### Exemplos de criação de pipeline

A seguir, você encontra diferentes exemplos de como instanciar um pipeline de eventos com base nos tópicos discutidos anteriormente.

1. **Criação de um Telemetry Event Pipeline com autenticação de entidade**

   Se o desenvolvedor quiser enviar eventos de telemetria e não precisar usar a autenticação por chave de telemetria, a API [**PFEventPipelineCreateTelemetryPipelineHandleWithEntity**](/pt-BR/services/playfab/api-references/c/pfeventpipeline/functions/pfeventpipelinecreatetelemetrypipelinehandlewithentity) serve para essa finalidade, como mostra o próximo exemplo:

   ```cpp theme={null}
   void EventPipelineCreation(PFEntityHandle entityHandle, XTaskQueueHandle taskQueueHandle)
   {
       PFEventPipelineHandle handle;

       HRESULT hr = PFEventPipelineCreateTelemetryPipelineHandleWithEntity(
           entityHandle,                       // entityHandle
           taskQueueHandle,                    // queue
           nullptr,                            // eventPipelineBatchUploadedEventHandler
           nullptr,                            // eventPipelineBatchFailedEventHandler
           nullptr,                            // handlerContext
           &handle                             // eventPipelineHandle
       );

       if (FAILED(hr))
       {
           printf("Failed creating event pipeline: 0x%x\r\n", hr);
           return;
       }
   }
   ```

   Este exemplo mostra como criar um Telemetry Event Pipeline que usa a autenticação de entidade e não tem manipuladores. Isso significa que o pipeline dispara os eventos e esquece o resultado.

2. **Criação de um Telemetry Event Pipeline com autenticação por chave de telemetria**

   Se o desenvolvedor quiser enviar eventos de telemetria e precisar usar a autenticação por chave de telemetria, a API PFEventPipelineCreateTelemetryPipelineHandleWithKey serve para essa finalidade, como mostra o próximo exemplo:

   ```cpp theme={null}
   void EventPipelineCreation(PFServiceConfigHandle serviceConfigHandle, XTaskQueueHandle taskQueueHandle)
   {
       PFEventPipelineHandle handle;

       PFEventPipelineTelemetryKeyConfig telemetryKeyConfig
       {
           "myTelemetryKey",                   // telemetryKey
           serviceConfigHandle,                // serviceConfigHandle
       };

       HRESULT hr = PFEventPipelineCreateTelemetryPipelineHandleWithKey(
           &telemetryKeyConfig,                // eventPipelineTelemetryKeyConfig
           taskQueueHandle,                    // queue
           nullptr,                            // eventPipelineBatchUploadedEventHandler
           nullptr,                            // eventPipelineBatchFailedEventHandler
           nullptr,                            // handlerContext
           &handle                             // eventPipelineHandle
       );

       if (FAILED(hr))
       {
           printf("Failed creating event pipeline: 0x%x\r\n", hr);
           return;
       }
   }
   ```

   Este exemplo mostra como criar um pipeline de eventos de telemetria que não usa a autenticação de entidade.

   O pipeline de eventos começa a carregar eventos usando a chave de telemetria, com a possibilidade de adicionar uma entidade posteriormente. Consulte [Mudando para a autenticação de entidade ou atualizando a entidade](#switching-to-entity-auth-or-updating-entity)

3. **Criação de um PlayStream Event Pipeline**

   Se o desenvolvedor quiser enviar eventos do PlayStream, a API PFEventPipelineCreatePlayStreamPipelineHandle serve para essa finalidade, como mostra o próximo exemplo:

   ```cpp theme={null}
   void EventPipelineCreation(PFEntityHandle entityHandle, XTaskQueueHandle taskQueueHandle)
   {
       PFEventPipelineHandle handle;

       HRESULT hr = PFEventPipelineCreatePlayStreamPipelineHandle(
           entityHandle,                       // entityHandle
           taskQueueHandle,                    // queue
           nullptr,                            // eventPipelineBatchUploadedEventHandler
           nullptr,                            // eventPipelineBatchFailedEventHandler
           nullptr,                            // handlerContext
           &handle                             // eventPipelineHandle
       );

       if (FAILED(hr))
       {
           printf("Failed creating event pipeline: 0x%x\r\n", hr);
           return;
       }
   }
   ```

   Este exemplo mostra como é criado um PlayStream Event Pipeline que usa a autenticação de entidade e não tem manipuladores. Isso significa que o pipeline dispara os eventos e esquece o resultado.

4. **Event Pipeline usando manipuladores de eventos**

   Este exemplo mostra como os manipuladores de eventos seriam fornecidos às APIs de criação do pipeline.

   ```cpp theme={null}
   void CALLBACK OnBatchUploadedHandler(void* context, PFUploadedEvent const* const* events, size_t eventsCount)
   {
       // Handle response
   }

   void CALLBACK OnBatchUploadFailedHandler(void* context, HRESULT hr, const char* errorMessage, PFEvent const* const* events, size_t eventsCount)
   {
       // Handle response
   }

   void EventPipelineCreation(PFEntityHandle entityHandle, XTaskQueueHandle taskQueueHandle)
   {
       PFEventPipelineHandle handle;

       HRESULT hr = PFEventPipelineCreateTelemetryPipelineHandleWithEntity(
           entityHandle,                       // entityHandle
           taskQueueHandle,                    // queue
           OnBatchUploadedHandler,             // eventPipelineBatchUploadedEventHandler
           OnBatchUploadFailedHandler,         // eventPipelineBatchFailedEventHandler
           nullptr,                            // handlerContext
           &handle                             // eventPipelineHandle
       );

       if (FAILED(hr))
       {
           printf("Failed creating event pipeline: 0x%x\r\n", hr);
           return;
       }
   }
   ```

Como mostra o exemplo, ***OnBatchUploadedHandler*** e ***OnBatchUploadFailedHandler*** são declarados como duas funções de retorno de chamada diferentes, passadas quando o Event Pipeline é criado. Cada resultado associado a um evento é retornado em uma dessas duas funções, dependendo de o resultado ter sido de êxito ou de falha. Cabe ao desenvolvedor de jogos decidir como tratar o resultado.

### Emitindo eventos

Emitir eventos é uma operação simples depois que o pipeline de eventos já foi criado. O desenvolvedor de jogos deve chamar a API [**PFEventPipelineEmitEvent**](/pt-BR/services/playfab/api-references/c/pfeventpipeline/functions/pfeventpipelineemitevent), que recebe o identificador do pipeline de eventos existente e o evento que deseja enviar.

```cpp theme={null}
void EmitEvent(PFEventPipelineHandle handle)
{
    PFEvent myEvent
    {
        nullptr,
        "custom.playfab.events.PlayFab.Test.TelemetryEventPipelineTests",
        "TelemetryEvent",
        nullptr,
        "{}"
    };

    HRESULT hr = PFEventPipelineEmitEvent(
        handle,
        &myEvent
    );

    if (FAILED(hr))
    {
        printf("Failed emitting event: 0x%x\r\n", hr);
        return;
    }
}
```

É importante observar que, ao usar a autenticação por chave de telemetria, o único valor válido para entityType como parte de **PFEntityKey** é **"external"**. Quaisquer outros tipos de entidade são rejeitados, e os eventos não são carregados.

Exemplo de um PFEntityKey válido ao usar a autenticação por chave de telemetria:

```cpp theme={null}
void EmitEvent(PFEventPipelineHandle handle)
{
    PFEntityKey pfEntityKey{ "my-unique-ID", "external" };  // Note the "external" value

    PFEvent myEvent
    {
        &pfEntityKey,
        "custom.playfab.events.PlayFab.Test.EventsWithTelemetryKey",
        "TelemetryEvent",
        nullptr,
        "{}"
    };

    HRESULT hr = PFEventPipelineEmitEvent(
        handle,
        &myEvent
    );

    if (FAILED(hr))
    {
        printf("Failed emitting event: 0x%x\r\n", hr);
        return;
    }
}
```

Se o limite de tamanho do buffer for excedido quando um evento for emitido, você receberá o seguinte erro do SDK:

* `E_PF_API_CLIENT_REQUEST_RATE_LIMIT_EXCEEDED (0x892354dd)`

Defina um tamanho de buffer adequado às suas necessidades.

<a id="switching-to-entity-auth-or-updating-entity" />

### Mudando para a autenticação de entidade ou atualizando a entidade

Se um pipeline tiver sido criado usando apenas uma configuração de chave de telemetria, há uma forma de mudar para a autenticação de entidade, ou de atualizar seu pipeline para usar uma entidade diferente.

Usando [**PFEventPipelineAddUploadingEntity**](/pt-BR/services/playfab/api-references/c/pfeventpipeline/functions/pfeventpipelineadduploadingentity), é possível anexar uma entidade a um pipeline em execução sem precisar reinicializá-lo. Isso também substitui a entidade existente, se houver.

Exemplo:

Um Telemetry Event Pipeline é criado com a configuração de chave de telemetria no início da execução do título. Possíveis motivos para isso são que ainda não há uma identidade de jogador ou que você ainda não quer registrar nada relacionado a um jogador.

```cpp theme={null}
void EventPipelineCreation(PFServiceConfigHandle serviceConfigHandle, XTaskQueueHandle taskQueueHandle)
{
    PFEventPipelineHandle handle;

    PFEventPipelineTelemetryKeyConfig telemetryKeyConfig
    {
        "myTelemetryKey",                   // telemetryKey
        serviceConfigHandle,                // serviceConfigHandle
    };

    HRESULT hr = PFEventPipelineCreateTelemetryPipelineHandleWithKey(
        &telemetryKeyConfig,                // eventPipelineTelemetryKeyConfig
        taskQueueHandle,                    // queue
        nullptr,                            // eventPipelineBatchUploadedEventHandler
        nullptr,                            // eventPipelineBatchFailedEventHandler
        nullptr,                            // handlerContext
        &handle                             // eventPipelineHandle
    );

    if (FAILED(hr))
    {
        printf("Failed creating event pipeline: 0x%x\r\n", hr);
        return;
    }
}
```

Depois que um jogador entrar, ou quando você quiser começar a enviar eventos anexados a uma entidade específica, chame **PFEventPipelineAddUploadingEntity** com o identificador do pipeline de eventos existente e o identificador da entidade desejada, da seguinte forma:

```cpp theme={null}
void EventPipelineUpdateEntity(PFEventPipelineHandle handle)
{
    HRESULT hr = PFEventPipelineAddUploadingEntity(
        handle,                 // eventPipelineHandle
        entityHandle            // entityHandle
    );

    if (FAILED(hr))
    {
        printf("Failed adding uploading entity: 0x%x\r\n", hr);
        return;
    }
}
```

Após essa chamada, o pipeline começará a registrar todos os eventos subsequentes vinculados a essa entidade.

<a id="switching-to-telemetry-key-auth" />

### Mudando para a autenticação por chave de telemetria

Ampliando o cenário anterior, se o desenvolvedor quiser voltar à autenticação de telemetria e desanexar o registro de eventos da entidade, poderá chamar [**PFEventPipelineRemoveUploadingEntity**](/pt-BR/services/playfab/api-references/c/pfeventpipeline/functions/pfeventpipelineremoveuploadingentity) e passar o identificador do pipeline de eventos assim:

```cpp theme={null}
void EventPipelineRemoveEntity(PFEventPipelineHandle handle)
{
    HRESULT hr = PFEventPipelineRemoveUploadingEntity(
        handle                  // eventPipelineHandle
    );

    if (FAILED(hr))
    {
        printf("Failed removing uploading entity: 0x%x\r\n", hr);
        return;
    }
}
```

Essa chamada remove a entidade e, efetivamente, volta à autenticação por chave de telemetria para todos os eventos subsequentes.

<a id="update-pipeline-configuration" />

### **Atualizar a configuração do pipeline**

Você pode atualizar pipelines usando a API [**PFEventPipelineUpdateConfiguration**](/pt-BR/services/playfab/api-references/c/pfeventpipeline/functions/pfeventpipelineupdateconfiguration), que recebe o identificador do pipeline de eventos existente e um novo struct de configuração, da seguinte forma:

```cpp theme={null}
void EventPipelineUpdateConfiguration(PFEventPipelineHandle handle)
{
    uint32_t maxEvents = 10;
    uint32_t maxWaitTime = 5;
    uint32_t pollDelay = 50;
    PFHCCompressionLevel compressionLevel = PFHCCompressionLevel::Medium;
    bool retryOnDisconnect = true;
    size_t bufferSize = 2048;

    PFEventPipelineConfig eventPipelineConfig
    {
        &maxEvents,             // maxEventsPerBatch
        &maxWaitTime,           // maxWaitTimeInSeconds
        &pollDelay,             // pollDelayInMs
        &compressionLevel,      // compressionLevel
        &retryOnDisconnect,     // retryOnDisconnect
        &bufferSize,            // bufferSize
    };

    HRESULT hr = PFEventPipelineUpdateConfiguration(
        handle,                 // eventPipelineHandle
        eventPipelineConfig     // eventPipelineConfig
    );

    if (FAILED(hr))
    {
        printf("Failed updating event pipeline configuration: 0x%x\r\n", hr);
        return;
    };
}
```

***Lembrete**: quaisquer propriedades vazias ou nulas substituem o valor de configuração existente pelo valor padrão.*

## Chaves de telemetria inválidas/desativadas

Caso uma chave de telemetria seja desativada ou uma chave inválida seja fornecida na criação do pipeline, todos os pipelines de eventos em execução com essa chave de telemetria começarão a falhar assim que descobrirem que a chave é inválida ou foi desativada.

Caso o cliente reative a chave, o pipeline não perceberá isso e continuará enviando falhas pelo manipulador de eventos com falha. Vale mencionar que esse comportamento é baseado em sessão, o que significa que, se o título for reiniciado, um novo pipeline será criado e poderá carregar eventos novamente.

## Ciclo de vida do identificador do pipeline

Como outros identificadores do PlayFab, os identificadores de pipeline de eventos usam um padrão de duplicar/fechar:

* [**PFEventPipelineCloseHandle**](/pt-BR/services/playfab/api-references/c/pfeventpipeline/functions/pfeventpipelineclosehandle): fecha um identificador de pipeline. Quando o último identificador de um pipeline é fechado, o pipeline é destruído e todos os eventos restantes no buffer são enviados.
* [**PFEventPipelineDuplicateHandle**](/pt-BR/services/playfab/api-references/c/pfeventpipeline/functions/pfeventpipelineduplicatehandle): duplica um identificador de pipeline. Tanto o identificador original quanto o duplicado devem ser fechados de forma independente com [**PFEventPipelineCloseHandle**](/pt-BR/services/playfab/api-references/c/pfeventpipeline/functions/pfeventpipelineclosehandle).

```cpp theme={null}
// Duplicate a handle for use in another component
PFEventPipelineHandle duplicatedHandle;
HRESULT hr = PFEventPipelineDuplicateHandle(originalHandle, &duplicatedHandle);

// When done, close both handles independently
PFEventPipelineCloseHandle(duplicatedHandle);
PFEventPipelineCloseHandle(originalHandle);
```

## Confira também

* [Tutorial do pipeline de eventos](/pt-BR/services/playfab/sdks/c/event-pipeline/eventpipeline-tutorial)


## Related topics

- [Tutorial do Event Pipeline](/pt-BR/services/playfab/sdks/c/event-pipeline/eventpipeline-tutorial.md)
- [Notas de versão do SDK PlayFab Services para C/C++](/pt-BR/services/playfab/release-notes/playfab-c/index.md)
- [SDK do PlayFab Services](/pt-BR/services/playfab/sdks/c/index.md)
- [Notas de versão do SDK PlayFab Services 2023](/pt-BR/services/playfab/release-notes/2023.md)
- [Notas de versão do SDK PlayFab Services 2025](/pt-BR/services/playfab/release-notes/2025.md)
