2015/11/28

Windows 10 1511のバージョン判定

Windows 10のビルド10586というか、Threshold2というか、1151のバージョンをコード的にどう確認するかについて、以下の記事を参考にレジストリ情報を追加してみた。
レジストリを読んでいるだけだが、新しいReleaseIdに「1511」の値が出ている。BuildLabの方には「th2」の文字が入っている。その後ろにある「151112-1900」は2015/11/12 1900というリリース日時を示しているのかもしれない。

これを元に実用的な処理を組むにはあやふや過ぎるので、あくまで参考程度で。

2015/11/14

WPFのPer-Monitor DPIサポート(その1)

WPF自体のPer-Monitor DPIサポートについて。


従来、WPF自体にはPer-Monitor DPIのサポートはなく、Win32 APIを駆使する必要があったわけですが、.NET Framework 4.6.1の後のバージョンでようやくサポートが入るようです。
このエントリ中にあるサーベイに登録すればプレビュー版を試せるとのことで、登録しておいたところ、昨日招待メールが届いたのでダウンロードして試してみました。

ダウンロードできるのは.NET Framework 4.6.1のプレビュー版のようで、それを利用するサンプルコードは既にGitHubで公開されています。
このサンプルコードの範囲内で簡単にまとめると、以下が追加されています。
  • System.Windows名前空間
    • DpiScaleInfo構造体(DPI情報を格納する)

  • System.Windows.Media.VisualTreeHelperクラス
    • public static DpiScaleInfo GetDpi(Visual visual)メソッド
    • public static void SetRootDpi(Visual visual, DpiScaleInfo dpiInfo)メソッド

  • System.Windows.Windowクラス
    • protected override void OnDpiChanged(DpiScaleInfo oldDpiScaleInfo, DpiScaleInfo newDpiScaleInfo)メソッド

  • System.Windows.Controls.Imageクラス
    • protected override void OnDpiChanged(DpiScaleInfo oldDpiScaleInfo, DpiScaleInfo newDpiScaleInfo)メソッド
    • public event RoutedEventHandler DpiChangedイベントハンドラー
さらにコメントを見ると、大元のSystem.Windows.Media.VisualクラスにOnDpiChangedメソッドとDpiChangedイベントハンドラーが追加されるようです。

つまり、他の色々なイベント処理と同じように、各コントロールでDPI変化イベントを捉えて処理できるようになる、ということです。当然コントロールによって予め処理が作り込まれているものもあって、Windowクラスではモニターをまたがって移動したときに自動的にサイズ変更がされるようになっていました(位置はWM_DPICHANGED準拠)。さらに必要な処理があれば、OnDpiChangedをオーバーライドするなりDpiChangedに登録するなりして入れ込めばいいわけですね。

どんなものが来るのかなと思ってましたが、自然な拡張のようでとりあえず安心しました。

[追記1]

DpiChangedイベントハンドラーはRoutedEventHandlerとなっているとおり、引数はただのRoutedEventArgsなので、DPI情報を直接取得はできません。これは少しだけ面倒なので、以下のような専用のDpiChangedEventArgsを使うようにしてはどうかとフィードバックしてみました。

[追記2]

フィードバックへの返信で、このサポートが入るのは4.6.1ではなく、その後のバージョンだと訂正されたので、修正しました。

Managed Native Wifiライブラリ

WLAN Profile Viewerのモデルのコア部分を追加修正してライブラリとして公開しました。
名前のManagedとNativeが矛盾しているような感じもしますが、Native WifiというWin32 APIのマネージドラッパーという性格上、これが一番ストレートな気がしたので。

同種のものは既にManaged Wifiがありますが、これが大枠だけ提供するのに対して、このManaged Native Wifiはすぐ使えるメソッドを提供しています。非同期処理になるものについてはTAPでasync/awaitベースのメソッドも用意しています。

一応、ほぼ同じことはNetshでも可能ですが、反応がやはり遅いのと、処理の結果を非同期に受け取ることができないので(例えば、無線LANに接続するようリクエストはできても、接続できたか否かの結果は直接受け取れない)、使い勝手は劣ります。

1. 機能


現在の機能は以下のようなものです。

・利用可能なネットワーク、BSSネットワークの一覧取得。
・無線LANを(自動走査を待たずに)すぐ走査させる。
・無線プロファイルの一覧取得、追加、削除、順番の変更。
・無線LANへの接続、切断。

アプリのサブ機能でちょっと無線LANを利用したい、というぐらいのカジュアルな用途なら大体カバーできるんじゃないかと思います。というか、自分が昔ほしかった。

ただし、無線プロファイルの追加はプロファイルを構成するXMLを条件に合わせて自分で組み立てないといけないので、実は簡単ではないです。

2. 使用例


例として、現在利用可能な無線LANの中に、それに対応した無線プロファイルが存在していれば、そのうち最も信号状態のよい無線LANに接続するものです。

NativeWifiクラスのEnumerateAvailableNetworksメソッドは利用可能な無線LANの情報を収めたAvailableNetworkPackオブジェクトを列挙します。このProfileNameプロパティに、その無線LANに対応した無線プロファイルが存在していればそのプロファイル名が入っています。

まずこのProfileNameの有無でフィルターした後、同じくSignalQualityプロパティに信号状態が0-100の範囲で入っているので(大きいほどよい)、これの逆順で並び替え、最大のものを取得します。

これが取得できているかチェックした後、ConnectNetworkAsyncメソッドで非同期に接続を試みます。引数はAvailableNetworkPackオブジェクトから無線インターフェイスのID、プロファイル名、BSSの種別をそれぞれ渡します。最後はタイムアウト時間で、ここでは10秒を指定しています。この時間までに接続できればTrue、できなければFalseが戻り値として返ります。実際のところ、信号状態がよければ瞬時に繋がります。

こんな感じでさほど複雑ではないですが、WLAN Profile Viewerの中にもNativeWifiクラスの使用例があるので参考にしてください。

3. 課題

  • エラー処理: Native Wifiで起こり得るエラーについてMSDNでは網羅されてないので、実際どんなエラーが起きてどう処理すればいいのか、まだ煮詰まってません。

  • 取得する情報: Native Wifiで取得できる情報は多岐に渡るので、現在はその一部を拾い出している状態です。ここは使用シナリオに応じて検討の要あり。

  • Wi-Fi Direct: Windows 8以降、Native WifiにWi-Fi Direct関係の関数が追加されていますが、そもそもデスクトップアプリからのWi-Fi Directの使用方法がよく分かってないので、手つかずの状態。