> ## 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 生命周期

> 按照正确的顺序初始化、配置和关闭 PlayFab Services C SDK，包括内存钩子、Core 和服务配置。

本页涵盖 PlayFab Services SDK 的完整启动和关闭序列。每个游戏都遵循相同的高层模式：配置可选钩子、初始化 Core、创建服务配置、初始化 Services、执行业务逻辑，然后按相反顺序关闭。

## 初始化序列

初始化分为四步。第一步是可选的；其余三步是必需的。

```
PFMemSetFunctions (optional)  →  PFInitialize  →  PFServiceConfigCreateHandle  →  PFServicesInitialize
```

### 第 1 步：设置自定义内存钩子（可选）

如果你的游戏使用自定义内存分配器，请在调用任何其他 PlayFab API 之前调用 [**PFMemSetFunctions**](/services/playfab/api-references/c/pfplatform/functions/pfmemsetfunctions)。这会将所有 SDK 的内存分配路由到你自己的 `alloc` 和 `free` 回调。

```cpp theme={null}
PFMemoryHooks hooks{};
hooks.alloc = MyAllocFunction;
hooks.free = MyFreeFunction;
HRESULT hr = PFMemSetFunctions(&hooks);
```

<Info>
  [**PFMemSetFunctions**](/services/playfab/api-references/c/pfplatform/functions/pfmemsetfunctions) 必须在 [**PFInitialize**](/services/playfab/api-references/c/pfcore/functions/pfinitialize) 之前调用。一旦钩子设置完成，就不能再次调用。
</Info>

如果你不需要自定义内存管理，可以跳过这一步。SDK 会使用默认的分配例程。

### 第 2 步：初始化 PlayFab Core

[**PFInitialize**](/services/playfab/api-references/c/pfcore/functions/pfinitialize) 设置 SDK 的全局状态，包括 HTTP 层和后台任务队列。具体签名因平台而异。

#### Windows、Linux、iOS 和 macOS

```cpp theme={null}
HRESULT hr = PFInitialize(nullptr); // Uses a default threadpool queue
```

如果想控制哪个队列处理后台工作，请传入一个 **XTaskQueueHandle**。传入 `nullptr` 以使用默认的线程池队列。

#### Android

在 Android 上，你还必须提供 Java VM 和应用程序上下文，以便 SDK 可以初始化 libHttpClient：

```cpp theme={null}
HRESULT hr = PFInitialize(nullptr, javaVm, applicationContext);
```

<Note>
  如果你没有显式调用 **PFInitialize**，[**PFServicesInitialize**](/services/playfab/api-references/c/pfservices/functions/pfservicesinitialize) 会使用默认参数在内部调用它。对于大多数游戏来说这没问题。但是，如果你通过 **PFMemSetFunctions** 使用自定义内存钩子，你**必须**自己调用 **PFInitialize** — 否则 [**PFServicesInitialize**](/services/playfab/api-references/c/pfservices/functions/pfservicesinitialize) 会在你的内存钩子生效之前初始化 Core，SDK 会转而使用默认的分配例程。
</Note>

### 第 3 步：创建服务配置

[**PFServiceConfigCreateHandle**](/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfigcreatehandle) 创建一个句柄，告诉 SDK 目标是哪个 PlayFab 游戏（title）和端点。你可以在 [Game Manager](https://developer.playfab.com) 中找到这两个值。

```cpp theme={null}
PFServiceConfigHandle serviceConfigHandle{ nullptr };
HRESULT hr = PFServiceConfigCreateHandle(
    "https://ABCDEF.playfabapi.com",    // API endpoint from Game Manager
    "ABCDEF",                           // Title ID from Game Manager
    &serviceConfigHandle);
```

返回的 **PFServiceConfigHandle** 是所有后续登录调用所必需的。

### 第 4 步：初始化 PlayFab Services

**PFServicesInitialize** 在 Core 之上设置 Services 层（Inventory、Leaderboards、Friends 等）。

#### Windows、Linux、iOS 和 macOS

```cpp theme={null}
HRESULT hr = PFServicesInitialize(nullptr);
```

该参数保留供将来使用；请传入 `nullptr`。

#### Android

在 Android 上，传入一个包含 Java VM 和应用程序上下文的 **HCInitArgs** 结构：

```cpp theme={null}
HRESULT hr = PFServicesInitialize(nullptr, initArgs);
```

此调用成功后，SDK 便已准备就绪。你可以登录玩家并进行服务调用。

## PFServiceConfigHandle 生命周期

**PFServiceConfigHandle** 是一个引用计数的句柄。SDK 通过引用计数管理其内部生命周期，但你负责关闭自己拥有的每一个句柄。

| 函数                                                                                                                                | 描述                                                                                                                                                                 |
| --------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [**PFServiceConfigCreateHandle**](/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfigcreatehandle)       | 创建新句柄。初始引用计数为 1。                                                                                                                                                   |
| [**PFServiceConfigDuplicateHandle**](/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfigduplicatehandle) | 递增引用计数并返回第二个句柄。两个句柄都必须独立关闭。                                                                                                                                        |
| [**PFServiceConfigCloseHandle**](/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfigclosehandle)         | 递减引用计数。当计数达到 0 时，配置会被销毁。                                                                                                                                           |
| [**PFServiceConfigGetAPIEndpoint**](/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfiggetapiendpoint)   | 获取 API 端点字符串。先调用 [**PFServiceConfigGetAPIEndpointSize**](/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfiggetapiendpointsize) 以确定缓冲区大小。 |
| [**PFServiceConfigGetTitleId**](/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfiggettitleid)           | 获取 title ID 字符串。先调用 [**PFServiceConfigGetTitleIdSize**](/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfiggettitleidsize) 以确定缓冲区大小。      |

### 复制句柄

当你需要在管理自己生命周期的组件之间共享服务配置时，使用 [**PFServiceConfigDuplicateHandle**](/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfigduplicatehandle)：

```cpp theme={null}
PFServiceConfigHandle duplicatedHandle{ nullptr };
HRESULT hr = PFServiceConfigDuplicateHandle(serviceConfigHandle, &duplicatedHandle);

// Both handles are now valid and must be closed separately
PFServiceConfigCloseHandle(duplicatedHandle);
PFServiceConfigCloseHandle(serviceConfigHandle);
```

## 关闭序列

关闭与初始化相反。你必须在 Core 之前反初始化 Services，且两个调用都是异步的。

```
Close handles  →  PFServicesUninitializeAsync  →  PFUninitializeAsync
```

### 第 1 步：关闭所有已打开的句柄

在拆除 SDK 之前，关闭你拥有的每一个 **PFEntityHandle** 和 **PFServiceConfigHandle**：

```cpp theme={null}
PFEntityCloseHandle(entityHandle);
entityHandle = nullptr;

PFServiceConfigCloseHandle(serviceConfigHandle);
serviceConfigHandle = nullptr;
```

### 第 2 步：反初始化 Services

[**PFServicesUninitializeAsync**](/services/playfab/api-references/c/pfservices/functions/pfservicesuninitializeasync) 拆除 Services 层。在继续之前等待其完成。

```cpp theme={null}
XAsyncBlock asyncServices{};
HRESULT hr = PFServicesUninitializeAsync(&asyncServices);
hr = XAsyncGetStatus(&asyncServices, true); // Blocking wait
```

### 第 3 步：反初始化 Core

Services 清理完成后，调用 [**PFUninitializeAsync**](/services/playfab/api-references/c/pfcore/functions/pfuninitializeasync) 拆除 Core：

```cpp theme={null}
XAsyncBlock asyncCore{};
HRESULT hr = PFUninitializeAsync(&asyncCore);
hr = XAsyncGetStatus(&asyncCore, true); // Blocking wait
```

<Note>
  如果你没有显式调用 **PFInitialize**，则可以跳过 **PFUninitializeAsync**。在这种情况下，[**PFServicesUninitializeAsync**](/services/playfab/api-references/c/pfservices/functions/pfservicesuninitializeasync) 会自动处理 Core 的清理。但是，如果你自己调用了 **PFInitialize**，则必须自己调用 [**PFUninitializeAsync**](/services/playfab/api-references/c/pfcore/functions/pfuninitializeasync)。
</Note>

## 完整示例

以下示例展示了 Windows 游戏从初始化到关闭的完整生命周期：

```cpp theme={null}
#include <playfab/services/PFServices.h>

void RunPlayFab()
{
    //
    // Optional: set custom memory hooks
    //
    PFMemoryHooks hooks{};
    hooks.alloc = MyAllocFunction;
    hooks.free = MyFreeFunction;
    HRESULT hr = PFMemSetFunctions(&hooks);

    //
    // Initialize Core
    //
    hr = PFInitialize(nullptr);

    //
    // Create a service configuration
    //
    PFServiceConfigHandle serviceConfigHandle{ nullptr };
    hr = PFServiceConfigCreateHandle(
        "https://ABCDEF.playfabapi.com",
        "ABCDEF",
        &serviceConfigHandle);

    //
    // Initialize Services
    //
    hr = PFServicesInitialize(nullptr);

    //
    // Log in a player (Windows example using XUser)
    //
    PFAuthenticationLoginWithXUserRequest request{};
    request.createAccount = true;
    request.user = userHandle;

    XAsyncBlock asyncLogin{};
    hr = PFAuthenticationLoginWithXUserAsync(serviceConfigHandle, &request, &asyncLogin);
    hr = XAsyncGetStatus(&asyncLogin, true);

    size_t bufferSize{};
    hr = PFAuthenticationLoginWithXUserGetResultSize(&asyncLogin, &bufferSize);

    std::vector<char> loginResultBuffer(bufferSize);
    PFAuthenticationLoginResult const* loginResult{};
    PFEntityHandle entityHandle{ nullptr };
    hr = PFAuthenticationLoginWithXUserGetResult(
        &asyncLogin, &entityHandle,
        loginResultBuffer.size(), loginResultBuffer.data(),
        &loginResult, nullptr);

    //
    // ... make service calls ...
    //

    //
    // Shutdown: close handles first
    //
    PFEntityCloseHandle(entityHandle);
    entityHandle = nullptr;

    PFServiceConfigCloseHandle(serviceConfigHandle);
    serviceConfigHandle = nullptr;

    //
    // Shutdown: uninitialize Services, then Core
    //
    XAsyncBlock asyncServices{};
    hr = PFServicesUninitializeAsync(&asyncServices);
    hr = XAsyncGetStatus(&asyncServices, true);

    XAsyncBlock asyncCore{};
    hr = PFUninitializeAsync(&asyncCore);
    hr = XAsyncGetStatus(&asyncCore, true);
}
```

## 常见错误

| 错误                                                                                                                                                                                                                               | 发生的情况                            | 解决方法                                                                                                                                                                                                  |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 在 [**PFInitialize**](/services/playfab/api-references/c/pfcore/functions/pfinitialize) 之后调用 [**PFMemSetFunctions**](/services/playfab/api-references/c/pfplatform/functions/pfmemsetfunctions)                                   | 调用失败。内存钩子只能在初始化之前设置。             | 将 [**PFMemSetFunctions**](/services/playfab/api-references/c/pfplatform/functions/pfmemsetfunctions) 移到程序中的第一个 PlayFab 调用。                                                                            |
| 在 [**PFServicesUninitializeAsync**](/services/playfab/api-references/c/pfservices/functions/pfservicesuninitializeasync) 之前调用 [**PFUninitializeAsync**](/services/playfab/api-references/c/pfcore/functions/pfuninitializeasync) | 未定义行为。Core 已被拆除而 Services 仍依赖于它。 | 始终先反初始化 Services，等待完成后再反初始化 Core。                                                                                                                                                                     |
| 显式调用 [**PFInitialize**](/services/playfab/api-references/c/pfcore/functions/pfinitialize) 后忘记调用 [**PFUninitializeAsync**](/services/playfab/api-references/c/pfcore/functions/pfuninitializeasync)                               | Core 资源泄漏。后台队列和 HTTP 层未清理。       | 如果你调用了 [**PFInitialize**](/services/playfab/api-references/c/pfcore/functions/pfinitialize)，就必须调用 [**PFUninitializeAsync**](/services/playfab/api-references/c/pfcore/functions/pfuninitializeasync)。 |
| 未等待异步反初始化完成                                                                                                                                                                                                                      | 清理仍在进行时进程可能已退出，导致崩溃或挂起。          | 使用 `XAsyncGetStatus(async, true)` 或 **XAsyncBlock** 回调来等待完成。                                                                                                                                          |
| 泄漏 **PFServiceConfigHandle** 或 **PFEntityHandle**                                                                                                                                                                                | 引用计数的资源未被释放，可能阻止干净关闭。            | 在调用反初始化之前关闭你创建或复制的每一个句柄。                                                                                                                                                                              |

## 参见

* [快速入门：Win32](/services/playfab/sdks/c/quickstart-win32)
* [快速入门：Windows](/services/playfab/sdks/c/quickstart-gdk)
* [调试跟踪](/services/playfab/sdks/c/tracing)
* [异步编程模型](https://learn.microsoft.com/en-us/gaming/gdk/_content/gc/system/overviews/async-programming-model)


## Related topics

- [多人游戏服务器的生命周期](/zh-CN/services/playfab/multiplayer/servers/multiplayer-game-server-lifecycle.md)
- [大厅生命周期与过期](/zh-CN/services/playfab/multiplayer/lobby/lobby-ttl.md)
- [多人游戏服务器构建的生命周期](/zh-CN/services/playfab/multiplayer/servers/multiplayer-build-lifecycle.md)
- [多人游戏服务器构建区域的生命周期](/zh-CN/services/playfab/multiplayer/servers/multiplayer-build-region-lifecycle.md)
- [实时音频处理](/zh-CN/services/xbox-services/multiplayer/chat/game-chat2/real-time-audio-manipulation.md)
