WinRT コンポーネント

WinRT (Windows Runtime)は、Windows 8以降で実装された、新しいWindows APIです。 WinRTコンポーネント(WinRT APIが提供するクラスなど)は、COMの進化版(COMの上位互換)に、 .NET Frameworkの型情報を加えたような形式になっています。

WinRT コンポーネントは、Windows 8世代、つまり、.NET Frameworkよりもだいぶ後に作られただけあって、 C# からの参照はかなり簡単になっています。 C# で書かれたライブラリとほとんど区別なく WinRT コンポーネントを参照できます。 よっぽど意識しない限り、ネイティブ ライブラリを参照しているとは感じないでしょう。

Visual Studio 上では、下図のように、「参照の追加」→「Windows」→参照したいコンポーネントを選んで「OK」という手順を踏みます。

WinRTコンポーネントの参照

Windows アプリ

WinRT は前述のとおり、Windows 8世代の新APIです。 Windows 8から Windows 10にかけて紆余曲折ありましたが、要は、以下のタイプのアプリから使う前提のものです。

  • Windows ストア アプリ
    • 「Modern アプリ」とか「メトロ スタイル」とか呼ばれていた時期もあります
    • これを単に「Windows アプリ」と呼んで、これまでの Win32 API ベースのアプリは「従来のデスクトップ アプリ」と呼びたがっている(呼ばれるようになってほしい)節もあります
  • Universal Windows Platform (UWP)アプリ

これらに関連したプロジェクトを作ると、標準の状態で WinRT コンポーネントの参照ができます。

従来のデスクトップ アプリ

標準の状態では無理ですが、少し手を入れることで、従来のデスクトップ アプリからもWinRTコンポーネントを参照できます。

csproj を手書きで書き換える必要があります。以下のように、TargetPlatformVersionというタグを1行追加します。

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProjectGuid>{F404E6CA-F7FD-4AB8-A531-D8203BCC3F70}</ProjectGuid>
    <OutputType>Exe</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <RootNamespace>NativeInterop</RootNamespace>
    <AssemblyName>NativeInterop</AssemblyName>
    <TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
    <TargetPlatformVersion>10.0.10240.0</TargetPlatformVersion>
    <FileAlignment>512</FileAlignment>
    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
  </PropertyGroup>
...

TargetPlatformVersionタグの中身には、8.0, 8.1, 10.0 など、Windows のバージョンを書きます。

これで、例えば、以下のようなコンソール アプリで、WinRT コンポーネントを使えます。

using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.System;

namespace NativeInterop
{
    class WinRtSample
    {
        public static void Main()
        {
            MainAsync().Wait();
        }

        static async Task MainAsync()
        {
            var allUsers = await User.FindAllAsync();

            foreach (var user in allUsers)
            {
                Console.WriteLine(user.NonRoamableId);
            }
        }
    }

    static class WinRtExtensions
    {
        public static TaskAwaiter<T> GetAwaiter<T>(this IAsyncOperation<T> t) => t.AsTask().GetAwaiter();

        public static Task<T> AsTask<T>(this IAsyncOperation<T> t)
        {
            var tcs = new TaskCompletionSource<T>();
            t.Completed += (info, state) =>
            {
                try
                {
                    tcs.TrySetResult(info.GetResults());
                }
                catch(Exception ex)
                {
                    tcs.TrySetException(ex);
                }
            };
            return tcs.Task;
        }
    }
}

更新履歴

ブログ