Windows Compatibility Pack for .NET CoreDev Basics/Keyword

Windows Compatibility Packにより、.NET Standardではサポートされていない、.NET FrameworkのAPIが.NET Coreでも使えるようになる。

» 2017年11月21日 05時00分 公開
[かわさきしんじInsider.NET編集部]
「Dev Basics/Keyword」のインデックス

連載目次

 Windows Compatibility Pack for .NET Core(以下、Compatibility Pack)は、.NET Standard 2.0では規定されていない.NET FrameworkベースのAPIを.NET Coreプロジェクトで利用できるようにするNuGetパッケージ。ただし、Windows FormsやWPFなどはサポートされていない。また、本稿執筆時点(2017年11月20日)では、プレビュー段階のプロジェクトとなっている。

Compatibility Packとは

 .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();
    }
  }
}

Microsoft.Win32.Registryクラスを使用するプログラム例

 これはもちろん.NET Frameworkでは動作するが、.NET Coreをプラットフォームとした場合、通常はMicrosoft.Win32.Registryクラスはサポートされていないので動作しない。実際に、.NET Coreベースのコンソールアプリプロジェクトを作成して、Mainメソッドの内容(と「using Microsoft.Win32;」宣言)を丸ごとコピー&ペーストすると、Visual Studio 2017では次のようにRegistryクラスを使用している箇所でエラーとなることが分かる。

.NET CoreプロジェクトではMicrosoft.Win32.Registryクラスは使えない .NET CoreプロジェクトではMicrosoft.Win32.Registryクラスは使えない

 ここでプロジェクトにCompatibility Packパッケージをインストールする。パッケージ名は「Microsoft.Windows.Compatibility」となっているので、NuGetパッケージの管理ウィンドウでは「Windows.Compatibility」などと入力して検索するとよいだろう。

Compatibility Packパッケージのインストール Compatibility Packパッケージのインストール

 これにより、先ほど見たエラーがなくなり、.NET CoreベースのアプリでもWindows上で実行する分にはレジストリから情報を取得できるようになる。

.NET Coreベースのアプリの実行画面(タイトルバーに「dotnet.exe」が含まれていることからこれが.NET Coreプロジェクトであることが分かる) .NET Coreベースのアプリの実行画面(タイトルバーに「dotnet.exe」が含まれていることからこれが.NET Coreプロジェクトであることが分かる)

 もう1つ注意する点としては、先にも述べたがCompatibility Packに含まれるAPIの中には「Windowsだけで動作がサポートされているものがある」ことだ。そして、macOSやLinuxからそれらのAPIを呼び出すと、PlatformNotSupportedException例外が発生する点だ。例えば、先ほどのコードをmacOS上で実行すると、以下のように実行時に例外が発生する。

macOS上ではMicrosoft.Win32.Registry.GetValueメソッド呼び出しでPlatformNotSupportedException例外が発生した macOS上ではMicrosoft.Win32.Registry.GetValueメソッド呼び出しでPlatformNotSupportedException例外が発生した

 このように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();
    }
  }
}

IsOSPlatformメソッドで処理を切り分ける

 PlatformNotSupportedException例外が発生することにはメリットもある。それは、Platform Compatibility Analyzerで、クロスプラットフォームでの互換性がないAPIを使用しているかどうかのチェックを行えることだ。Platform Compatibility Analyzerは今述べた「PlatformNotSupportedException例外を発生するAPI」などを動的にチェックしてくれるNuGetパッケージだ。これを.NET Coreプロジェクトにインストールすると、次のように互換性がない部分(Microsoft.Win32.Registry.GetValueメソッド呼び出し)に波線が表示されるとともに、[エラー一覧]ウィンドウにもそのことが報告される。

Platform Compatibility Analyzerによる互換性チェック Platform Compatibility Analyzerによる互換性チェック
ポップアップが左右に長いためカットしている。

 こうしたことから、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をプラットフォームとすることが推奨されることには注意しよう。

参考資料


「Dev Basics/Keyword」のインデックス

Dev Basics/Keyword

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。