tmytのらくがき

個人の日記レベルです

AzureaのWindows Mobile向けサポートを終了します

タイトルの通りですが、AzureaのWindows Mobile向けサポートを年内をもって終了する予定です。 2017年12月31日時点でリリースされているバイナリを最終バージョンとし、それ以降はアップデートは配信されなくなります。

Azureaは2010年1月にWindows Mobile 5以降を対象としてリリースされました。当時はWillcomがAdvanced W-ZERO3 [es]とか売ってた時代です。 以降、国内外でWindows Mobile向けTwitterクライアントとしてそれなりに使われていたみたいです。街中で見かけることも時々ありました。

しかしながら、Windows Mobileシリーズは2013年にMicrosoftのサポートは終了しており、そこから4年もたったのでもういい加減いいかな。と思った次第です。 これまでありがとうございました。

同アプリのWindows向けバイナリは2018年以降もサポートが継続されます。 Windows向けは東京オリンピックぐらいまでは続くんではないでしょうか。 こちらはこれからもよろしくお願いします。

最近UWP版はじめました

Visual Studio PreviewでDesktopBridgeが簡単になりました

このエントリは2017/9/3時点でのVisual Studio Previewで動作を確認しています。リリース時の動作とは異なる場合があります。

Visual Studio 2017 Preview (Version 15.4.0 Preview 1.0)でWPFアプリケーションをDesktop Bridgeでパッケージングすることがとても簡単になりました。 いままではDesktop App Converterでがんばったり、手作業でAppxManifestを作ったり、JavaScript UWP プロジェクトを生贄にしたり、いろいろめんどくさかったDesktop Bridgeがやっと簡単になりました。

試しにやってみたので手順をまとめておきます。

1. WPFアプリを作る

ソリューションの新規作成からてきとうにやります。ここ読むようなひとは作れると思うので省略します。

2. Windows Application Packaging Projectをソリューションに追加する

ソリューションを右クリック→追加→新しいプロジェクトを選びます。

f:id:tmyt:20170903032106p:plain

Visual C#Windows ユニバーサルのなかから「Windows Application Packaging Project」を選択して適当に名前を付けてOKします。

f:id:tmyt:20170903032338p:plain

バージョンは最小バージョンを14393にしておけば問題ないと思います。

f:id:tmyt:20170903032441p:plain

3. 既存のWPFプロジェクトをWindows Application Packaging Projectから参照する

ソリューションエクスプローラのApplicationを右クリックして、参照の追加を選択します。

f:id:tmyt:20170903032626p:plain

アセンブリ参照ダイアログみたいなのが出るのでチェックを付けてOKします。

f:id:tmyt:20170903032829p:plain

4. おわりです

あとは実行ターゲットをWindows Application Packaging Projectに設定してF5実行すると、WPFアプリケーションが起動します。 同時にスタートメニューにも登録されていることを確認できます。

f:id:tmyt:20170903033029p:plain

f:id:tmyt:20170903033049p:plain

まとめ

すごい簡単になりました。パッケージ情報も普通のUWPのAppxmanifestエディタが使えるので楽です。 アイコンとかは400x400ピクセルの画像だけ用意しておけばたいていは自動生成されます。

このプロジェクトテンプレートで楽になるのは単体、もしくはいくつかのDLLとともに配布されるパッケージで、 特にインストーラを用いていないZIP配布のアプリケーションに適しているように見えます。

GPD Pocketのホールセンサーを交換しました

GPD Pocketの最初のほうのロットにはホールセンサー(磁力センサー)の取り付けに問題があるらしくって、半分ぐらい閉じるとスリープするんだけど、そのあと完全に閉めると起きてくるっていうハードバグがあったんです。 GPDとしても問題は認識していて、対応を問い合わせると深圳にいったん送り返して部品を交換 or 部品を送るので自力交換の2つを提示されました。

自力交換できるならやりたいけど…でも深圳のやつらの言うことだしはんだをはがしてとか言いだすんじゃねぇの……とおもって交換の仕方が公開されたのでそれを見たらあきらかにらくしょーだったので自力交換しました。

www.youtube.com

らくしょーやん!部品おくって!!!とメールして、わかった部品おくるぜ!!!と言われてから約2週間。中国を出発して、はるばるオランダを経由した部品は29日に到着しました。

28-07-2017 16:11 Receive item at delivery office (Inb)
26-07-2017 17:37    The item has been processed in the country of destination
26-07-2017 11:49    The item has arrived in the country of destination
25-07-2017 09:20    The item is on transport to the country of destination
24-07-2017 12:35    The item is processed at the PostNL sorting center
24-07-2017 12:35    The item is at the PostNL sorting center
21-07-2017 01:10    The item is ready for shipment
18-07-2017 03:45    The item is pre-advised
16-07-2017 00:04    The Item is at the shippers warehouse

こいつを取り付けます。

とりあえず裏のねじを6本外すとバックパネルが外れます。簡単。

アンテナを外して、ケーブルを外して、ヒートシンクを外して、メインボードを外すと…そこに問題の部品がいます。

こいつもねじ止めされてるので外します。どうせいらないのでフレキケーブルを引っ張って取り外します。

古い部品(左)と新しい部品(右)ついてるセンサが変わってるみたい。背の高さが微妙に違ったり、左にはんだ付けされてる個所が増えてる。

新しい部品をはめたら、あとは逆の手順で戻します。

だいたい20分ぐらいで分解、交換、元に戻せました。

ふたを閉めても起きてこなくなったぞおおおおおおおおおおおおおおおおおおおおうおおおおおおおおおおおおおおおおおおおおおお

おしまい。

C++/Win32からSurface Dialを制御する (RS2版)

Surface Dialが出たころはWindows 10 Anniversary Update (Build 14393)だったのが、今はCreators Update (Build 15063)で、RadialController周りも少しアップデートがあったことに今更気づいたのでC++から触ってみます。

追加されたインターフェース

RadialController周りで増えたのがこのあたり。

  • IRadialController2
  • IRadialControllerMenuItemStatics2
  • IRadialControllerRotationChangedEventArgs2
  • IRadialControllerScreenContactContinuedEventArgs2
  • IRadialControllerScreenContactStartedEventArgs2

このうちEventArgsとついているのは、これまで通りのイベント引数に対してQueryInterfaceすると読めます。

// たとえばIRadialControllerRotationChangedEventArgs2の場合
/*
using namespace Microsoft::WRL;
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::UI::Input;
*/
EventRegistrationToken rotationChangedEvent;
// ComPtr<IRadialController
_controller->add_RotationChanged(
    Callback<ITypedEventHandler<RadialController*, RadialControllerRotationChangedEventArgs*>>(
    [this](IRadialController*, IRadialControllerRotationChangedEventArgs* args) {
        ComPtr<IRadialControllerRotationEventArgs2> args2;
        args->QueryInterface(IID_PPV_ARGS(&args));
        // 好きに使う
        // args2->get_SimpleHapticsController();
        return S_OK;
    }).Get(), &rotationChangedEvent);

残りのIRadialController2IRadialControllerMenuItemStatics2は、IRadialControllerIRadialControllerMenuItemStaticsに対して QueryInterfaceすれば読めます。

/*
using namespace Microsoft::WRL;
using namespace Windows::Foundation;
using namespace ABI::Windows::UI::Input;
*/
ComPtr<IRadialControllerMenuItemStatics> menuItemStatics;
ComPtr<IRadialControllerMenuItemStatics2> menuItemStatics2;
GetActivationFactory(
    HStringReference(RuntimeClass_Windows_UI_Input_RadialControllerMenuItem).Get(),
    &menuItemStatics);
menuItemStatics->QueryInterface(IID_PPV_ARGS(&menuItemStatics2));

だいたいQueryInterfaceすればどうにかなります。

C++/Win32でDialを使ったコードを書く

前に書いたやつを書き直してGitHubにサンプルプロジェクトを公開しました。VS2017+15063 SDKでそのまま実行できるはずです。

IVector実装の入手

システムアイコンを追加削除するには、任意のIVector実装が必要です。 正直実装するのは面倒なのでWin2Dで使用されている実装を拝借します。 この実装はMITライセンスで公開されています。

Win2Dから

  • ErrorHandling.h
  • LifeSpanTracker.h
  • Vector.h
  • WinStringBuilder.h
  • WinStringWrapper.h

を入手してプロジェクトに追加します。

プロジェクトの設定

プロジェクトの設定の変更が必要です。プロジェクトを右クリックした、プロパティから次の設定を変更します。 15063になって、WindowsSDK_UnionMetadataPathが使えるようになったのでちょっとだけ短くなりました。

  1. 構成プロパティ > 全般 > Windows SDK バージョン を “10.0.15063.0” に設定
  2. 構成プロパティ > C/C++ > 全般 > Windows ランタイム拡張機能の使用 を “はい (/ZW)” に設定
  3. 構成プロパティ > C/C++ > 全般 > 追加の #using ディレクトリを “$(VC_ReferencesPath_VC_x86)\store\references;$(WindowsSDK_UnionMetadataPath)” に設定
  4. 構成プロパティ > C/C++ > コード生成 > 最小リビルドを有効にするを “いいえ (/Gm-)” に設定
  5. 構成プロパティ > MIDL > 全般 > Windows ランタイムを有効にしますを “はい (/winrt)” に設定
  6. 構成プロパティ > MIDL > 全般 > 追加のメタデータ ディレクトリを “$(WindowsSDK_UnionMetadataPath)” に設定
  7. 構成プロパティ > MIDL > 詳細設定 > ‘ABI’ 名前空間を追加するを “はい (/ns_prefix)” に設定

f:id:tmyt:20170720002214p:plain f:id:tmyt:20170720002120p:plain f:id:tmyt:20170720002248p:plain f:id:tmyt:20170720002333p:plain f:id:tmyt:20170720002423p:plain

IDLの作成

すごく面倒なんですが、IVector<T>インスタンス化するにはIDLが必要です。 genericとC++のテンプレートと、COMの都合だそうです*1

プロジェクトを右クリックして、追加、コード、MIDL ファイルで追加します。 ここではとりあえずVector.idlとしておきます。

f:id:tmyt:20170720001939p:plain

今回はWindows.Foundation.Collections.IVector<Windows.UI.Input.RadialControllerSystemMenuItemKind>が使えればいいので、 こんな感じで書いておきます。namespaceで指定する名前空間はなんでもいいみたいです*2

import "inspectable.idl";
import "Windows.Foundation.idl";
import "Windows.UI.Input.idl";

namespace collections
{
    declare{
        interface Windows.Foundation.Collections.IVector<Windows.UI.Input.RadialControllerSystemMenuItemKind>;
    }
}

Vector_h.hの参照

だいたい終わりです。 IVector<T>インスタンスを作成するMicrosoft::WRL::Make<T>を読んでいるファイルで、 Vector_h.hをインクルードする必要があります。

このときのファイル名はIDLのファイル名から拡張子を除いた部分に_hを付けて拡張子idlをhに変更したものを 指定します。

#include"Vector_h.h"

おしまい

これでとりあえずRadialControllerの全機能が使えると思います。 IDL周り以外は大して難しくないはずなので遊んでみてください。

github.com

*1:http://mntone.hateblo.jp/entry/2014/08/29/095251

*2:15063 SDKを使っている分には問題はなさそうです

Blackberry KEYone (BBB100-6) を買いました

Blackberry KEYone (BBB100-6)つまるところ国内版を買いました。Amazonで予約したけど一向に出荷されないので、閉店間際に新宿ビックカメラいったら1つだけ在庫残ってました。

中身。

遊びづらそうだったのでデレステいれてみたり。

画面分割したら結構頑張れるのでは…?

IIJmio TypeAでがんばる方法

  1. ##46368676##
  2. 携帯電話情報
  3. LTE Only にする

するとつながりました

入れたもの

Layout for KEYone

ATOKとかGoogle 日本語入力がいい感じになるやつ

play.google.com

JuiceSSH

SSHクライアント

play.google.com

買ったもの

OverLay Plus for BlackBerry KEYone

とりあえずさらさらのやつに

www.miyavix.co.jp

そんなかんじ

GPD Pocketのために買ったもの

Indiegogoでキャンペーンが始まった直後に出資していたGPD Pocketが2週間くらい前に届いてたけどもエントリ書くの忘れてました。

こういう感じで届いて

こんなのが入っていて

まぁ普通のWindowsでした。

買ったもの

赤乳首。

ThinkPadロープロファイル用がそのまま使えるので交換しました。標準の青色は指が滑りやすくて使いづらいのでとりあえず交換するのをお勧めします。

nttxstore.jp

TypeCハブ。HDMI付き。

PDで充電もできるハブ。PDのハブは微妙だぞって公式のUpdateにも書いてあったのが気になったのでお試し用に。

という結果になりました。

https://www.amazon.co.jp/dp/B01MZ699BC/www.amazon.co.jp

いれもの

同じメーカーのMacBook Airのいれものが好きなのでサイズ感的にたぶんこれだろ。って買ったらなかなかいいサイズ感でした。だいたいぴったり。

https://www.amazon.co.jp/dp/B005BIHILK/www.amazon.co.jp

Desktop Bridgeで既存のWin32アプリを手軽にパッケージングしたい

既存のWin32アプリをWindows Storeで公開したりWindows 10Sで実行するには、Desktop BridgeでUWPに見せかけるしかないんですが、ぱっとみすごくめんどくさそうに見えるんです。でもMSDNに裏技が書いてあったので試してみました。

※今回やったことはMSDNに全部書いてあります。Visual Studio による .NET デスクトップ アプリ用デスクトップ ブリッジ パッケージ ガイド - UWP app developer | Microsoft Docsのステップ1 変換の個所が該当します。

そもそも

そもそもミスリードしてる人が多いですが、Win32アプリをUWPに変換するためにDesktop App Converter (DAC)は必須要件では『ありません』。Desktop App Converterはインストーラが存在する既存のWin32アプリをある程度自動で変換するための仕組みです。

DACもやってることは単純で仮想マシン起動して、その中でインストーラ実行して、インストーラが終了した時点でのファイルシステムレジストリの差分を回収するだけの仕組みです。Desktop Bridge自体はDAC非依存なので、UWPに含めるパッケージを自力で作れるのであれば、DACなんて使わなくてもいいんです。

結局はDesktop Bridgeで変換されたWin32アプリは、Appxの中にWin32の実行ファイルが入ってるだけのたんなるAppxパッケージです。

なので、たんにZIPしてるだけのアプリをUWPにしたいがためだけにインストーラ書くとか完全に間違いで、MSDN見たらもっと簡単な方法があったのでやってみました。今回はコードスニペットと、画像多めでお送りします。

準備

まず変換したいアプリを用意します。

MSDNで紹介されているのは、.NETアプリなのでWPFとかのが該当します。が、手元にそんなものはなかったのでAzureaを変換してみます。MSDNにあるのと、今回試したのの大きな違いは.NETかC++ Nativeかです。MSDNでは.NETアプリなので、Any CPUでおっけー!*1とか書いてますけど、これ残念ながらネイティブコードなのでx86とx64で実行コード違うし、そもそもAnyにしたらx86で詰むやろ…とかあるのでその辺も回避してきます。

この時点でソリューションはまだこうです。これからいろいろやっていきます。

f:id:tmyt:20170509004204p:plain

JavaScript UWPプロジェクトの追加

何度も言いますけど、Desktop Bridgeで変換されたWin32アプリは、Appxの中にWin32の実行ファイルが入ってるだけのたんなるAppxパッケージです。なので、簡単にパッケージを作るには、UWPプロジェクトにファイル追加してマニフェスト編集するのが一番楽なんです。ストア用の署名とかも全部勝手にやってくれるし。

ということで、まずはJavaScript UWPプロジェクトを追加します。よーするにJavaScript UWPプロジェクトをいけにえにして、Desktop Bridgeで実行されるWin32アプリを含んだAppxを作ります。なんでJavaScriptなのかというと、最初のMSDNのページの一番最後にちらっと書いてあります。

  • Debug でアプリをビルドすると、次のようなエラーが出力されます。Microsoft.Net.CoreRuntime.targets(235,5): エラー: カスタム エントリ ポイントを持つアプリケーションの実行可能ファイルはサポートされていません。 パッケージ マニフェストでの Application 要素の Executable 属性を確認してください。 この問題を回避するには、代わりに Release モードを使用します。
  • UWP プロジェクトのルート フォルダーに格納されている Win32 バイナリは、Release では削除されます。 Win32 バイナリを格納するフォルダーを使用しない場合、.NET Native コンパイラは最終的なパッケージからそれらのバイナリを削除します。これにより、実行可能ファイルのエントリ ポイントが見つからないため、マニフェストの検証エラーが出力されます。

ということなので全く話になりません。JavaScript UWPプロジェクトは単なるHTMLを表示するだけのマニフェストでビルドもなにもしないから余計なこと何もしないので、試してみたらたまたまうまくいきました。とかそういう感じなんでしょう。きっと。

f:id:tmyt:20170509004751p:plain

普段C#とかVBでUWP書いてる人はもしかするとインストールすらしてないかもしれないJavaScriptを選択して、Blank Appを作成します。名前は『アプリの名前.Package』とかにしとくと分かりやすいと思います。今回変換したいのはAzureaなのでAzurea.Packageという名前でプロジェクトを作りました。

プロジェクト作ったときに聞かれるターゲットバージョンですが、どうせ後で書き換えちゃうのでお好きな感じで結構です。

f:id:tmyt:20170509005623p:plain

プロジェクトが出来上がると、ソリューションがこんな感じになります。

f:id:tmyt:20170509005704p:plain

そしてVisual Studioでは自動的にmain.jsが開かれて

// Your code here!

f:id:tmyt:20170509005742p:plain

とか言ってますが、このファイルが入ってるディレクトリを含め、赤丸の部分は不要なので削除します。

f:id:tmyt:20170509005907p:plain

すっきりしました。

f:id:tmyt:20170509010009p:plain

imagesには、アプリのアイコンとかが入ってたりするのでそのまま置いておきます。(あとで使います)

Win32実行ファイルの追加

いけにえにするJavaScript UWPプロジェクトの準備ができたので、Appxに含めるファイルを追加していきます。

MSDNの手順にそって、win32というフォルダを作ります。

f:id:tmyt:20170509010254p:plain

別にこれwin32である必要はまったくなくて、わかりやすそうだからwin32なだけです。appとか、applicationとかprogramとかなんでも大丈夫です。なんで何でもいいかというと、Win32の実行ファイルがAppxにパッケージングされていることが大事で、実行するWin32実行ファイルのパスはappxmanifestで指定するので本当になんでもいいです。なんでもいいんですけど、MSDNでwin32って書いてたので、とりあえずそのままwin32で進めます。

次に、アプリケーションが実行に必要なファイルをwin32の中にいい具合に追加します。とりあえず、Releaseビルドした結果をエクスプローラからドラッグ&ドロップで追加してみました。

f:id:tmyt:20170509010751p:plain

この時pdbももれなく追加するのがポイントです*2pdbを追加しておくと、Appxのパッケージングプロセスの中でpdbだけ切り出されていつものUWPみたいにappxsymにしてくれます。ぜひ追加しましょう。

ファイルを追加したら、win32配下のファイルをすべてコンテンツとしてマークします。コンテンツにしないとAppxのなかにうまく含めてくれません。

f:id:tmyt:20170509011159p:plain

出力ディレクトリにコピーについても新しければコピーするもしくは、常にコピーするにします。

f:id:tmyt:20170509011243p:plain

ここまで来たら基本的にはだいたい終わりです。あらまぁ簡単ですね。って感じです。

appxmanifestの編集

パッケージのコンテンツにWin32実行ファイルの実行に必要なファイルを追加したんですが、手動でコピーしました。これだと、毎回コピーしないといけなくて面倒なんですが、それの対応はちょっと後回しにしてappxmanifestを編集します。

残念ながらDesktop Bridge周りはUIで編集できないので手作業で編集します。まずはpackage.appxmanifestを右クリックして、コードを表示します。

f:id:tmyt:20170509011536p:plain

するとこういうXMLが表示されます。

<?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="0f891c8e-ba95-4518-b6ab-b73741a82090"
    Version="1.0.0.0"
    Publisher="CN=yutaka" />

  <mp:PhoneIdentity PhoneProductId="0f891c8e-ba95-4518-b6ab-b73741a82090" PhonePublisherId="00000000-0000-0000-0000-000000000000" />

  <Properties>
    <DisplayName>Azurea.Package</DisplayName>
    <PublisherDisplayName>yutaka</PublisherDisplayName>
    <Logo>images\storelogo.png</Logo>
  </Properties>

  <Dependencies>
    <TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
  </Dependencies>

  <Resources>
    <Resource Language="x-generate" />
  </Resources>

  <Applications>
    <Application 
      Id="App"
      StartPage="index.html">

      <uap:VisualElements
        DisplayName="Azurea.Package"
        Description="Azurea.Package"
        BackgroundColor="transparent"
        Square150x150Logo="images\Square150x150Logo.png"
        Square44x44Logo="images\Square44x44Logo.png">

        <uap:DefaultTile Wide310x150Logo="images\Wide310x150Logo.png" />
        <uap:SplashScreen Image="images\splashscreen.png" />

      </uap:VisualElements>
    </Application>
  </Applications>

  <Capabilities>
    <Capability Name="internetClient" />
  </Capabilities>

</Package>

MSDNに書いてある内容を順番に反映していきます。

まずPackageタグにxmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"を追加します。さらに、PackageタグのIgnorableNamespacesrescapも追加します。IgnorableNamespacesはスペース区切りなので、uap mp rescapになります。

追加したPackageタグはこうなります。

<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"
  xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
  IgnorableNamespaces="uap mp rescap">

次にDependenciesタグにあるTargetDeviceFamily<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.14393.351" MaxVersionTested="10.0.14393.351" />で置き換えます*3。置き換えたDependenciesはこうなります。

  <Dependencies>
    <TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.14393.351" MaxVersionTested="10.0.14393.351" />
  </Dependencies>

Capabilitesタグに<rescap:Capability Name="runFullTrust" />を追加します。これでAppxが完全信頼で実行されるようになります*4。追加するとこうなります*5

  <Capabilities>
    <rescap:Capability Name="runFullTrust" />
    <Capability Name="internetClient" />
  </Capabilities>

最後にアプリのエントリポイントを設定します。ApplicationタグにExecutable属性とEntryPoint属性を指定します。この時、Executable属性には、実行ファイルのAppx内の相対パス*6EntryPoint属性にはWindows.FullTrustApplicationを指定します。今回変換するAzureaはAzurea.exeが実行ファイル名なので、これらを設定するとこうなりました。

<Application Id="Azurea" Executable="win32\Azurea.exe" EntryPoint="Windows.FullTrustApplication">

これで手書きで編集しないといけない部分はおしまいです。あとアイコンとかはいつも通りGUIから生成とかしちゃって大丈夫です。

ここまで全部変更したXMLはこうなります。

<?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"
  xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
  IgnorableNamespaces="uap mp rescap">


  <Identity
    Name="0f891c8e-ba95-4518-b6ab-b73741a82090"
    Version="1.0.0.0"
    Publisher="CN=yutaka" />

  <mp:PhoneIdentity PhoneProductId="0f891c8e-ba95-4518-b6ab-b73741a82090" PhonePublisherId="00000000-0000-0000-0000-000000000000" />

  <Properties>
    <DisplayName>Azurea.Package</DisplayName>
    <PublisherDisplayName>yutaka</PublisherDisplayName>
    <Logo>images\storelogo.png</Logo>
  </Properties>

  <Dependencies>
    <TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.14393.351" MaxVersionTested="10.0.14393.351" />
  </Dependencies>

  <Resources>
    <Resource Language="x-generate" />
  </Resources>

  <Applications>
    <Application
      Id="Azurea"
      Executable="win32\Azurea.exe"
      EntryPoint="Windows.FullTrustApplication">

      <uap:VisualElements
        DisplayName="Azurea.Package"
        Description="Azurea.Package"
        BackgroundColor="transparent"
        Square150x150Logo="images\Square150x150Logo.png"
        Square44x44Logo="images\Square44x44Logo.png">

        <uap:DefaultTile Wide310x150Logo="images\Wide310x150Logo.png" />
        <uap:SplashScreen Image="images\splashscreen.png" />

      </uap:VisualElements>
    </Application>
  </Applications>

  <Capabilities>
    <rescap:Capability Name="runFullTrust" />
    <Capability Name="internetClient" />
  </Capabilities>

</Package>

この状態でAppxmanifestのGUIエディタを開くとスタートページが設定されてない。とか言ってきます。

f:id:tmyt:20170509013058p:plain

このパラメータは本来Applicationタグに設定されているんですが、さっき消しちゃったのでこんなエラーがでます。出るんですが、Appx作るうえで何も起こられないのであまり気にせずこのまま放っておきます。

パッケージのビルド

あとはもうビルドしたらできあがりです。プロジェクトを右クリックして、ストア、アプリパッケージの作成でできます。

f:id:tmyt:20170509013305p:plain

この先は普段のUWPのビルドと変わらないので割愛します。ひとつだけ注意する点があって、パッケージのアーキテクチャの指定です。

f:id:tmyt:20170509013420p:plain

.NETでWPFみたいなILだけのアプリの場合はNeutralにAny CPUを指定します。これでOKです。それ以外の人は、x86とx64にチェックを入れて、それぞれビルドしましょう。しばらくするとパッケージが出力されます。インストールとかして試してみるといいと思います。

パッケージに含めるコンテンツを自動で更新する

ここまででできたAppxの中身を更新するには毎回手作業でコピーしてあげないといけなくてかったるいので自動でやります。そもそも、今回のAzureaはネイティブコードなのでx86/x64のパッケージを別々に生成しないといけなくて毎回コピーなんてめんどくさくてやってられません。

これらを実現するためにスクリプトを書きます。今時ならPowerShell使えよって感じなんですが、PowerShell力が低いのでバッチファイル書きます。

まず、win32の中身をクリーンするやつです。これをcleanup.batとします。終了コードが0じゃないとビルドが止まってしまうのでとりあえずexit 0してます。

del /Q win32\Azurea.exe
del /Q win32\Azurea.pdb
del /Q win32\AzLang.dll
del /Q win32\AzLang.pdb
del /Q win32\ColorSchemes\*
del /Q win32\Language\*
exit 0

次に、プロジェクトの出力を集めてwin32ディレクトリにコピーするやつです。これはcopyfiles.batとします。Appxパッケージビルド時のプラットフォーム名を使ってコピーするディレクトリを振り分けています。

@echo off
echo Packaging for %*
set build=%1%
set arch=%2%
mkdir win32

if "%arch%"=="x64" goto copy_amd64
if "%arch%"=="x86" goto copy_x86
goto undefined_platform

:copy_amd64
copy ..\x64\%build%\Azurea.exe win32\Azurea.exe
copy ..\x64\%build%\Azurea.pdb win32\Azurea.pdb
copy ..\x64\%build%\AzLang.dll win32\AzLang.dll
copy ..\x64\%build%\AzLang.pdb win32\AzLang.pdb
goto copy_noarch

:copy_x86
copy ..\%build%\Azurea.exe win32\Azurea.exe
copy ..\%build%\Azurea.pdb win32\Azurea.pdb
copy ..\%build%\AzLang.dll win32\AzLang.dll
copy ..\%build%\AzLang.pdb win32\AzLang.pdb
goto copy_noarch

:copy_noarch
mkdir win32\ColorSchemes
mkdir win32\Language
xcopy ..\Azurea\ColorSchemes win32\ColorSchemes /-Y /E
xcopy ..\Language win32\Language /-Y /E
goto EOF

:undefined_platform
echo "Undefined platform " %arch%
exit 1

:EOF

これらはプロジェクトの中のscriptsというディレクトリにまとめて保存しました。

f:id:tmyt:20170509014256p:plain

次にこれらを呼び出してもらわないといけません。ということでまずJavaScript UWPプロジェクトをアンロードします。

f:id:tmyt:20170509014350p:plain

次に、アンロードしたプロジェクトを右クリックして、編集を選択します。

f:id:tmyt:20170509014428p:plain

表示されたXMLを下のほうまでスクロールして、最後にこんなのを追加します。

  <Target Name="BeforeBuild">
    <Exec Command="scripts\cleanup.bat" />
    <Exec Command="scripts\copyfiles.bat $(Configuration) $(Platform)" />
  </Target>
  <PropertyGroup>
    <DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
  </PropertyGroup>

追加したら保存して閉じます。それぞれの意味ですが、

  • BeforeBuild ビルド前に実行するタスクです。
  • $(Configuration) ビルド設定で、ReleaseとかDebugとか入っています。
  • $(Platform) アーキテクチャx86とかx64とか入ってます。

これでAppxのビルド時に自動でコピーされるようになっていい感じになりました。

自動で追加できるようにすると、コピーするファイルをコンテンツでマークするのが面倒になります。その場合は、同じように、プロジェクトをアンロードして、編集して、Contentタグにワイルドカードを指定してあげるといい感じになります。

Azureaではこんな感じで指定してます。

  <ItemGroup>
    <Content Include="win32\Azurea.exe">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="win32\AzLang.dll">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="win32\Azurea.pdb">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="win32\AzLang.pdb">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="win32\ColorSchemes\*.txt">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="win32\Language\*.*">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
  </ItemGroup>

おしまい

MSDNでは.NETアプリのみを対象としてJavaScript UWPプロジェクトをいけにえにしてDesktop BridgeなAppxを作る方法が紹介されてましたが、普通のNativeアプリケーションでも工夫すればどうってことなかったです。

今回のエントリはパッケージを作成するところまでですが、署名鍵をストア申請用に変更するためにパッケージと予約名を関連付けるとかは、通常のUWOとおんなじです。いい記事もたくさんあるので参考にしてみるといいと思います。

ちなみに、ですが、現状Desktop Bridgeを使ったFull TrustなAppxは通常の方法ではストアに提出できません。だそうです。Full TrustなAppxが提出できるフラグをアカウントにつけてもらわないといけないので、Desktop Bridge を活用して、既存のアプリやゲームを Windows ストアに移行しましょうのフォームを送信する必要があるそうです*7

*1:実行コードはILで書いてあってCLRで実行されるので

*2:MSDNに書いてないけど

*3:MSDNに10.0.14393.0って書いてますが、どうもDesktop BridgeにバグがあってWindowsBSODすることがあるらしく、この問題が修正された10.0.14393.351を指定するほうがよさそうです。

*4:Run Full Trust あきらかにパワーがある

*5:ちなみにrunFullTrustなアプリはAppContainerで実行されないのでinternetClient capabilityとか書いても書かなくてもあんまり意味はありません。

*6:なのでプロジェクトに作ったwin32というディレクトリ名はなんでもよかったのです。

*7:先日やったばかりなので実際どうなってるのかはよくわかりません