> ## Documentation Index
> Fetch the complete documentation index at: https://docs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 1 つのアプリケーションで複数の GameInput API バージョンを使用する

> QueryInterface を使用して、v0 と v4 など、異なる GameInput API バージョンを同じアプリケーションで組み合わせる方法について説明します。

v0 から v4 までの各 GameInput API バージョンは、独自の COM インターフェイスのセットを定義します。GameInput ランタイムは、同じ基盤となるオブジェクトですべてのバージョンを実装するため、デバイスなどの単一のオブジェクトには、v0 インターフェイス、v4 インターフェイス、およびその間の各バージョンのインターフェイスがあります。オブジェクトをあるバージョンから別のバージョンに切り替えるには、そのオブジェクトで [QueryInterface](https://docs.xbox.com/ja-jp/windows/win32/api/unknwn/nf-unknwn-iunknown-queryinterface\(refiid_void\)) を呼び出します。

これにより、次のことが可能になります。

* v0 などの以前の API バージョンに基づいて構築されたアプリケーションに、アプリケーション全体を一度に移行することなく v4 の機能を追加する。
* アプリケーションの残りの部分で v4 を使用している場合でも、以前のバージョンの GameInput に対してビルドされた SDK、ミドルウェア、またはエンジン プラグインを呼び出す。

## サポートされている API バージョン

GameInput ランタイムは、自身のメジャー バージョン以下のすべての API バージョンをサポートします。たとえば、GameInput 4.0 ランタイムがインストールされている場合、すべての GameInput オブジェクトは v0、v1、v2、v3、および v4 のインターフェイスを実装し、アプリケーションはそれらを任意に組み合わせて使用できます。

| インストールされているランタイム | 使用できる API バージョン |
| - | - |
| 4.x | v0、v1、v2、v3、v4 |
| 3.x | v0、v1、v2、v3 |
| 2.x | v0、v1、v2 |
| 1.x | v0、v1 |

インストールされているランタイムより新しい API バージョンを要求すると、`QueryInterface` と [GameInputInitialize](https://docs.xbox.com/ja-jp/reference/input/gameinput/functions/gameinputinitialize.md) は `E_NOINTERFACE` で失敗します。アプリケーションが使用する最も高い API バージョンによって、アプリケーションに必要な最小ランタイム バージョンが決まります。

PC では、インストールされているランタイムは、GameInput 再配布可能パッケージ、またはゲームと共に配置するランタイムです。詳細については、[GameInput NuGet パッケージ](https://docs.xbox.com/ja-jp/build/core-features/common/input/overviews/input-nuget.md) と [GameInput のサイドロード](https://docs.xbox.com/ja-jp/build/core-features/common/input/overviews/input-agility-redistributable.md) を参照してください。XBOX では、ランタイムは GDK に含まれており、より新しいランタイムをゲームと共に配置することもできます。詳細については、[XBOX 本体での GameInput](https://docs.xbox.com/ja-jp/build/core-features/common/input/overviews/input-xbox.md) を参照してください。

## プロジェクトをセットアップする

新しい実装では、最新の [Microsoft.GameInput](https://www.nuget.org/packages/Microsoft.GameInput) NuGet パッケージのヘッダーと `GameInput.lib` を使用します。パッケージでは、`<GameInput.h>` が最新のヘッダーであり、以前の各ヘッダーは `<v0/GameInput.h>` や `<v2/GameInput.h>` などのバージョン付きフォルダーにあります。ライブラリは [GameInputInitialize](https://docs.xbox.com/ja-jp/reference/input/gameinput/functions/gameinputinitialize.md) をエクスポートします。これは、要求された任意の API バージョンの GameInput を作成します。

GDK に含まれるものなど、以前のリリースのライブラリも引き続き動作します。詳細については、[以前のライブラリを維持する](#keep-an-earlier-library) を参照してください。

### v0 ヘッダーをインクルードする

v1 以降、各 GameInput ヘッダーは、`GameInput::v4` などのバージョン付き名前空間でその型を宣言します。一方、v0 ヘッダーはグローバル名前空間で型を宣言します。v0 ヘッダーを最新のヘッダーと一緒に使用するには、`GameInputV0.h` などの独自のヘッダーに次の定型コードを記述します。

```cpp theme={null}
// GameInputV0.h: declares the v0 API in the GameInput::v0 namespace
#pragma once

#include <windows.h>
#include <GameInput.h>

// The v0 header isn't namespaced; its dependencies are already included above.
namespace GameInput::v0
{
    // Prevent the legacy typedefs from finding interfaces declared by the latest header.
    struct IGameInput;
    struct IGameInputReading;
    struct IGameInputDevice;
    struct IGameInputDispatcher;
    struct IGameInputForceFeedbackEffect;
    struct IGameInputRawDeviceReport;

    #include <v0/GameInput.h>
}
```

このヘッダーは次のように動作します。

* 最初に最新の `<GameInput.h>` をインクルードします。これにより、最新の API が独自の名前空間で宣言され、v0 ヘッダーが依存する Windows ヘッダーと COM ヘッダーがインクルードされるため、v0 ヘッダーが名前空間内でそれらを再度インクルードすることはありません。
* 前方宣言により、v0 ヘッダー内の typedef は、最新のヘッダーで既に宣言されたインターフェイスを参照するのではなく、`GameInput::v0` に新しいインターフェイスを宣言します。
* 名前空間内で `<v0/GameInput.h>` をインクルードすると、`GameInput::v0::IGameInput` や `GameInput::v0::GameInputKindGamepad` のように、すべての v0 の型、列挙型、定数が `GameInput::v0` に移動します。

v0 のソース ファイルでは、`<GameInput.h>` の代わりに `GameInputV0.h` をインクルードし、既存のコードで修飾されていない名前を引き続き使用できるように `using namespace GameInput::v0;` を追加します。`GameInputV0.h` をインクルードするソース ファイルでは、`GameInput::v4::IGameInput` などの完全な名前を使用して最新の API を使用することもできます。

## 例: v0 アプリケーションに v4 の機能を追加する

v4 の機能を使い始めるために v0 のコードを書き直す必要はありません。v0 のコードは独自のソース ファイルに保持し、新しい v4 のコードは別のソース ファイルに記述します。2 つの間で GameInput オブジェクトを `IUnknown*` として受け渡し、それぞれの側で必要なバージョンの `QueryInterface` を呼び出します。

### 既存の v0 コード

次の v0 コードは、GameInput を作成してゲームパッドを読み取ります。元の v0 コードと比較して、変更点は次の 3 つだけです。

* `<GameInput.h>` の代わりに `GameInputV0.h` をインクルードします。
* 最新のライブラリは v0 の `GameInputCreate` 関数をエクスポートしないため、v0 の IID を指定して `GameInputInitialize` を呼び出すことで GameInput を作成します。
* A ボタンが押されたときに、新しい v4 コードを呼び出します。

```cpp theme={null}
// LegacyInput.cpp: existing code that uses the v0 API
#include "GameInputV0.h"

using namespace GameInput::v0;

// Implemented in NewInputFeatures.cpp.
void SetControllerColor(IUnknown* device);

IGameInput* g_gameInput = nullptr;

HRESULT InitializeInput()
{
    return GameInput::v4::GameInputInitialize(__uuidof(IGameInput), reinterpret_cast<void**>(&g_gameInput));
}

void UpdateGamepad()
{
    IGameInputReading* reading = nullptr;
    if (SUCCEEDED(g_gameInput->GetCurrentReading(GameInputKindGamepad, nullptr, &reading)))
    {
        GameInputGamepadState state;
        reading->GetGamepadState(&state);

        if (state.buttons & GameInputGamepadA)
        {
            IGameInputDevice* device = nullptr;
            reading->GetDevice(&device);
            SetControllerColor(device);
            device->Release();
        }

        reading->Release();
    }
}
```

### 新しい v4 コード

新しいソース ファイルは v4 ヘッダーをインクルードし、v0 コードから渡されたデバイスで `QueryInterface` を呼び出します。次に、v4 で新しく追加された [IGameInputDevice::SetLightingColor](https://docs.xbox.com/ja-jp/reference/input/gameinput/interfaces/igameinputdevice/methods/igameinputdevice_setlightingcolor.md) と [IGameInputDevice::ApplyLightingColors](https://docs.xbox.com/ja-jp/reference/input/gameinput/interfaces/igameinputdevice/methods/igameinputdevice_applylightingcolors.md) を使用して、コントローラーのセンター ライトの色を変更します。デバイスにセンター ライトがない場合、この呼び出しは無視されます。

```cpp theme={null}
// NewInputFeatures.cpp: new code that uses the v4 API
#include <windows.h>
#include <v4/GameInput.h>

using namespace GameInput::v4;

void SetControllerColor(IUnknown* legacyDevice)
{
    IGameInputDevice* device = nullptr;

    // Fails with E_NOINTERFACE if the installed runtime is older than 4.0.
    if (SUCCEEDED(legacyDevice->QueryInterface(IID_PPV_ARGS(&device))))
    {
        device->SetLightingColor({ 0, 255, 0 }, GameInputLightingGroupCenterLight);
        device->ApplyLightingColors();
        device->Release();
    }
}
```

`QueryInterface` が失敗した場合、インストールされているランタイムは v4 をサポートしていません。v0 のコードは引き続き動作し、アプリケーションは v4 の機能をスキップできます。

すべてのコードで v4 を使用するようになったら、`GameInputV0.h` と `QueryInterface` の呼び出しを削除できます。

### 以前のライブラリを維持する

GDK に含まれるものなど、以前のリリースのライブラリを引き続きリンクする場合、既存の v0 コードを変更する必要はまったくありません。そのリリースの v0 ヘッダーのインクルードと `GameInputCreate` の呼び出しをそのまま続けます。この呼び出しはインストールされているランタイムに転送されるため、ランタイムが 4.0 以降の場合、返されるオブジェクトは v4 インターフェイスも実装し、前に示した新しい v4 コードは変更なしで動作します。

以前のライブラリは `GameInputInitialize` をエクスポートしません。v4 インターフェイスは `QueryInterface` を呼び出すことによってのみ取得し、`GameInputInitialize` を呼び出す v4 の `GameInputCreate` は呼び出さないでください。

## バージョン間の切り替えに関する規則

異なる API バージョンのインターフェイスは、`IGameInput` や `IGameInputDevice` などの同じ名前を持ちますが、メソッドが異なる別の型です。v0 インターフェイスへのポインターは、両方が同じオブジェクトを参照している場合でも、v4 インターフェイスへのポインターではありません。

> [!NOTE]
>
> キャストは `QueryInterface` の呼び出しと同じではありません。別の API バージョンのインターフェイスを取得するには、常に `QueryInterface` を使用してください。バージョン間の変換に `static_cast`、`reinterpret_cast`、または C スタイルのキャストを使用しないでください。キャストはコンパイルされますが、変換されたポインターを介してメソッドを呼び出すと間違ったメソッドが呼び出される可能性があり、未定義の動作につながります。

```cpp theme={null}
GameInput::v0::IGameInputDevice* legacyDevice = /* ... */;

// Wrong: compiles, but calls the wrong methods at run time.
auto badDevice = reinterpret_cast<GameInput::v4::IGameInputDevice*>(legacyDevice);

// Correct: asks the object for its v4 interface.
GameInput::v4::IGameInputDevice* device = nullptr;
HRESULT hr = legacyDevice->QueryInterface(IID_PPV_ARGS(&device));
```

また、次の規則にも留意してください。

* **v0 ヘッダーの後に別の GameInput ヘッダーをインクルードしないでください。** v0 ヘッダーは `GAMEINPUT_E_DEVICE_DISCONNECTED` などのエラー コードをマクロとして定義しており、これらのマクロにより、その後にインクルードされる GameInput ヘッダーの宣言が壊れます。`GameInputV0.h` は、最初に最新のヘッダーをインクルードすることでこの規則に従っています。
* **返されるオブジェクトは、呼び出したバージョンを使用します。** たとえば、v4 の読み取りで `GetDevice` を呼び出すと v4 のデバイスが返され、v4 の `IGameInput` に登録されたデバイス コールバックは v4 のデバイスを受け取ります。これらのオブジェクトを別のバージョンを使用するコードに渡す前に、`QueryInterface` を呼び出してください。
* **`QueryInterface` を呼び出すたびに参照が追加されます。** 他の COM インターフェイス ポインターと同様に、返されたポインターが不要になったら解放してください。
* **結果を確認してください。** 新しい API バージョンを要求した場合、失敗は、インストールされているランタイムがそのバージョンをサポートしていないことを意味します。
* **`GameInputV0.h` の v0 の型は、別個の C++ 型です。** `GameInput::v0::IGameInput` と、`<v0/GameInput.h>` 単体のグローバルな `IGameInput` は同じインターフェイスを表しますが、C++ ではこれらは異なる型として扱われます。既存のコードや別のライブラリがグローバルな v0 の型で関数を宣言している場合は、`<v0/GameInput.h>` のみをインクルードするソース ファイルからそれらの関数を呼び出してください。

## 以前の API バージョンを使用する SDK を呼び出す

一部の SDK、ミドルウェア、およびエンジン プラグインは、特定の GameInput API バージョンに対してビルドされており、そのバージョンの GameInput インターフェイスを想定しています。アプリケーションは、新しいバージョンを使用しながら、これらのコンポーネントを呼び出すことができます。`QueryInterface` を呼び出してコンポーネントが想定するバージョンを取得し、そのポインターを渡します。

この呼び出しは、コンポーネントが使用するものと同じ GameInput ヘッダーをインクルードするソース ファイルに記述します。次の例では、`ThirdPartySdk.h` が `ThirdPartySdkInitialize(GameInput::v2::IGameInput*)` を宣言しており、アプリケーションの残りの部分は GameInput オブジェクトを `IUnknown*` として渡します。

```cpp theme={null}
// SdkBridge.cpp: calls an SDK that was built against the v2 API
#include <windows.h>
#include <v2/GameInput.h>
#include "ThirdPartySdk.h"

HRESULT InitializeThirdPartySdk(IUnknown* gameInputObject)
{
    GameInput::v2::IGameInput* gameInput = nullptr;
    HRESULT hr = gameInputObject->QueryInterface(IID_PPV_ARGS(&gameInput));
    if (SUCCEEDED(hr))
    {
        ThirdPartySdkInitialize(gameInput);
        gameInput->Release();
    }

    return hr;
}
```

同じ方法は逆方向にも機能します。コンポーネントが以前のバージョンの GameInput オブジェクトをアプリケーションに渡す場合は、そのオブジェクトで `QueryInterface` を呼び出して v4 インターフェイスを取得します。

すべてのバージョンが同じオブジェクトによって実装されているため、SDK とアプリケーションはデバイス、読み取り、および状態を共有します。SDK の API バージョンも、インストールされているランタイムのバージョン以下である必要があります。

## 関連項目

[GameInput API のバージョン管理](https://docs.xbox.com/ja-jp/build/core-features/common/input/overviews/input-versioning.md)\
[GameInput NuGet パッケージ](https://docs.xbox.com/ja-jp/build/core-features/common/input/overviews/input-nuget.md)\
[GameInput のサイドロード](https://docs.xbox.com/ja-jp/build/core-features/common/input/overviews/input-agility-redistributable.md)\
[GameInputInitialize](https://docs.xbox.com/ja-jp/reference/input/gameinput/functions/gameinputinitialize.md)\
[GameInput API リファレンス](https://docs.xbox.com/ja-jp/reference/input/gameinput/gameinput_members.md)


## Related topics

- [GameInput API のバージョン管理](https://docs.xbox.com/ja-jp/build/core-features/common/input/overviews/input-versioning.md)
- [GameInputInitialize](https://docs.xbox.com/ja-jp/reference/input/gameinput/functions/gameinputinitialize.md)
- [XBOX 本体での GameInput](https://docs.xbox.com/ja-jp/build/core-features/common/input/overviews/input-xbox.md)
- [GameInputCreate](https://docs.xbox.com/ja-jp/reference/input/gameinput/functions/gameinputcreate.md)
- [IGameInput::EnableBackgroundInput](https://docs.xbox.com/ja-jp/reference/input/gameinput/interfaces/igameinput/methods/igameinput_enablebackgroundinput.md)
