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

# 하나의 애플리케이션에서 여러 GameInput API 버전 사용

> QueryInterface를 사용하여 v0과 v4 같은 서로 다른 GameInput API 버전을 같은 애플리케이션에서 함께 사용하는 방법을 알아봅니다.

v0부터 v4까지의 각 GameInput API 버전은 고유한 COM 인터페이스 세트를 정의합니다. GameInput 런타임은 모든 버전을 동일한 기본 개체에 구현하므로, 장치와 같은 단일 개체에는 v0 인터페이스, v4 인터페이스, 그리고 그 사이의 각 버전에 대한 인터페이스가 있습니다. 개체를 한 버전에서 다른 버전으로 전환하려면 해당 개체에서 [QueryInterface](https://learn.microsoft.com/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/ko/reference/input/gameinput/functions/gameinputinitialize.md)가 `E_NOINTERFACE`와 함께 실패합니다. 애플리케이션이 사용하는 가장 높은 API 버전에 따라 필요한 최소 런타임 버전이 결정됩니다.

PC에서 설치된 런타임은 GameInput 재배포 가능 패키지 또는 게임과 함께 배포하는 런타임입니다. 자세한 내용은 [GameInput NuGet 패키지](https://docs.xbox.com/ko/build/core-features/common/input/overviews/input-nuget.md) 및 [GameInput 사이드로딩](https://docs.xbox.com/ko/build/core-features/common/input/overviews/input-agility-redistributable.md)을 참조하세요. XBOX에서는 런타임이 GDK에 포함되어 있으며, 게임과 함께 더 최신 런타임을 배포할 수도 있습니다. 자세한 내용은 [XBOX 콘솔의 GameInput](https://docs.xbox.com/ko/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>`와 같이 버전별 폴더에 있습니다. 라이브러리는 요청한 모든 API 버전에 대해 GameInput을 생성하는 [GameInputInitialize](https://docs.xbox.com/ko/reference/input/gameinput/functions/gameinputinitialize.md)를 내보냅니다.

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 코드는 별도의 소스 파일에 넣으세요. 두 코드 간에 GameInput 개체를 `IUnknown*`으로 전달하고, 각 쪽에서 필요한 버전에 대해 `QueryInterface`를 호출하도록 합니다.

### 기존 v0 코드

다음 v0 코드는 GameInput을 생성하고 게임패드를 읽습니다. 원래 v0 코드와 비교하면 다음 세 가지만 변경됩니다.

* `<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/ko/reference/input/gameinput/interfaces/igameinputdevice/methods/igameinputdevice_setlightingcolor.md) 및 [IGameInputDevice::ApplyLightingColors](https://docs.xbox.com/ko/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/ko/build/core-features/common/input/overviews/input-versioning.md)\
[GameInput NuGet 패키지](https://docs.xbox.com/ko/build/core-features/common/input/overviews/input-nuget.md)\
[GameInput 사이드로딩](https://docs.xbox.com/ko/build/core-features/common/input/overviews/input-agility-redistributable.md)\
[GameInputInitialize](https://docs.xbox.com/ko/reference/input/gameinput/functions/gameinputinitialize.md)\
[GameInput API 참조](https://docs.xbox.com/ko/reference/input/gameinput/gameinput_members.md)


## Related topics

- [GameInputInitialize](https://docs.xbox.com/ko/reference/input/gameinput/functions/gameinputinitialize.md)
- [XBOX 콘솔의 GameInput](https://docs.xbox.com/ko/build/core-features/common/input/overviews/input-xbox.md)
- [GameInput 자주 묻는 질문](https://docs.xbox.com/ko/build/core-features/common/input/overviews/input-faq.md)
- [GameInput API 버전 관리](https://docs.xbox.com/ko/build/core-features/common/input/overviews/input-versioning.md)
- [IGameInput::EnableBackgroundInput](https://docs.xbox.com/ko/reference/input/gameinput/interfaces/igameinput/methods/igameinput_enablebackgroundinput.md)
