2022/06/03

.NET 5でのアプリの更新

Microsoftストアで公開したアプリはストアのAPIを使って更新できますが、.NET 5以降は変わった点があるので、メモしておきます。 更新の際に出るダイアログのために、このオーナーとなるWindowを先に登録する必要がありますが、これは.NET 5より以前は以下のようなものでした。
[ComImport]
[Guid("3E68D4BD-7135-4D10-8018-9FB6D9F33FA1")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IInitializeWithWindow
{
void Initialize(IntPtr hwnd);
}
public void SetOwnerWindow(StoreContext context, Window window)
{
var handle = new WindowInteropHelper(window).Handle;
var initWindow = (IInitializeWithWindow)(object)context;
initWindow.Initialize(handle);
}
見てのとおり、COMのIInitializeWithWindowを定義しておいて、StoreContextのインスタンスをこれにキャストするものですが、.NET 5以降はInvalidCastExceptionが出て実行できなくなります。

このための修正としては、usingにWinRTを加えた上でAsでIInitializeWithWindowキャストする。
// using WinRT;
public void SetOwnerWindow(StoreContext context, Window window)
{
var handle = new WindowInteropHelper(window).Handle;
var initWindow = context.As<IInitializeWithWindow>();
initWindow.Initialize(handle);
}
もしくは、WinRT.Interop.InitializeWithWindow.Initializeを使う。これが公式に出ている方法で、StoreContextをキャストする必要がなく、したがってCOMの定義も要らなくなるので、やるならこちらだと思います。
// using WinRT.Interop;
public void SetOwnerWindow(StoreContext context, Window window)
{
var handle = new WindowInteropHelper(window).Handle;
InitializeWithWindow.Initialize(context, handle);
}
これを含めた更新のためのヘルパークラスの全体は以下のようになります。
using System;
using System.Net.NetworkInformation;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Interop;
using Windows.Services.Store;
using WinRT.Interop;
internal static class StoreHelper
{
/// <summary>
/// Checks if updated packages are available.
/// </summary>
/// <returns>True if available</returns>
/// <remarks>
/// If the packages are installed locally or published but as Package flights, this method
/// will not work correctly.
/// </remarks>
public static async Task<bool> CheckUpdateAsync()
{
if (!NetworkInterface.GetIsNetworkAvailable())
return false;
var context = StoreContext.GetDefault();
try
{
var updates = await context.GetAppAndOptionalStorePackageUpdatesAsync();
return (updates.Count > 0);
}
catch
{
return false;
}
}
/// <summary>
/// Proceeds to download and install updated packages.
/// </summary>
/// <param name="window">Owner window</param>
/// <returns>True if successfully finished downloading and installing</returns>
public static async Task<bool> ProceedUpdateAsync(Window window)
{
if (window is null)
throw new ArgumentNullException(nameof(window));
if (!NetworkInterface.GetIsNetworkAvailable())
return false;
var context = StoreContext.GetDefault();
try
{
var updates = await context.GetAppAndOptionalStorePackageUpdatesAsync();
if (updates.Count == 0)
return false;
SetOwnerWindow(context, window);
var result = await context.RequestDownloadAndInstallStorePackageUpdatesAsync(updates);
return (result.OverallState == StorePackageUpdateState.Completed);
}
catch
{
return false;
}
}
private static void SetOwnerWindow(StoreContext context, Window window)
{
var handle = new WindowInteropHelper(window).Handle;
InitializeWithWindow.Initialize(context, handle);
}
}
view raw StoreHelper.cs hosted with ❤ by GitHub

0 コメント :