> ## 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**](/zh-TW/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**](/zh-TW/services/playfab/api-references/c/pfplatform/functions/pfmemsetfunctions) 必須在 [**PFInitialize**](/zh-TW/services/playfab/api-references/c/pfcore/functions/pfinitialize) 之前呼叫。設定攔截之後，就無法再次呼叫它。
</Info>

如果您不需要自訂記憶體管理，請略過此步驟。SDK 會使用預設的配置常式。

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

[**PFInitialize**](/zh-TW/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**](/zh-TW/services/playfab/api-references/c/pfservices/functions/pfservicesinitialize) 會使用預設參數在內部呼叫它。這對大多數遊戲來說沒有問題。不過，如果您透過 **PFMemSetFunctions** 使用自訂記憶體攔截，就**必須**自行呼叫 **PFInitialize**；否則 [**PFServicesInitialize**](/zh-TW/services/playfab/api-references/c/pfservices/functions/pfservicesinitialize) 會在記憶體攔截生效之前初始化 Core，而 SDK 會改用預設的配置常式。
</Note>

### 步驟 3：建立服務設定

[**PFServiceConfigCreateHandle**](/zh-TW/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfigcreatehandle) 會建立一個控制代碼，告知 SDK 要以哪個 PlayFab 遊戲和端點為目標。您可以在 [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**](/zh-TW/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfigcreatehandle) | 建立新的控制代碼。初始參考計數為 1。 |
| [**PFServiceConfigDuplicateHandle**](/zh-TW/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfigduplicatehandle) | 遞增參考計數並傳回第二個控制代碼。這兩個控制代碼都必須分別關閉。 |
| [**PFServiceConfigCloseHandle**](/zh-TW/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfigclosehandle) | 遞減參考計數。當計數達到 0 時，設定會被終結。 |
| [**PFServiceConfigGetAPIEndpoint**](/zh-TW/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfiggetapiendpoint) | 擷取 API 端點字串。請先呼叫 [**PFServiceConfigGetAPIEndpointSize**](/zh-TW/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfiggetapiendpointsize) 以判斷緩衝區大小。 |
| [**PFServiceConfigGetTitleId**](/zh-TW/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfiggettitleid) | 擷取遊戲識別碼字串。請先呼叫 [**PFServiceConfigGetTitleIdSize**](/zh-TW/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfiggettitleidsize) 以判斷緩衝區大小。 |

### 複製控制代碼

當您需要在各自管理存留期的元件之間共用服務設定時，請使用 [**PFServiceConfigDuplicateHandle**](/zh-TW/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);
```

## 關閉順序

關閉是初始化的反向順序。您必須先將 Services 取消初始化，再將 Core 取消初始化，而且這兩個呼叫都是非同步的。

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

### 步驟 1：關閉所有開啟的控制代碼

在終止 SDK 之前，請關閉您擁有的每個 **PFEntityHandle** 和 **PFServiceConfigHandle**：

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

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

### 步驟 2：將 Services 取消初始化

[**PFServicesUninitializeAsync**](/zh-TW/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**](/zh-TW/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**](/zh-TW/services/playfab/api-references/c/pfservices/functions/pfservicesuninitializeasync) 會自動處理 Core 的清除。不過，如果您確實自行呼叫了 **PFInitialize**，就必須自行呼叫 [**PFUninitializeAsync**](/zh-TW/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**](/zh-TW/services/playfab/api-references/c/pfcore/functions/pfinitialize) 之後呼叫 [**PFMemSetFunctions**](/zh-TW/services/playfab/api-references/c/pfplatform/functions/pfmemsetfunctions) | 呼叫失敗。記憶體攔截只能在初始化之前設定。 | 將 [**PFMemSetFunctions**](/zh-TW/services/playfab/api-references/c/pfplatform/functions/pfmemsetfunctions) 移至程式中的第一個 PlayFab 呼叫。 |
| 在 [**PFServicesUninitializeAsync**](/zh-TW/services/playfab/api-references/c/pfservices/functions/pfservicesuninitializeasync) 之前呼叫 [**PFUninitializeAsync**](/zh-TW/services/playfab/api-references/c/pfcore/functions/pfuninitializeasync) | 未定義的行為。Core 在 Services 仍相依於它時就被終止。 | 一律先將 Services 取消初始化，等候完成，再將 Core 取消初始化。 |
| 在明確呼叫 [**PFInitialize**](/zh-TW/services/playfab/api-references/c/pfcore/functions/pfinitialize) 之後忘記呼叫 [**PFUninitializeAsync**](/zh-TW/services/playfab/api-references/c/pfcore/functions/pfuninitializeasync) | Core 資源洩漏。背景佇列和 HTTP 層不會被清除。 | 如果您呼叫了 [**PFInitialize**](/zh-TW/services/playfab/api-references/c/pfcore/functions/pfinitialize)，就必須呼叫 [**PFUninitializeAsync**](/zh-TW/services/playfab/api-references/c/pfcore/functions/pfuninitializeasync)。 |
| 未等候非同步取消初始化完成 | 程序可能會在清除仍在進行時結束，導致當機或停止回應。 | 使用 `XAsyncGetStatus(async, true)` 或 **XAsyncBlock** 回呼來等候完成。 |
| 洩漏 **PFServiceConfigHandle** 或 **PFEntityHandle** | 參考計數的資源不會被釋放，並可能妨礙正常關閉。 | 在呼叫取消初始化之前，關閉您建立或複製的每個控制代碼。 |

## 另請參閱

* [快速入門：Win32](/zh-TW/services/playfab/sdks/c/quickstart-win32)
* [快速入門：Windows](/zh-TW/services/playfab/sdks/c/quickstart-gdk)
* [偵錯追蹤](/zh-TW/services/playfab/sdks/c/tracing)
* [非同步程式設計模型](https://learn.microsoft.com/en-us/gaming/gdk/_content/gc/system/overviews/async-programming-model)


## Related topics

- [實體控制代碼](/zh-TW/services/playfab/sdks/c/entity-handles.md)
- [多人遊戲伺服器的生命週期](/zh-TW/services/playfab/multiplayer/servers/multiplayer-game-server-lifecycle.md)
- [多人遊戲伺服器組建的生命週期](/zh-TW/services/playfab/multiplayer/servers/multiplayer-build-lifecycle.md)
- [多人遊戲伺服器組建區域的生命週期](/zh-TW/services/playfab/multiplayer/servers/multiplayer-build-region-lifecycle.md)
- [Game Saves 概觀](/zh-TW/build/core-features/common/game-save/game-saves-overview.md)
