Windows Compatibility Packにより、.NET Standardではサポートされていない、.NET FrameworkのAPIが.NET Coreでも使えるようになる。
Windows Compatibility Pack for .NET Core(以下、Compatibility Pack)は、.NET Standard 2.0では規定されていない.NET FrameworkベースのAPIを.NET Coreプロジェクトで利用できるようにするNuGetパッケージ。ただし、Windows FormsやWPFなどはサポートされていない。また、本稿執筆時点(2017年11月20日)では、プレビュー段階のプロジェクトとなっている。
.NET Coreはクロスプラットフォームで動作する.NET実装であり、それがサポートするAPIは基本的には.NET Standardに準拠している。例えば、.NET Core 2.0は.NET Standard 2.0で規定されているAPIをサポートしている。.NET Standard 2.0ではサポートされるAPIが大きく増えているが、それでも.NET Frameworkにあるが.NET CoreにはないAPIは多い(特にWindowsに依存するもの)。このため、既存の.NET Frameworkプロジェクトを.NET Coreに移行するのは困難な場合がある。Compatibility Packは、.NET Frameworkから.NET Coreへの移行が楽になるように追加で約2万個のAPIを提供するものだ。
Compatibility Packでどのようなコンポーネントを利用できるようになるかは、MSDNブログの記事「Announcing the Windows Compatibility Pack for .NET Core」を参照してほしいが、Microsoft.Win32.Registryなど、.NET CoreプロジェクトであってもWindows上で動作するアプリでなければ使用できないものと、Windows/macOS/Linuxで使用できるものが存在する点には注意が必要だ(前述の記事で「Windows-Only」が「Yes」になっているもの)。Windowsのみで利用できるAPIを、Windows以外のプラットフォームで呼び出すとPlatformNotSupportedException例外が発生する(後述)。
例えば、.NET Frameworkベースのコンソールアプリで以下のようにレジストリから情報(ここではWindows 10のアクセントカラー)を取得するコードを書いたとする。
using System;
using Microsoft.Win32;
namespace CompatibilityPackSampleNetfx
{
class Program
{
static void Main(string[] args)
{
var key = @"HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM";
var value = "AccentColor";
var defaultvalue = "not found";
var rgb = Registry.GetValue(key, value, defaultvalue);
switch (rgb)
{
case string s:
Console.WriteLine(s);
break;
case int n:
int mask = 0x0000FF;
int[] rgbs = new int[4];
for (int i = 0; i < 4; i++)
{
rgbs[i] = n & mask;
n >>= 8;
}
Console.WriteLine(
$"Accent Color: {rgbs[0]:X} {rgbs[1]:X} {rgbs[2]:X} {rgbs[3]:X}");
break;
default:
Console.WriteLine(defaultvalue);
break;
}
Console.ReadKey();
}
}
}
これはもちろん.NET Frameworkでは動作するが、.NET Coreをプラットフォームとした場合、通常はMicrosoft.Win32.Registryクラスはサポートされていないので動作しない。実際に、.NET Coreベースのコンソールアプリプロジェクトを作成して、Mainメソッドの内容(と「using Microsoft.Win32;」宣言)を丸ごとコピー&ペーストすると、Visual Studio 2017では次のようにRegistryクラスを使用している箇所でエラーとなることが分かる。
ここでプロジェクトにCompatibility Packパッケージをインストールする。パッケージ名は「Microsoft.Windows.Compatibility」となっているので、NuGetパッケージの管理ウィンドウでは「Windows.Compatibility」などと入力して検索するとよいだろう。
これにより、先ほど見たエラーがなくなり、.NET CoreベースのアプリでもWindows上で実行する分にはレジストリから情報を取得できるようになる。
もう1つ注意する点としては、先にも述べたがCompatibility Packに含まれるAPIの中には「Windowsだけで動作がサポートされているものがある」ことだ。そして、macOSやLinuxからそれらのAPIを呼び出すと、PlatformNotSupportedException例外が発生する点だ。例えば、先ほどのコードをmacOS上で実行すると、以下のように実行時に例外が発生する。
このようにWindowsに依存するコードを含む場合には、IsOSPlatformメソッドを使用して、Windowsとそれ以外の環境で動作を切り分けることができる(「using System.Runtime.InteropServices;」宣言が必要)。
using System;
using Microsoft.Win32;
using System.Runtime.InteropServices;
namespace CompatibilityPackSampleMacOS
{
class Program
{
static void Main(string[] args)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
// Windowsに依存した処理を記述
var rgb = Registry.GetValue(key, value, defaultvalue);
// …… 省略 ……
} else {
// それ以外のプラットフォームでの処理を記述
}
Console.ReadKey();
}
}
}
PlatformNotSupportedException例外が発生することにはメリットもある。それは、Platform Compatibility Analyzerで、クロスプラットフォームでの互換性がないAPIを使用しているかどうかのチェックを行えることだ。Platform Compatibility Analyzerは今述べた「PlatformNotSupportedException例外を発生するAPI」などを動的にチェックしてくれるNuGetパッケージだ。これを.NET Coreプロジェクトにインストールすると、次のように互換性がない部分(Microsoft.Win32.Registry.GetValueメソッド呼び出し)に波線が表示されるとともに、[エラー一覧]ウィンドウにもそのことが報告される。
こうしたことから、Compatibility Packを使用する際には、Platform Compatibility Analyzerを併用するのがお勧めだ。そうすることで、既存の.NET Frameworkアプリの.NET Coreへの移行において使用できるAPIが大きく増えるとともに、互換性のないAPIの使用が常に監視されるようになる。
Compatibility Packを使用することで、.NET Coreベースのアプリで使用できるAPIが大幅に増え、既存の.NET Frameworkアプリの.NET Coreへの移行が容易になる(可能性がある)。ただし、何でもかんでも.NET Coreに移行するのがよいわけではない。例えば、Windowsのデスクトップアプリであれば、これまで通りに.NET Frameworkをプラットフォームとすることが推奨されることには注意しよう。
Copyright© Digital Advantage Corp. All Rights Reserved.