デスクトップ アプリからのWinRT API利用
Windowsストア アプリでない、通常の(デスクトップ版の).NETアプリからWinRT APIを呼び出す方法。
WinRT利用のために、.NET Framework自体に手が入っているので、.NET 4.5を使うなら、別にWindowsストア アプリでなくたってWinRT APIを呼べるわけですが。それのやり方、というか、Visual Studio上でいろいろ([参照の追加]ダイアログにWinRTコンポーネントの追加ペインを出したり)やるためには、csprojファイルを1行手動で書き換えないといけないというお話。
一部簡単に日本語で説明しようかというのと、元がVBなので、C#でさらっと書いてみたものを出しておこうかと。
WinRT APIとは
WinRTは、Windows 8で導入された新APIセットです。その一部は、XAML UIフレームワーク、つまり、Windowsストア アプリ(旧称、あるいは、通称Metroスタイル アプリ)を作るためのAPIです。そのほかにも、ファイル操作、ストリーム、ビットマップなど、OSのコア機能を提供しています。大部分は、Win32 APIや.NETでも同様のことができます。それでも、いくつかの場面では、(既存のWin32 APIを使うよりも)WinRT APIを使った方がきれいでわかりやすいことがあります。
WinRT APIは、主にWindowsストア アプリを作るためのAPIです。ただし、Windowsストア アプリでは、Win32 APIや、.NETの標準APIの一部分も使えます。
WinRT APIは様々な言語で作れ、様々な言語から使える(cross-languageな)APIです(現在、マイクロソフトがサポートしている言語として、JavaScript、C++、VB、C#、F#があります)。
WinRTコンポーネントは、WinMD(Windows Metadata)という、メタデータ ファイル(ファイル形式的には.NETアセンブリのメタデータと同じ)を持っていて、このファイルを介して、.NETからの利用や、インスペクション ツール(ReflectorやIL Spyのような、いわゆる逆コンパイラーなど)での読み込みができます。
WinRTの仕組みは、いわば、COMの改良/拡張となりますが、旧来のCOMよりも、だいぶ相互運用が楽になっています。
デスクトップ アプリでのWinRTコンポーネントの参照方法
プロジェクト ファイルの編集
プロジェクト ファイル(csproj)に以下の1行を追加します(OSをWindows 8/Windows RTに限定するという意味)。
<TargetPlatformVersion>8.0</TargetPlatformVersion>
場所的には、TargetFrameworkVersionが入ってる辺り。
<PropertyGroup>
<Configuration Condition=” ‘$(Configuration)’ == ” “>Debug</Configuration>
<Platform Condition=” ‘$(Platform)’ == ” “>AnyCPU</Platform>
<ProjectGuid>{DF27C494-9C02-42F8-AD96-CBEBA2D8B47B}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>WinRtConsoleApp</RootNamespace>
<AssemblyName>WinRtConsoleApp</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<TargetPlatformVersion>8.0</TargetPlatformVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
Visual Studio上で設定できるわけではないので、csprojファイルをメモ帳などで直接編集します。
参照の追加
以下のアセンブリ/WinRTコンポーネントへの参照を追加します。
- Windows.winmd
- 標準のWinRT API
- 場所: \Program Files (x86)\Windows Kits\8.0\References\CommonConfiguration\Neutral\Windows.winmd
- System.Runtime.WindowsRuntime
- 相互運用のための.NETアセンブリ
- WinRTをIAsyncAction/IAsyncOperationを、.NETのTaskクラス化/awaitable化するための拡張メソッド
- Point, Rect, Size構造体など、WinRT標準の型にマッピングされる型
- 場所: \Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5\System.Runtime.WindowsRuntime.dll
- 相互運用のための.NETアセンブリ
利用例
例えば、以下のような使い方をします。WinRT APIが提供する型はWindows名前空間の下で定義されています。
static void Main(string[] args)
{
MainAsync().Wait();
}
static asyncTask MainAsync()
{
var files = await Windows.Storage.KnownFolders.PicturesLibrary.GetFilesAsync(
Windows.Storage.Search.CommonFileQuery.OrderBySearchRank, 0, 10);
var pics = files.Where(f => IsImageFile(f.Name));
foreach (var pic in pics)
{
try
{
var desc = await GetDescription(pic);
Console.WriteLine(“name: {0}, width: {1}, height: {2}”,
desc.Name, desc.Width, desc.Height);
}
catch
{
continue;
}
}
}
private static async Task<PictureDescription> GetDescription(Windows.Storage.StorageFile pictureFile)
{
using (var stream = await pictureFile.OpenReadAsync())
{
var name = pictureFile.DisplayName;
var decoder = await Windows.Graphics.Imaging.BitmapDecoder.CreateAsync(stream);
var width = decoder.OrientedPixelWidth;
var height = decoder.OrientedPixelHeight;
retur nnewPictureDescription
{
Name = name,
Width = width,
Height = height,
};
}
}
static string[] ImageExtensions = new[] { “.bmp”, “.jpg”, “.jpeg”, “.png” };
static bool IsImageFile(string filename)
{
return ImageExtensions.Any(ext => filename.EndsWith(ext));
}
この例では、Pictureライブラリの直下にある画像ファイルの幅と高さを取得しています。
注釈
この説明を見てのとおり、.NET Frameworkというインフラ レベルでは、Windowsストア アプリに限らずデスクトップ アプリでも、WinRT、つまり、cross-languageなコンポーネント作成/利用ができます。
単に、1から作り直すチャンスが今(Windowsストア アプリ)というだけで、WinRTのcross-languageな側面は、今後利用の幅が広がっていくのではないかと、個人的には思っています(ただし、人的リソースにも限りがあるので、まあ、のんびりと)。
ちなみに、WinRTは「COMの改良/拡張」という話もしていますが、これが、Windows 8でしか動かせない理由だったりします。COMのためのインフラにかなり手を入れていて、この辺りがバックポートできないっぽい。
あと、同じWinRTコンポーネントでも、単に上記のような相互運用の仕組みに乗っているだけのもの(デスクトップ側からも利用可能)と、Windowsストア アプリのサンドボックス内での動作を前提にしているもの(デスクトップでの利用不可)があります。ここで例に挙げたようなファイルやビットマップ操作APIは全社(利用可)で、後者(利用不可)は、例えばコントラクトなんかがあります。(ちなみに、デスクトップ上に、Windowsストア アプリのサンドボックスを無理やり作って、Windowsストア アプリ on デスクトップみたいな真似をすることも、やろうと思えばやれるみたいですが。)
[…] デスクトップ アプリからのWinRT API利用 « ++C++; // 未確認飛行 C ブログ. カテゴリー: Desktop, WinRT パーマリンク ← DirectComposition layered child window sampleをVS 2012 Express For Windows Desktopで動かす。 […]
Using Windows 8* WinRT API from desktop applications | Intel® Developer Zone | S.F.Page
2012年10月9日 at 19:41
[…] そしたら一旦VSを終了し、以下の説明に従ってWinRT APIを使用できるよう設定。 デスクトップ アプリからのWinRT API利用 | ++C++; // 未確認飛行 C ブログ […]
Windows 10 のアクションセンターにC#で通知を表示してみた | 日曜研究室
2015年10月21日 at 22:41