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

> Initialize, configure, and shut down the PlayFab Services C SDK in the correct order, including memory hooks, Core, and service configuration.

This page covers the complete startup and shutdown sequence for the PlayFab Services SDK. Every title follows the same high-level pattern: configure optional hooks, initialize Core, create a service configuration, initialize Services, do work, then shut down in reverse order.

## Initialization sequence

Initialization has four steps. The first is optional; the remaining three are required.

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

### Step 1: Set custom memory hooks (optional)

If your title uses a custom memory allocator, call [**PFMemSetFunctions**](/services/playfab/api-references/c/pfplatform/functions/pfmemsetfunctions) before any other PlayFab API. This routes all SDK memory allocations through your own `alloc` and `free` callbacks.

```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) must be called before [**PFInitialize**](/services/playfab/api-references/c/pfcore/functions/pfinitialize). It can't be called again after hooks have been set.
</Info>

If you don't need custom memory management, skip this step. The SDK uses default allocation routines.

### Step 2: Initialize PlayFab Core

[**PFInitialize**](/services/playfab/api-references/c/pfcore/functions/pfinitialize) sets up the SDK's global state, including the HTTP layer and background task queue. The exact signature varies by platform.

#### Windows, Linux, iOS, and macOS

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

Pass an **XTaskQueueHandle** if you want to control which queue handles background work. Pass `nullptr` to use the default threadpool queue.

#### Android

On Android, you must also provide the Java VM and application context so the SDK can initialize libHttpClient:

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

<Note>
  If you don't call **PFInitialize** explicitly, [**PFServicesInitialize**](/services/playfab/api-references/c/pfservices/functions/pfservicesinitialize) calls it internally with default parameters. This is fine for most titles. However, if you're using custom memory hooks via **PFMemSetFunctions**, you **must** call **PFInitialize** yourself — otherwise [**PFServicesInitialize**](/services/playfab/api-references/c/pfservices/functions/pfservicesinitialize) initializes Core before your memory hooks take effect, and the SDK uses default allocation routines instead.
</Note>

### Step 3: Create a service configuration

[**PFServiceConfigCreateHandle**](/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfigcreatehandle) creates a handle that tells the SDK which PlayFab title and endpoint to target. You'll find both values in [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);
```

The returned **PFServiceConfigHandle** is required for all subsequent login calls.

### Step 4: Initialize PlayFab Services

**PFServicesInitialize** sets up the Services layer (Inventory, Leaderboards, Friends, and so on) on top of Core.

#### Windows, Linux, iOS, and macOS

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

The parameter is reserved for future use; pass `nullptr`.

#### Android

On Android, pass an **HCInitArgs** struct containing the Java VM and application context:

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

After this call succeeds, the SDK is ready. You can log in players and make service calls.

## PFServiceConfigHandle lifecycle

A **PFServiceConfigHandle** is a ref-counted handle. The SDK manages its internal lifetime through reference counting, but you're responsible for closing every handle you own.

| Function                                                                                                                          | Description                                                                                                                                                                                                         |
| --------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [**PFServiceConfigCreateHandle**](/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfigcreatehandle)       | Creates a new handle. The initial ref count is 1.                                                                                                                                                                   |
| [**PFServiceConfigDuplicateHandle**](/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfigduplicatehandle) | Increments the ref count and returns a second handle. Both handles must be closed independently.                                                                                                                    |
| [**PFServiceConfigCloseHandle**](/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfigclosehandle)         | Decrements the ref count. When it reaches 0, the config is destroyed.                                                                                                                                               |
| [**PFServiceConfigGetAPIEndpoint**](/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfiggetapiendpoint)   | Retrieves the API endpoint string. Call [**PFServiceConfigGetAPIEndpointSize**](/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfiggetapiendpointsize) first to determine the buffer size. |
| [**PFServiceConfigGetTitleId**](/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfiggettitleid)           | Retrieves the title ID string. Call [**PFServiceConfigGetTitleIdSize**](/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfiggettitleidsize) first to determine the buffer size.             |

### Duplicating a handle

Use [**PFServiceConfigDuplicateHandle**](/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfigduplicatehandle) when you need to share a service config across components that manage their own lifetimes:

```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);
```

## Shutdown sequence

Shutdown is the reverse of initialization. You must uninitialize Services before Core, and both calls are asynchronous.

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

### Step 1: Close all open handles

Before tearing down the SDK, close every **PFEntityHandle** and **PFServiceConfigHandle** you own:

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

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

### Step 2: Uninitialize Services

[**PFServicesUninitializeAsync**](/services/playfab/api-references/c/pfservices/functions/pfservicesuninitializeasync) tears down the Services layer. Wait for it to complete before proceeding.

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

### Step 3: Uninitialize Core

After Services cleanup finishes, call [**PFUninitializeAsync**](/services/playfab/api-references/c/pfcore/functions/pfuninitializeasync) to tear down Core:

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

<Note>
  If you didn't call **PFInitialize** explicitly, you can skip **PFUninitializeAsync**. In that case, [**PFServicesUninitializeAsync**](/services/playfab/api-references/c/pfservices/functions/pfservicesuninitializeasync) handles Core cleanup automatically. However, if you did call **PFInitialize** yourself, you must call [**PFUninitializeAsync**](/services/playfab/api-references/c/pfcore/functions/pfuninitializeasync) yourself.
</Note>

## Complete example

This example shows the full lifecycle from initialization through shutdown on a Windows title:

```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);
}
```

## Common mistakes

| Mistake                                                                                                                                                                                                                                  | What happens                                                                       | Fix                                                                                                                                                                                                                   |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Calling [**PFMemSetFunctions**](/services/playfab/api-references/c/pfplatform/functions/pfmemsetfunctions) after [**PFInitialize**](/services/playfab/api-references/c/pfcore/functions/pfinitialize)                                    | The call fails. Memory hooks can only be set before initialization.                | Move [**PFMemSetFunctions**](/services/playfab/api-references/c/pfplatform/functions/pfmemsetfunctions) to the very first PlayFab call in your program.                                                               |
| Calling [**PFUninitializeAsync**](/services/playfab/api-references/c/pfcore/functions/pfuninitializeasync) before [**PFServicesUninitializeAsync**](/services/playfab/api-references/c/pfservices/functions/pfservicesuninitializeasync) | Undefined behavior. Core is torn down while Services still depends on it.          | Always uninitialize Services first, wait for completion, then uninitialize Core.                                                                                                                                      |
| Forgetting to call [**PFUninitializeAsync**](/services/playfab/api-references/c/pfcore/functions/pfuninitializeasync) after explicit [**PFInitialize**](/services/playfab/api-references/c/pfcore/functions/pfinitialize)                | Core resources leak. The background queue and HTTP layer aren't cleaned up.        | If you called [**PFInitialize**](/services/playfab/api-references/c/pfcore/functions/pfinitialize), you must call [**PFUninitializeAsync**](/services/playfab/api-references/c/pfcore/functions/pfuninitializeasync). |
| Not waiting for async uninitialize to complete                                                                                                                                                                                           | The process may exit while cleanup is still in progress, causing crashes or hangs. | Use `XAsyncGetStatus(async, true)` or an **XAsyncBlock** callback to wait for completion.                                                                                                                             |
| Leaking **PFServiceConfigHandle** or **PFEntityHandle**                                                                                                                                                                                  | Ref-counted resources aren't freed and may prevent clean shutdown.                 | Close every handle you create or duplicate before calling uninitialize.                                                                                                                                               |

## See also

* [Quickstart: Win32](/services/playfab/sdks/c/quickstart-win32)
* [Quickstart: Windows](/services/playfab/sdks/c/quickstart-gdk)
* [Debug Tracing](/services/playfab/sdks/c/tracing)
* [Asynchronous Programming Model](https://learn.microsoft.com/en-us/gaming/gdk/_content/gc/system/overviews/async-programming-model)


## Related topics

- [Entity Handles](/services/playfab/sdks/c/entity-handles.md)
- [Lifecycle of a multiplayer server](/services/playfab/multiplayer/servers/multiplayer-game-server-lifecycle.md)
- [Lifecycle of multiplayer server builds](/services/playfab/multiplayer/servers/multiplayer-build-lifecycle.md)
- [PlayFab Services SDK - Event Pipeline](/services/playfab/sdks/c/event-pipeline/eventpipeline.md)
- [Lifecycle of a multiplayer server build region](/services/playfab/multiplayer/servers/multiplayer-build-region-lifecycle.md)
