Skip to content

Instantly share code, notes, and snippets.

@gileli121
Last active November 14, 2023 08:34
Show Gist options
  • Save gileli121/3b6396677e9f5345aa43b59badb7ecb3 to your computer and use it in GitHub Desktop.
Save gileli121/3b6396677e9f5345aa43b59badb7ecb3 to your computer and use it in GitHub Desktop.
MS Store - Solution to scenario that software changed from PAID & 30 Days trial to FREE & 30 Days trial
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using WindowTop.Helpers;
namespace WindowTop
{
public class CacheEntity
{
protected void SetValue<T>(T value, ref T propertyValue)
{
if (value == null)
{
try
{
value = Activator.CreateInstance<T>();
}
catch
{
// ignored
}
}
if (value == null && propertyValue == null || (propertyValue != null && propertyValue.Equals(value)))
return;
propertyValue = value;
Cache.Save();
}
}
public class Cache
{
#region Struct info and helpers
static readonly AppLogger log = new AppLogger();
const string CACHE_FILENAME = "cache.json";
static string CacheFileName { get; set; }
public static Cache Values { get; private set; }
static bool disableAutoSave;
static readonly JsonSerializerOptions jsonSerializerOptions = new JsonSerializerOptions()
{
WriteIndented = true,
Converters =
{
new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)
}
};
public static void DisableAutoSave()
{
disableAutoSave = true;
}
public static void EnableAutoSave()
{
disableAutoSave = false;
}
public static void Save()
{
if (disableAutoSave) return;
if (Values == null)
Values = new Cache();
File.WriteAllText(CacheFileName,
JsonSerializer.Serialize(Values, jsonSerializerOptions), Encoding.UTF8);
}
public static void Load()
{
if (App.AppManager.IsInstalled)
{
var configFolder = Path.Combine(Environment.GetFolderPath(
Environment.SpecialFolder.ApplicationData), App.AppName);
if (!Directory.Exists(configFolder))
Directory.CreateDirectory(configFolder);
CacheFileName = Path.Combine(configFolder, CACHE_FILENAME);
}
else
{
CacheFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, CACHE_FILENAME);
}
// Lines below are only for debugging. Remove it after done!
// if (File.Exists(CacheFileName))
// File.Delete(CacheFileName);
// END
if (!File.Exists(CacheFileName))
Save();
DisableAutoSave();
try
{
Values = JsonSerializer.Deserialize<Cache>(File.ReadAllText(CacheFileName, Encoding.UTF8),
jsonSerializerOptions);
}
catch (Exception e)
{
log.Fatal(e);
log.Info($"Trying to recovery by recreating the file {CACHE_FILENAME}");
EnableAutoSave();
File.Delete(CacheFileName);
Save();
DisableAutoSave();
Values = JsonSerializer.Deserialize<Cache>(File.ReadAllText(CacheFileName, Encoding.UTF8),
jsonSerializerOptions);
}
finally
{
EnableAutoSave();
}
}
#endregion
public UwpActivationCacheType UwpActivationCache { get; set; } = new UwpActivationCacheType();
public class UwpActivationCacheType : CacheEntity
{
bool isLicenseCached;
public bool
IsLicenseCached
{
get => isLicenseCached;
set => SetValue(value, ref isLicenseCached);
}
bool isFullVersion;
public bool IsFullVersion
{
get => isFullVersion;
set => SetValue(value, ref isFullVersion);
}
bool isTrialMode;
public bool IsTrialMode
{
get => isTrialMode;
set => SetValue(value, ref isTrialMode);
}
int daysLeft;
public int DaysLeft
{
get => daysLeft;
set => SetValue(value, ref daysLeft);
}
bool isTrialModeAvailable;
public bool IsTrialModeAvailable
{
get => isTrialModeAvailable;
set => SetValue(value, ref isTrialModeAvailable);
}
DateTime? trialStartDate;
public DateTime? TrialStartDate
{
get => trialStartDate;
set => SetValue(value, ref trialStartDate);
}
}
}
}
using System;
using System.Threading.Tasks;
using System.Windows;
using WindowTop.DataUnits;
namespace WindowTop.Managers.ActivationManagers
{
public class LoadActivationStateResult
{
public bool IsActivationLoaded { get; set; }
public string LoadingFailureMessage { get; set; }
public bool IsActivationStateChanged { get; set; }
}
public interface IActivationManager
{
bool IsLicenseCached { get; }
bool IsFullVersion { get; }
bool IsTrialMode { get; }
int DaysLeft { get; }
int MaxDaysLeft { get; }
bool IsFreeModeAllowed { get; }
bool IsTrialModeAvailable { get; }
bool IsProductKeyMethod { get; }
bool SupportUnActivation { get; }
bool SupportResetActivation { get; }
Action<bool> OnActivationStateChanged { get; set; }
Task<LoadActivationStateResult> LoadActivationStateAsync();
void OpenPurchasePage();
Task<Result<bool>> RequestSetTrialModeAsync(Window ownerWindow = null); // Should return false on error
bool UpdateTrailMode(); // Should return true if the trial property changed
Task<Result<bool>> RequestPurchaseAppAsync(Window ownerWindow = null);
void RequestActivateProductKey(string productKey, Action onActivated,
Action<string> onFailActivate, Action<string> onIllegalActivation);
void RequestCleanActivateProductKey(string productKey, Action onSuccess, Action<string> onFailure);
void RequestDeActivate(Action onUnActivated, Action<string> onUnActivateFailed);
}
}
using System;
namespace WindowTop.DataUnits
{
public class Result<T>
{
public T Value { get; set; }
public string ErrorMessage { get; set; }
public Exception Exception { get; set; }
public bool IsFailed => Exception != null || ErrorMessage != null;
public Result(Exception e, T value) : this(value)
{
this.Exception = e;
this.ErrorMessage = e.Message;
}
public Result(string errorMessage, T value) : this(value)
{
this.ErrorMessage = errorMessage;
}
public Result(T value)
{
this.Value = value;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
namespace WindowTop.Managers.ActivationManagers.UwpActivationManager.Models.SkuExtendedJsonData
{
public class LegalText
{
public string Copyright { get; set; }
public string CopyrightUri { get; set; }
public string PrivacyPolicy { get; set; }
public string PrivacyPolicyUri { get; set; }
public string Tou { get; set; }
public string TouUri { get; set; }
}
public class LocalizedProperty
{
public string SkuDescription { get; set; }
public string SkuTitle { get; set; }
public string SkuButtonTitle { get; set; }
public List<object> SkuDisplayRank { get; set; }
public LegalText LegalText { get; set; }
public string Language { get; set; }
}
public class Properties
{
public string FulfillmentType { get; set; }
public List<object> BundledSkus { get; set; }
public bool IsRepurchasable { get; set; }
public int SkuDisplayRank { get; set; }
public bool IsTrial { get; set; }
}
public class CollectionData
{
public DateTime acquiredDate { get; set; }
public bool autoRenew { get; set; }
public List<object> additionalIds { get; set; }
public List<object> effectiveBeneficiaries { get; set; }
public DateTime endDate { get; set; }
public List<object> externalReferences { get; set; }
public List<object> fulfillmentData { get; set; }
public bool isCacheable { get; set; }
public string itemId { get; set; }
public string localTicketReference { get; set; }
public DateTime modifiedDate { get; set; }
public List<object> musicTracksInfo { get; set; }
public string orderId { get; set; }
public string orderLineItemId { get; set; }
public string ownershipType { get; set; }
public string productFamily { get; set; }
public string productId { get; set; }
public string productKind { get; set; }
public string productTitleId { get; set; }
public string purchasedCountry { get; set; }
public int quantity { get; set; }
public string skuId { get; set; }
public string skuType { get; set; }
public DateTime startDate { get; set; }
public string status { get; set; }
public List<object> tags { get; set; }
public string transactionId { get; set; }
}
public class Sku
{
public List<LocalizedProperty> LocalizedProperties { get; set; }
public Properties Properties { get; set; }
public string SkuId { get; set; }
public object RecurrencePolicy { get; set; }
public CollectionData CollectionData { get; set; }
}
public class Conditions
{
public DateTime EndDate { get; set; }
}
public class Price
{
public string CurrencyCode { get; set; }
public int ListPrice { get; set; }
public int MSRP { get; set; }
}
public class OrderManagementData
{
public Price Price { get; set; }
}
public class Availability
{
public List<string> Actions { get; set; }
public string AvailabilityId { get; set; }
public Conditions Conditions { get; set; }
public OrderManagementData OrderManagementData { get; set; }
public int DisplayRank { get; set; }
public bool RemediationRequired { get; set; }
}
public class SkuExtendedJsonData
{
public Sku Sku { get; set; }
public List<Availability> Availabilities { get; set; }
public static SkuExtendedJsonData GetFromJson(string json)
{
return JsonSerializer.Deserialize<SkuExtendedJsonData>(json);
}
}
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Interop;
using Windows.Services.Store;
using Unclassified.TxLib;
using WindowTop.DataUnits;
using WindowTop.Helpers;
using WindowTop.Managers.ActivationManagers.UwpActivationManager.Models.SkuExtendedJsonData;
namespace WindowTop.Managers.ActivationManagers.UwpActivationManager
{
public class UwpActivationManager : IActivationManager
{
static readonly AppLogger log = new AppLogger();
// TODO: This should match the store product id that defined in the Package.StoreAssociation.xml
const string STORE_PRODUCT_ID = "XXXXXXXXXXXX"; // Use your own product id here
const string STORE_SHORTCUT_LINK = "ms-windows-store://pdp/?ProductId=XXXXXXXXXXXX"; // Use your own product id here
const string STORE_PRO_ADDON_ID = "XXXXXXXXXXXX"; // Use your pro addon id here here
const string STORE_TRIAL_ADDON_ID = "XXXXXXXXXXXX"; // Use your trial addon id here here
public bool IsLicenseCached { get; private set; }
public bool IsFullVersion { get; private set; }
public bool IsTrialMode { get; private set; }
public int DaysLeft { get; private set; }
public int MaxDaysLeft => 30;
public bool IsFreeModeAllowed => true;
public DateTime? TrialStartDate { get; private set; }
public bool IsTrialModeAvailable { get; private set; }
public bool IsProductKeyMethod => false;
public bool SupportUnActivation => false;
public bool SupportResetActivation => false;
public Action<bool> OnActivationStateChanged { get; set; }
public UwpActivationManager()
{
if (Cache.Values.UwpActivationCache.IsLicenseCached)
{
IsTrialModeAvailable = Cache.Values.UwpActivationCache.IsTrialModeAvailable;
TrialStartDate = Cache.Values.UwpActivationCache.TrialStartDate;
IsTrialMode = Cache.Values.UwpActivationCache.IsTrialMode;
IsFullVersion = Cache.Values.UwpActivationCache.IsFullVersion;
DaysLeft = Cache.Values.UwpActivationCache.DaysLeft;
IsLicenseCached = true;
}
}
async Task StoreContextOnOfflineLicensesChangedAsync()
{
var activationStateResult = await LoadActivationStateAsync();
if (!activationStateResult.IsActivationLoaded)
log.Error(
$"Failed to refresh activation state on StoreContextOnOfflineLicensesChangedAsync event. Error {activationStateResult.LoadingFailureMessage}");
}
void StoreContextOnOfflineLicensesChanged_EventHandler(StoreContext sender, object args)
{
StoreContextOnOfflineLicensesChangedAsync().GetAwaiter().GetResult();
}
static async Task<List<StoreProduct>> GetAllDurableAddonsAsync(StoreContext storeContext = null)
{
if (storeContext == null)
{
storeContext = UwpStoreContextManager.GetStoreContextForApp(IntPtr.Zero);
if (storeContext == null)
{
log.Error("Failure in GetAllDurableAddonsAsync. Failed to get storeContext instance");
return null;
}
}
var addonsRequest = await storeContext.GetAssociatedStoreProductsAsync(new[] {"Durable"});
if (addonsRequest.ExtendedError != null)
{
log.Error(
$"Failure in GetAllDurableAddonsAsync. Failed to get list of addons. Error: {addonsRequest.ExtendedError.Message}");
return null;
}
if (addonsRequest.Products == null)
{
log.Error("Failure in GetAllDurableAddonsAsync. No products returned");
return null;
}
return addonsRequest.Products.Values.ToList();
}
static async Task<bool> GetIsAppLegacyPurchasedAsync(StoreContext storeContext)
{
var maxLegacyPurchaseDate = DateTime.ParseExact(
"2021-09-21", // Change this value as needed. From this date, the app become free and the full functionality moved to addon
"yyyy-MM-dd",
null)
.ToUniversalTime();
var storeProductRequest = await storeContext.GetStoreProductForCurrentAppAsync();
if (storeProductRequest.ExtendedError != null)
{
log.Error(
$"Failure in GetIsAppLegacyPurchasedAsync() method. Error: {storeProductRequest.ExtendedError.Message}");
return false;
}
var storeProduct = storeProductRequest.Product;
if (storeProduct == null)
{
log.Error("Failure in GetIsAppLegacyPurchasedAsync(). storeProduct returned null");
return false;
}
if (storeProduct.Skus == null)
{
log.Error("Failure in GetIsAppLegacyPurchasedAsync(). Skus is null");
return false;
}
foreach (var storeProductSku in storeProduct.Skus)
{
SkuExtendedJsonData skuData;
try
{
skuData = SkuExtendedJsonData.GetFromJson(storeProductSku.ExtendedJsonData);
}
catch (Exception e)
{
log.Error(
$"Failure in GetIsAppLegacyPurchasedAsync(). Failed to parse skuData. Error: {e.Message}");
continue;
}
if (skuData.Sku == null)
continue;
if (skuData.Sku.CollectionData == null)
continue;
var cd = skuData.Sku.CollectionData;
var isLegacyPurchase =
cd.productId == STORE_PRODUCT_ID &&
cd.skuType == "Full" &&
cd.status == "Active" &&
cd.acquiredDate <= maxLegacyPurchaseDate;
if (isLegacyPurchase)
return true;
}
return false;
}
static DateTime? GetTrialStartDate(StoreProduct trialAddon)
{
if (trialAddon.Skus == null)
{
log.Error("Failure in GetTrialStartDate. trialAddon.Skus is null");
return null;
}
DateTime? firstTimeDate = null;
foreach (var trialAddonSku in trialAddon.Skus)
{
SkuExtendedJsonData skuData;
try
{
skuData = SkuExtendedJsonData.GetFromJson(trialAddonSku.ExtendedJsonData);
}
catch (Exception e)
{
log.Error(
$"Failure in GetTrialStartDate(). Failed to parse skuData. Error: {e.Message}");
continue;
}
if (skuData.Sku?.CollectionData == null)
continue;
var cd = skuData.Sku.CollectionData;
if (
cd.productId == trialAddon.StoreId &&
cd.skuType == "Full" &&
cd.status == "Active" &&
(firstTimeDate == null || cd.acquiredDate < firstTimeDate))
{
firstTimeDate = cd.acquiredDate;
}
}
if (firstTimeDate == null)
{
log.Error("Failure in GetTrialStartDate(). firstTimeDate is null");
return null;
}
return firstTimeDate;
}
async Task<bool> CalculateTrialModeAsync(StoreProduct trialAddon = null)
{
if (trialAddon == null)
{
var allAddons = await GetAllDurableAddonsAsync();
if (allAddons == null)
{
log.Error("Failure in CalculateTrialModeAsync. allAddons returned as null");
return false;
}
trialAddon = allAddons.FirstOrDefault(a => a.StoreId == STORE_TRIAL_ADDON_ID);
}
if (trialAddon == null)
{
log.Error("Failure in CalculateTrialModeAsync. trialAddon is null");
return false;
}
if (trialAddon.IsInUserCollection)
{
log.Info("Trial addon is in the user collection");
var trialStartDate = GetTrialStartDate(trialAddon);
if (trialStartDate == null)
{
log.Error(
$"Failed to int daysLeft property from trialAddon.");
return false;
}
TrialStartDate = trialStartDate;
IsTrialModeAvailable = false;
UpdateTrailMode();
if (!IsTrialMode)
log.Info(
$"Trial time already passed. So it is disabled, and IsFullVersion property is: {IsFullVersion}");
}
else
{
log.Info("Trial addon is not in the user collection");
IsTrialMode = false;
IsTrialModeAvailable = true;
}
return true;
}
public async Task<LoadActivationStateResult> LoadActivationStateAsync()
{
var o = new LoadActivationStateResult();
// Get the store context
var storeContext = UwpStoreContextManager.GetStoreContextForApp(IntPtr.Zero);
if (storeContext == null)
{
log.Error(
"Failure in LoadActivationStateAsync. Failed to get storeContext object in UwpActivationManager");
o.LoadingFailureMessage = log.LastLog;
return o;
}
// Set up OnOfflineLicensesChanged_EventHandler only once (make sure we added it once)
storeContext.OfflineLicensesChanged -= StoreContextOnOfflineLicensesChanged_EventHandler;
storeContext.OfflineLicensesChanged += StoreContextOnOfflineLicensesChanged_EventHandler;
var oldIsFullVersion = IsFullVersion;
var oldIsTrialMode = IsTrialMode;
if (await GetIsAppLegacyPurchasedAsync(storeContext))
{
log.Info("Detected legacy puchase");
IsFullVersion = true;
IsTrialMode = false;
}
else
{
log.Info("No legacy purchase detected");
var allAddons = await GetAllDurableAddonsAsync(storeContext);
if (allAddons == null)
{
log.Error("Failure in LoadActivationStateAsync. Failed to get addons list. it returned as null");
o.LoadingFailureMessage = log.LastLog;
return o;
}
var proAddon = allAddons.FirstOrDefault(a => a.StoreId == STORE_PRO_ADDON_ID);
if (proAddon == null)
{
log.Error("Failure in LoadActivationStateAsync. Failed to get proAddon. It returned as null");
o.LoadingFailureMessage = log.LastLog;
return o;
}
if (proAddon.IsInUserCollection)
{
log.Info("Pro addon is in the user collection");
IsFullVersion = true;
IsTrialMode = false;
IsTrialModeAvailable = false;
}
else
{
log.Info("Pro addon is not in the user collection");
var trialAddon = allAddons.FirstOrDefault(a => a.StoreId == STORE_TRIAL_ADDON_ID);
if (trialAddon == null)
{
log.Error("Failure in LoadActivationStateAsync. Failed to get trialAddon. It returned as null");
o.LoadingFailureMessage = log.LastLog;
return o;
}
if (!await CalculateTrialModeAsync(trialAddon))
{
log.Error(
"Failure in LoadActivationStateAsync. There is failure in CalculateTrialModeAsync method.");
o.LoadingFailureMessage = log.LastLog;
return o;
}
IsFullVersion = IsTrialMode;
}
}
// // TODO: This is for testing only! Remove this later!!!
// IsTrialMode = true;
// IsFullVersion = true;
// SaveLicenseToCache();
// // ENDOF TODO
SaveLicenseToCache();
o.IsActivationLoaded = true;
o.IsActivationStateChanged = oldIsFullVersion != IsFullVersion || oldIsTrialMode != IsTrialMode;
log.Info(
$"License state: IsFullVersion={IsFullVersion}, IsTrialMode={IsTrialMode}, IsActivationStateChanged={o.IsActivationStateChanged}");
return o;
}
public void OpenPurchasePage()
{
Process.Start(STORE_SHORTCUT_LINK);
}
public async Task<Result<bool>> RequestSetTrialModeAsync(Window ownerWindow = null)
{
var result = await RequestGetProductAsync(STORE_TRIAL_ADDON_ID, ownerWindow);
if (result.IsFailed)
{
log.Error(
$"Failure in RequestSetTrialModeAsync. Basic failure in RequestGetProductAsync. Error: {result.ErrorMessage}");
return new Result<bool>(log.LastLog, false);
}
if (result.Value.ExtendedError != null)
{
log.Error(
$"Failure in RequestSetTrialModeAsync. API failure in RequestGetProductAsync. Error: {result.Value.ExtendedError.Message}");
return new Result<bool>(log.LastLog, false);
}
var requestResult = result.Value;
log.Info($"requestResult.Status={requestResult.Status}");
async Task HandleTrialModeOwnedEvent()
{
var oldIsTrialMode = IsTrialMode;
await CalculateTrialModeAsync();
if (IsTrialMode)
IsFullVersion = IsTrialMode;
SaveLicenseToCache();
OnActivationStateChanged?.Invoke(oldIsTrialMode != IsTrialMode);
}
switch (requestResult.Status)
{
case StorePurchaseStatus.AlreadyPurchased:
{
App.ToastManager.ShowError(Tx.T("The trial period already started for this product"));
await HandleTrialModeOwnedEvent();
return new Result<bool>(true);
}
case StorePurchaseStatus.Succeeded:
{
await HandleTrialModeOwnedEvent();
return new Result<bool>(true);
}
case StorePurchaseStatus.NotPurchased:
{
App.ToastManager.ShowNotification(
Tx.T("The trial period was not started_ it may have been canceled"));
return new Result<bool>(true);
}
case StorePurchaseStatus.NetworkError:
{
var failureReason = Tx.T("The trial period was not started due to a Network Error");
App.ToastManager.ShowError(failureReason);
return new Result<bool>(failureReason, false);
}
case StorePurchaseStatus.ServerError:
{
var failureReason = Tx.T("The trial period was not started due to a Server Error");
App.ToastManager.ShowError(failureReason);
return new Result<bool>(failureReason, false);
}
default:
{
var failureReason = Tx.T("The trial period was not started due to an Unknown Error");
App.ToastManager.ShowError(failureReason);
return new Result<bool>(failureReason, false);
}
}
// throw new NotImplementedException(
// "In UWP you never should be able to set trial mode from within the software." +
// "If you got this error, it is bug, contact the developer for support");
}
public bool UpdateTrailMode()
{
if (TrialStartDate == null)
{
log.Error("Can't calculate days left because the TrialStartDate is null");
return false;
}
var daysPassed = (DateTime.Now - TrialStartDate).Value.Days;
DaysLeft = MaxDaysLeft - daysPassed;
log.Info($"Calculated trial days. daysPassed={daysPassed}, daysLeft={DaysLeft}");
var oldIsTrialMode = IsTrialMode;
IsTrialMode = DaysLeft > 0;
IsFullVersion = IsTrialMode;
return oldIsTrialMode != IsTrialMode;
}
static async Task<Result<StorePurchaseResult>> RequestGetProductAsync(string productId, Window ownerWindow = null)
{
var ownerWindowPtr = IntPtr.Zero;
if (ownerWindow != null)
ownerWindowPtr = new WindowInteropHelper(ownerWindow).EnsureHandle();
var storeContext = UwpStoreContextManager.GetStoreContextForApp(ownerWindowPtr);
if (storeContext == null)
{
log.Error("Failed to get storeContext object in UwpActivationManager");
return new Result<StorePurchaseResult>(log.LastLog, null);
}
var result = await storeContext.RequestPurchaseAsync(productId);
return new Result<StorePurchaseResult>(result);
}
public async Task<Result<bool>> RequestPurchaseAppAsync(Window ownerWindow = null)
{
var requestProduct = await RequestGetProductAsync(STORE_PRO_ADDON_ID, ownerWindow);
if (requestProduct.IsFailed)
{
log.Error($"Failed in RequestPurchaseAppAsync. Reason: {requestProduct.ErrorMessage}");
return new Result<bool>(log.LastLog, false);
}
var requestPurchaseResult = requestProduct.Value;
if (requestPurchaseResult.ExtendedError != null)
{
log.Error($"Failed in RequestPurchaseAsync. Error: {requestPurchaseResult.ExtendedError}");
return new Result<bool>(log.LastLog, false);
}
var oldIsFullVersion = IsFullVersion;
var oldIsTrialMode = IsTrialMode;
log.Info($"StorePurchaseStatus={requestPurchaseResult.Status}");
// License will refresh automatically using the StoreContext.OfflineLicensesChanged event
switch (requestPurchaseResult.Status)
{
case StorePurchaseStatus.AlreadyPurchased:
{
App.ToastManager.ShowError(Tx.T("TEXT_You already bought this app"));
IsFullVersion = true;
IsTrialMode = false;
SaveLicenseToCache();
OnActivationStateChanged?.Invoke(oldIsFullVersion != IsFullVersion ||
oldIsTrialMode != IsTrialMode);
return new Result<bool>(true);
}
case StorePurchaseStatus.Succeeded:
{
// License will refresh automatically using the StoreContext.OfflineLicensesChanged event
App.ToastManager.ShowSuccess(Tx.T("TEXT_Your purchase was successful"));
IsFullVersion = true;
IsTrialMode = false;
SaveLicenseToCache();
OnActivationStateChanged?.Invoke(oldIsFullVersion != IsFullVersion ||
oldIsTrialMode != IsTrialMode);
return new Result<bool>(true);
}
case StorePurchaseStatus.NotPurchased:
{
App.ToastManager.ShowNotification(
Tx.T("Product was not purchased_ it may have been canceled"));
return new Result<bool>(false);
}
case StorePurchaseStatus.NetworkError:
{
var failureReason = Tx.T("Product was not purchased due to a Network Error");
App.ToastManager.ShowError(failureReason);
return new Result<bool>(failureReason, false);
}
case StorePurchaseStatus.ServerError:
{
var failureReason = Tx.T("Product was not purchased due to a Server Error");
App.ToastManager.ShowError(failureReason);
return new Result<bool>(failureReason, false);
}
default:
{
var failureReason = Tx.T("Product was not purchased due to an Unknown Error");
App.ToastManager.ShowError(failureReason);
return new Result<bool>(failureReason, false);
}
}
}
public void RequestActivateProductKey(string productKey, Action onActivated,
Action<string> onFailActivate, Action<string> onIllegalActivation)
{
throw new NotImplementedException(
"This method (RequestActivateProductKey) should not be called in the current IActivationManager implementation" +
"because IsProductKeyMethod property is false. This is the UWP implementation of IActivationManager." +
"If you got this error, it is bug. contact the developer for support");
}
public void RequestDeActivate(Action onUnActivated, Action<string> onUnActivateFailed)
{
throw new NotImplementedException(
"This method (RequestDeActivate) should not be called in the current IActivationManager implementation" +
"because SupportUnActivation property is false.");
}
public void RequestCleanActivateProductKey(string productKey, Action onSuccess, Action<string> onFailure)
{
throw new NotImplementedException(
"This method (RequestCleanActivateProductKey) should not be called in the current IActivationManager implementation" +
"because SupportResetActivation property is false.");
}
void SaveLicenseToCache()
{
Cache.Values.UwpActivationCache.IsTrialModeAvailable = IsTrialModeAvailable;
Cache.Values.UwpActivationCache.TrialStartDate = TrialStartDate;
Cache.Values.UwpActivationCache.IsTrialMode = IsTrialMode;
Cache.Values.UwpActivationCache.IsFullVersion = IsFullVersion;
Cache.Values.UwpActivationCache.DaysLeft = DaysLeft;
Cache.Values.UwpActivationCache.IsLicenseCached = true;
IsLicenseCached = true;
}
}
}
using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using Windows.Services.Store;
using NLog;
namespace WindowTop.Managers
{
public class UwpStoreContextManager
{
static readonly Logger log = LogManager.GetCurrentClassLogger();
static IntPtr contextWinHandle = IntPtr.Zero;
public static StoreContext GetStoreContextForApp(IntPtr ownerWindow)
{
try
{
var storeContext = StoreContext.GetDefault();
var initWindow = (IInitializeWithWindow) (object) storeContext;
if (ownerWindow == IntPtr.Zero)
{
if (contextWinHandle == IntPtr.Zero)
{
contextWinHandle = new WindowInteropHelper(new Window()
{Topmost = true, WindowStartupLocation = WindowStartupLocation.CenterScreen})
.EnsureHandle();
}
ownerWindow = contextWinHandle;
}
initWindow.Initialize(ownerWindow);
return storeContext;
}
catch (Exception e)
{
// error = new LauncherException("An error has occured while loading the license information from Microsoft Store");
log.Error(
$"An error has occured while loading the license information from Microsoft Store. Exception: {e.Message}");
return null;
}
}
[ComImport]
[Guid("3E68D4BD-7135-4D10-8018-9FB6D9F33FA1")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IInitializeWithWindow
{
void Initialize(IntPtr hwnd);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment