如何使用 "Project Centennial converter" 从转换为 UWP 的 Win32 应用访问 Windows.Services.Store 命名空间以启用应用内购买?

How to access Windows.Services.Store namespace from a Win32 app converted to UWP with the "Project Centennial converter" to enable in-app purchases?

我有一个在 VS 2008 中开发的本机 C++/MFC 应用程序,没有 .NET 内容,我使用 Project Centennial converter 将其转换为 UWP 应用程序。所以现在我有一个 .appx 包作为 UWP 应用程序在 Windows 10 v 1607 中运行。

我的下一个目标是在提交到 Windows 商店之前添加应用内购买支持。

但问题是如何通过本机 C 或 C++ 代码从纯 Win32 应用程序访问 Windows.Services.Store 命名空间?

使用 WRL。以下是有关如何购买应用内购买的示例:

#include <windows.h>
#include <Windows.Services.Store.h>
#include <wrl.h>

using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::Services::Store;
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;

#define CheckHr(hr) do { if (FAILED(hr)) __debugbreak(); } while (false)

const wchar_t kItemFriendlyName[] = L"10 coins";
const wchar_t kItemStoreId[] = L"ten_coins";

void OnPurchaseOperationDone(IAsyncOperation<StorePurchaseResult*>* operation, AsyncStatus status);

void Purchase10Coins()
{
    ComPtr<IStoreContextStatics> storeContextStatics;
    auto hr = RoGetActivationFactory(HStringReference(L"Windows.Services.Store.StoreContext").Get(), __uuidof(storeContextStatics), &storeContextStatics);
    CheckHr(hr);

    ComPtr<IStoreContext> storeContext;
    hr = storeContextStatics->GetDefault(&storeContext);
    CheckHr(hr);

    ComPtr<IStorePurchasePropertiesFactory> purchasePropertiesFactory;
    hr = RoGetActivationFactory(HStringReference(L"Windows.Services.Store.StorePurchaseProperties").Get(), __uuidof(purchasePropertiesFactory), &purchasePropertiesFactory);
    CheckHr(hr);

    ComPtr<IStorePurchaseProperties> purchaseProperties;
    hr = purchasePropertiesFactory->Create(HStringReference(kItemFriendlyName).Get(), &purchaseProperties);
    CheckHr(hr);

    ComPtr<IAsyncOperation<StorePurchaseResult*>> purchaseOperation;
    hr = storeContext->RequestPurchaseWithPurchasePropertiesAsync(HStringReference(kItemStoreId).Get(), purchaseProperties.Get(), &purchaseOperation);
    CheckHr(hr);

    // Change the following line to call Callback<IAsyncOperationCompletedHandler<StorePurchaseResult*>> if you want the callback to happen back on the UI thread
    // Implementing FtmBase allows it to fire on the thread the operation finished
    auto onCompletedCallback = Callback<Implements<RuntimeClassFlags<ClassicCom>, IAsyncOperationCompletedHandler<StorePurchaseResult*>, FtmBase>>(
        [](IAsyncOperation<StorePurchaseResult*>* operation, AsyncStatus status)
    {
        OnPurchaseOperationDone(operation, status);
        return S_OK;
    });

    hr = purchaseOperation->put_Completed(onCompletedCallback.Get());
    CheckHr(hr);
}

void OnPurchaseOperationDone(IAsyncOperation<StorePurchaseResult*>* operation, AsyncStatus status)
{
    if (status != AsyncStatus::Completed)
    {
        // It failed for some reason. Find out why.
        ComPtr<IAsyncInfo> asyncInfo;
        auto hr = operation->QueryInterface(__uuidof(asyncInfo), &asyncInfo);
        CheckHr(hr);

        HRESULT errorCode;
        hr = asyncInfo->get_ErrorCode(&errorCode);
        CheckHr(hr);

        // Do something with the errorCode


        // Return once error is handled
        return;
    }

    ComPtr<IStorePurchaseResult> purchaseResult;
    auto hr = operation->GetResults(&purchaseResult);
    CheckHr(hr);

    StorePurchaseStatus purchaseStatus;
    hr = purchaseResult->get_Status(&purchaseStatus);
    CheckHr(hr);

    switch (purchaseStatus)
    {
    case StorePurchaseStatus_Succeeded:
    case StorePurchaseStatus_AlreadyPurchased:
        // Success. Product was purchased
        break;

    case StorePurchaseStatus_NotPurchased:
        // User canceled the purchase
        break;

    case StorePurchaseStatus_NetworkError:
        // The device could not reach windows store
        break;

    case StorePurchaseStatus_ServerError:
        // Something broke on the server
        break;
    }
}

检查应用程序是否处于试用状态的方法如下:

void CheckIsTrial(std::function<void(bool)> onCompleted)
{
    ComPtr<IStoreContextStatics> storeContextStatics;
    auto hr = RoGetActivationFactory(HStringReference(L"Windows.Services.Store.StoreContext").Get(), __uuidof(storeContextStatics), &storeContextStatics);
    CheckHr(hr);

    ComPtr<IStoreContext> storeContext;
    hr = storeContextStatics->GetDefault(&storeContext);
    CheckHr(hr);

    ComPtr<IAsyncOperation<StoreAppLicense*>> getLicenseOperation;
    hr = storeContext->GetAppLicenseAsync(&getLicenseOperation);
    CheckHr(hr);

    hr = getLicenseOperation->put_Completed(Callback<Implements<RuntimeClassFlags<ClassicCom>, IAsyncOperationCompletedHandler<StoreAppLicense*>, FtmBase>>(
        [onCompleted{ std::move(onCompleted) }](IAsyncOperation<StoreAppLicense*>* operation, AsyncStatus status)
    {
        if (status != AsyncStatus::Completed)
        {
            // It failed for some reason. Find out why.
            ComPtr<IAsyncInfo> asyncInfo;
            auto hr = operation->QueryInterface(__uuidof(asyncInfo), &asyncInfo);
            CheckHr(hr);

            HRESULT errorCode;
            hr = asyncInfo->get_ErrorCode(&errorCode);
            CheckHr(hr);

            // Do something with the errorCode

            // Return once error is handled
            return S_OK;
        }

        ComPtr<IStoreAppLicense> appLicense;
        auto hr = operation->GetResults(&appLicense);
        CheckHr(hr);

        boolean isActive, isTrial = false;

        hr = appLicense->get_IsActive(&isActive);
        CheckHr(hr);

        if (isActive)
        {
            hr = appLicense->get_IsTrial(&isTrial);
            CheckHr(hr);
        }

        onCompleted(static_cast<bool>(isActive));
        return S_OK;
    }).Get());
    CheckHr(hr);
}

看这里:https://msdn.microsoft.com/en-us/library/windows/apps/Windows.Services.Store.StoreContext.aspx

它指出:

Note  In a Windows desktop application that uses the Desktop Bridge, you must add some additional code to configure the StoreContext object before your app can use this object. For more information, see Using the StoreContext class in a desktop application that uses the Desktop Bridge. https://msdn.microsoft.com/windows/uwp/monetize/in-app-purchases-and-trials#desktop

经过以下更改,这对我来说编译并工作:

1) #include <utility.h>

2) 编写一个 onCompleted 处理程序:

void onCompleted(bool bActiveLicense)
{
//     App has active license or not
}

3) 更改捕获如下:

[=, onCompleted{ std::move(onCompleted) }]