Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I have a native C++/MFC app that is developed in VS 2008, no .NET stuff, that I converted into a UWP app using the Project Centennial converter. So now I have an .appx package that runs in Windows 10 v 1607 as a UWP app.

My next goal is to add in-app purchase support before submission to Windows Store.

The question though is how do I access Windows.Services.Store namespace from a pure Win32 app from a native C or C++ code?

like image 989
c00000fd Avatar asked Sep 28 '16 22:09

c00000fd


2 Answers

Use WRL. Here's an example on how to purchase an in app purchase:

#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;
    }
}

Here's how to check if application is on trial:

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);
}
like image 115
Sunius Avatar answered Oct 08 '22 05:10

Sunius


See here: https://msdn.microsoft.com/en-us/library/windows/apps/Windows.Services.Store.StoreContext.aspx

It states:

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

like image 24
David Hollowell - MSFT Avatar answered Oct 08 '22 06:10

David Hollowell - MSFT