Windows 10 リリース前の最後の休日ということで若干面倒なネタを
正式リリース後にいろいろ変わるかもしれませんが、UWP アプリでもやりたい放題したい!サイドローディングならできるんでしょ?ということで、以前 Microsoft の荒井さんが紹介していたアプリブローカー が使えないか試してみたいと思います
最初 Windows 10 SDK や .NET Framework 4.6 でランタイムブローカーをビルドしようとしたんですが、Visual Studio 2015 RC の開発者コマンドプロンプト使ってもなぜかターゲットバージョンが Windows 8.1 になるので諦めたのは内緒!
・・・というわけで、Windows 8.1 のランタイムブローカーを拝借することにしました
※ 参考までに今回利用したソースファイル一式は下記の GitHub リポジトリにアップしています
※ Windows 10 Insider Preview Build 10240 時点での情報のため、正式リリース後仕様等が変更になっている可能性があります
きっと正式リリースしたら Windows 10 用の方法が公開されるはず!
まずは Windows 8.1 のランタイムブローカー用プロジェクトテンプレートを下記からダウンロードしてインストールします
visualstudiogallery.msdn.microsoft.com
インストールが終わったら Visual Studio 2013 を起動します
お次はプロジェクトの新規作成ダイアログを開き「Visual C#」の下の方にある「Brokered Windows Runtime Component」のテンプレートを選んでプロジェクトを作成します
プロジェクトが開かれたらデフォルトで作成される Class.cs は削除し、下記のインタフェースとその実装クラスを追加します
namespace RuntimeBroker.Broker { /// <summary> /// Desktop Application launcher interfce /// </summary> [ComVisible(true)] public interface IAppLauncher { /// <summary> /// Launch desktop application from file name /// </summary> /// <param name="fileName">target application executable file name</param> void Launch(string fileName); } }
こっちがインタフェース
namespace RuntimeBroker.Broker { /// <summary> /// Desktop application launcher /// </summary> [ComVisible(true)] public sealed class AppLauncher : IAppLauncher { /// <summary> /// Launch desktop application from file name /// </summary> /// <param name="fileName">target application executable file name</param> public void Launch(string fileName) { Process.Start(fileName); } } }
そして実装クラス本体です
クラス属性に COM 参照可能にする ComVisible 属性をつけることと、実装クラス本体を sealed クラスにすることを忘れないように気を付けます
ここまでできたらまたプロジェクト追加
今度は「他の言語」-「Visual C++」からやっぱり下の方にある「Brokered Windows Runtime ProxyStub」のテンプレートを選んでプロジェクトを作成します
プロジェクトができたらソリューションエクスプローラーのビューから追加したプロジェクトを選び、右クリックメニューから「プロパティ」を開きます
「共通プロパティ」-「参照」のツリーを選び、右側の「新しい参照の追加」ボタンで先ほど作った Brokered Windows Runtime Component のプロジェクト RuntimeBroker.Broker のプロジェクト参照を追加します
さらに「構成プロパティ」-「リンカー」を選択し、「出力の登録」を「はい」に変更します
変更したら「OK」ボタンでダイアログを閉じ、プロジェクトを保存して Visual Studio 2013 は終了、今度は管理者として Visual Studio 2015 RC を起動します*1
Visual Studio 2013 で開いていたソリューションを再度開き、さらに新しいプロジェクトを作成
ここで Universal Windows Platform アプリの Blank App を追加します
プロジェクトができたら、UWP プロジェクトにプロジェクト参照として ProxyStub の方の参照を追加します
さらに Package.appxmanifest を開き編集します
<?xml version="1.0" encoding="utf-8"?> <Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" IgnorableNamespaces="uap mp"> <Identity Name="7304a498-82e6-4db2-86f8-2660b5580812" Publisher="CN=matatabi-ux" Version="1.0.0.0" /> <mp:PhoneIdentity PhoneProductId="7304a498-82e6-4db2-86f8-2660b5580812" PhonePublisherId="00000000-0000-0000-0000-000000000000"/> <Properties> <DisplayName>RuntimeBroker</DisplayName> <PublisherDisplayName>matatabi-ux</PublisherDisplayName> <Logo>Assets\StoreLogo.png</Logo> </Properties> <Dependencies> <TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.10069.0" MaxVersionTested="10.0.10069.0" /> </Dependencies> <Resources> <Resource Language="x-generate"/> </Resources> <Applications> <Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="RuntimeBroker.App"> <uap:VisualElements DisplayName="RuntimeBroker" Square150x150Logo="Assets\Logo.png" Square44x44Logo="Assets\SmallLogo.png" Description="RuntimeBroker" BackgroundColor="#464646"> <uap:SplashScreen Image="Assets\SplashScreen.png" /> </uap:VisualElements> </Application> </Applications> <Capabilities> <Capability Name="internetClient" /> </Capabilities> <Extensions> <Extension Category="windows.activatableClass.inProcessServer"> <InProcessServer> <Path>clrhost.dll</Path> <ActivatableClass ActivatableClassId="RuntimeBroker.Broker.AppLauncher" ThreadingModel="both"> <ActivatableClassAttribute Name="DesktopApplicationPath" Type="string" Value="%RuntimeBrokerPath%" /> </ActivatableClass> </InProcessServer> </Extension> </Extensions> </Package>
変更したのは最後の
<Extensions> <Extension Category="windows.activatableClass.inProcessServer"> <InProcessServer> <Path>clrhost.dll</Path> <ActivatableClass ActivatableClassId="RuntimeBroker.Broker.AppLauncher" ThreadingModel="both"> <ActivatableClassAttribute Name="DesktopApplicationPath" Type="string" Value="%RuntimeBrokerPath%" /> </ActivatableClass> </InProcessServer> </Extension> </Extensions>
この状態で一度ソリューションをビルド!
警告は無視してとりあえず適当に MainPage.xaml を修正
<Page x:Class="RuntimeBroker.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:RuntimeBroker" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Button Content="Launch calc app" FontSize="32" HorizontalAlignment="Center" VerticalAlignment="Center" Click="Button_Click"/> </Grid> </Page>
コードビハインドはこんな感じで、ボタンが押されたら AppLauncher からデスクトップアプリの電卓を起動するようにしてみました
/// <summary> /// An empty page that can be used on its own or navigated to within a Frame. /// </summary> public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); } /// <summary> /// Launch a desktop application 'calc.exe' /// </summary> /// <param name="sender">event sender</param> /// <param name="e">event aruguments</param> private void Button_Click(object sender, RoutedEventArgs e) { new AppLauncher().Launch("calc.exe"); } }
コーディングとしてはこれで終わりですが、まだ準備が必要です
まずは UWP を実行する Windows 10 環境の適当な場所に DLL や winmd を配置するためのフォルダを作ります
今回は安直に「C:\RuntimeBroker」というフォルダを作りました
フォルダができたら Visual Studio のソリューションエクスプローラー上で右クリックメニューから「エクスプローラーでフォルダを開く」を選び、ソリューションフォルダ内の「Debug」または「Release」配下にあるであろう「RuntimeBroker.ProxyStub」フォルダの中の DLL などを全部、先ほどの「C:\RuntimeBroker」にコピーします
コピーができたら Windows 10 上で左下の Windows ロゴボタンを右クリックして、「システム」を開きます
左側に表示される「システムの詳細設定」を選び表示された「システムのプロパティ」の「詳細設定」タブ、下の方の「環境変数」ボタンを押します
「環境変数」のダイアログが開いたら「システム環境変数」の方の「新規」ボタンを押して「RuntimeBrokerPath」の名前で「C:\RuntimeBroker」のフォルダパスを値に入力して「OK」ボタンで保存します
さらにさらに・・・まだまだ続く、Windows 10 上で左下の Windows ロゴボタンを右クリックして「コマンドプロンプト(管理者)」を選んでコマンドプロンプトを管理者モードで開きます
プロンプトが起動したら次のコマンドを実行・・・
cd %RuntimeBrokerPath% icacls . /T /grant *S-1-15-2-1:RX regsvr32 RuntimeBroker.ProxyStub.dll
先ほどの C:\RuntimerBroker フォルダをアプリから読み書きできるようにするために icals のコマンドを実行し、さらに RuntimeBroker.ProxyStub.dll の DLL を COM に登録しました
さてこれで、すべての準備が整ったはずなので UWP の RuntimeBroker プロジェクトをストートアッププロジェクトに設定し、プラットフォームを x86 に変更しておためし実行!
できましたー!!電卓が起動しましたね
ランタイムブローカーは管理者権限昇格の UAC が必要な処理や通信が重いなどちょっと制限があるみたいですが、業務アプリを UWP で作るときには心強いコンポーネントですね・・・正式リリースではきっと Windows 10 SDK、.NET Framework 4.6 でも作れるようになるはずだし!
*1:途中のビルドで管理者権限がないと失敗するため