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?
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);
}
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
With the following changes, this compiled and worked for me:
1) #include <utility.h>
2) write an onCompleted handler:
void onCompleted(bool bActiveLicense)
{
// App has active license or not
}
3) Change capture as follows:
[=, onCompleted{ std::move(onCompleted) }]