はつねの日記

Kinect, Windows 10 UWP, Windows Azure, IoT, 電子工作

System.Net.WebSocketsはWindows 7では動かない

時々忘れがちになるのでまとめておきますね。

 

System.Net.WebSocketsはWindows 7では動かない

System.Net.WebSocketsを使ってWebSocketクライアントを作成したとき、Windows 8/8.1やWindows 10では問題なく稼働しますがWindows 7では実行時エラーで異常終了します。

これは

https://msdn.microsoft.com/ja-jp/library/system.net.websockets.websocket.aspx

-------引用開始

一部のクラスで、 System.Net.WebSockets 名前空間は、Windows 7Windows Vista SP2、および Windows Server 2008 でサポートされます。 ただし、クライアントとサーバー Websocket の唯一のパブリックの実装では、Windows 8 および Windows Server 2012となります。

-------引用終了

と注意書きがあるように、定義はあるけれどWindows 8以降じゃないと実装が伴っていないところがあるからです。

なぜ、こんなことがあるかといえば、Windowsカーネルモードドライバであるhttp.sysを直接利用することでHTTP周りのオーバーヘッドを少なくしているのですが、Windows 7のhttp.sysがWebSocketに対応していないからです。

Windwos 7のメインストリームサポートは終了しています

https://www.microsoft.com/ja-jp/atlife/article/windows10-portal/eos.aspx

みんな大好きWindows 7は2009年10月22日にライフサイクルがスタートして2015年1月13日にメインストリームサポートが終了しています。延長サポートの終了こそ2020年1月14日ということでまだ先ですが、延長サポート期間である現在はセキュリティ更新はおこなわれますが、仕様変更や新機能のリクエストはサポート対象外となり、これからWindows 7のHTTP.sysにWebSocket実装が追加されることはほぼないと考えてよいでしょう。

ではどうすればいいのか

一つの解決策としては、HTTP.sysを使わないWebSocket実装のコードを書く、もしくは、HTTP.sysを使っていないライブラリをNuGetで探してくるというものがあります。

https://github.com/kerryjiang/WebSocket4Net

https://github.com/sta/websocket-sharp

NuGetでライブラリを探すときは、企業ユースを考えるならばSystem.Net.WebSocketsならば対応している認証PROXYがサポートされているかなどのチェックを十分に行う必要があるでしょう。なお、残念ながら上記2つについてもまだきっちり調べ終わっていません。

 

しかし、System.Net.WebSocketsであればHTTP.sysを使って「オーバーヘッドが少ない」=「性能がよいことが期待される」なのにWindwos 7をサポートすることでその利点を得られないという問題が生じてしまいます。

対象となる機能がWindows 7でも使えないといけないのか、もしくは、対象となる利用者がWindows 7をどれくらい使っているのかを見極めて判断するといいでしょう。

企業でもWindows 7からWindows 8.1Windows 10への置き換え(少なくとも新規導入は8.1か10がデフォルト)が始まっている時期なので悩ましいところですね。

 

Windows 8以降かどうかをチェックする

Windows 7のときにはWebSocketを使った機能をdisableしたいときなどは、OSのバージョンチェックが必要になってきます。

対象はWPFとかWindowsフォームのときで、UWPやXamarin.Android、Xamarin.iOSのときは対象環境で動かないということはないのでチェックは不要です。

ですので実装時は

#if WPF

#endif

のようにifディレクティブを定義してその中でOSバージョンのメジャーバージョンとマイナーバージョンを取得してチェックします。

var searcher = new System.Management.ManagementObjectSearcher("SELECT * FROM Win32_OperatingSystem");
var os = searcher.Get().Cast().FirstOrDefault();
var major = 6;
var minor = 1;
if ((os != null) && (os["OsType"] != null) && (os["Version"] != null))
{
    if (os["OsType"].ToString() == "18")
    {
        major = new System.Version(os["Version"].ToString()).Major;
        minor = new System.Version(os["Version"].ToString()).Minor;
    }
}

Windows 10以上はmajor >= 10でよいのですが、Windows 8.xは、major == 6 && minor >= 2で判断しますので、その点だけ注意しましょう。

2017年10月の登壇予定

2017/10/21(土)

fukuten.connpass.com

ASP.NET系ばかりなので、.NETのクライアント側ネタで乗り込みます!って通常枠は埋まっているのでLTで!

2017/10/29(日)

2017.sendaiitfes.org

2日間イベントの2日目に登壇します。MRアプリ開発の入門をわかりすく解説します。

2017/10/11(水)

metadata-jp.org

開催案内はまだですが、「今まで待っていたものに名前がついた。それはMixed Realityだよとあなたは言った。」というタイトルでWinMRの世界観を30分でお伝えいたします。

 

Windows 10 Insider Preview Build 16294

一般の方にはもしかしたらなじみがなく、また、仕事道具を動かすプラットフォームとしてWindowsを使っている人にも縁がないものに、Insider Previewがあります。

あくまでも「いまつくっている最中のバージョンを様々な環境でまずはつかってもらおう」というものです。

一般公開前ですから品質的に問題があったり致命的なバグがあったりも覚悟しつつ、アプリ開発していたり、OSそのものの新しい機能をいち早くためしたいという人がちょっとだけ未来に一般公開されるバージョンを試せるものということです。

Insider Previewのリリース間隔がみじかくなってくると、秋に公開されるというFall Creators updateもそろそろなの?みたいな感覚が味わえるのもいい点ですね。

もちろん、品質や日本語訳の変な点をどんどんフィードバックするのもInsider Preview参加者の役目の1つだったりします。

 

16294でなにがかわったかといえば以下のような点。変わったというよりもほぼバグフィックス

  • Surface Pro 3でOSが起動できないバグの修正
  • オランダ版であったOneDriveからのダウンロード通知でクラッシュループが発生する問題の修正
  • expand.exeがファイル名に日本語が含まれているときに展開できない問題の修正
  • 0x800B010Cが発生する問題の修正
  • insider build 16291をインストールしようとすると0x80070057か0x8007071が発生する問題の解決

 

これをみて思うのは新機能の追加というよりも特定条件下で発生する問題の解決が多く、チューニングと汎用化の最終的な匙加減にはいてきたのかなって点。

よく「これくらいのバグをみつけられずにだしてくるのか?」なんて感想がブログで見受けられるけど、これ、なかなか面倒ですよね。対象ハードを絞れるといいだろうけれど。

あと、どうしてInsider Previewなのに「マイクロソフトも」みたいな感じで人格攻撃しちゃう人がいるのかはいつも不思議だったりします。問題点をかばう必要はないけど。きっと身近な人が失敗すると「だからお前はダメなんだ!」みたいな怒り方をしてそうですよね。

HoloLensアプリのサンプルプロジェクトをgithubで公開する

ソースコードを公開せずに多人数でHoloLensアプリを作るときは、「Visual Studio Team Services」などで非公開でやっていくとよいと感じです。

ちょっとしたサンプルコードならば、gistなどもいいでしょう。

サンプルプロジェクトを公開するならgithubがやっぱり一番よさそうです。

HoloLensアプリを公開するときはUnityプロジェクトとUWPプロジェクトでそれぞれ別の.gitignoreファイルを置けると便利です。

そこで次のようなフォルダ構造を作成し、UnityプロジェクトフォルダとVisualStudioソリューションフォルダにそれぞれに適した.gitignoreファイルを置きましょう。

[アプリ名フォルダ]

   +[Unityプロジェクトフォルダ]

       +assets

          |unityファイル

   +UWP

          |VisualStudioソリューションファイル

          +[プロジェクトフォルダ]

 

このフォルダの作り方やその他の詳細はHoloLensアプリ作成時の共通作業(2017年9月編)を参照してください。

 

github上にサンプルプロジェクトのリポジトリを作成

image

新規にリポジトリを作るときに下の方に[.gitignore]ドロップダウンリストがあるので、そこで「Unity」を選択して「アプリ名フォルダ」と同じ名前でリポジトリを作成します。

Unityを指定したときの.gitignoreファイルの内容は次のようになります。

--

/[Ll]ibrary/
/[Tt]emp/
/[Oo]bj/
/[Bb]uild/
/[Bb]uilds/
/Assets/AssetStoreTools*

# Visual Studio 2015 cache directory
/.vs/

# Autogenerated VS/MD/Consulo solution and project files
ExportedObj/
.consulo/
*.csproj
*.unityproj
*.sln
*.suo
*.tmp
*.user
*.userprefs
*.pidb
*.booproj
*.svd
*.pdb

# Unity3D generated meta files
*.pidb.meta

# Unity3D Generated File On Crash Reports
sysinfo.txt

# Builds
*.apk
*.unitypackage

--

リポジトリをローカルにクローンする

リポジトリができたならば、ローカル(自分のPC)にリポジトリをクローンします。

 

image

このとき、すでにサンプルプロジェクトを作ってしまっていたならば、作成済のサンプルプロジェクトのアプリ名フォルダをリネームしておきます。そして、その場所を指定してクローンします。

image

ローカルドライブにフォルダが作成できならば、このフォルダを「アプリ名フォルダ」としてHoloLensアプリのプロジェクトを作成します。

あらかじめ作成してありリネームしてあるならば、そのフォルダの中身を移動してきます。

image

クローン下フォルダに移動するだけでローカル側の変更として検知されます。ここで、.gitignoreファイルをUnityプロジェクトフォルダに移動します。

今回はUWP側はUnityから自動生成すればいいのでUWPフォルダを丸ごと削除します。

UWP側でも独自のコードを書いているのであれば、UWPファイルだには次のような.gitigoneファイルを配置します。

--

#ignore thumbnails created by windows
Thumbs.db
#Ignore files build by Visual Studio
*.obj
*.exe
*.pdb
*.user
*.aps
*.pch
*.vspscc
*_i.c
*_p.c
*.ncb
*.suo
*.tlb
*.tlh
*.bak
*.cache
*.ilk
*.log
*.dll
*.lib
*.sbr
*.msi
*.appx
obj/
bin/
TestResults/
AppPackages/
BundleArtifacts/
packages/
UpgradeLog*.*

--

コミットしてプッシュする

公開するコードがすべて格納出来たら、コミットを行い、プッシュします。

image

github上のUnityプロジェクトフォルダを見てみる次のようになります。

image

これでコードを公開できました。

github.com

HoloLensアプリ作成時の共通作業(2017年9月編)

HoloLensアプリを作成するときのフォルダ構成を公開します。

[アプリ名フォルダ]

   +[Unityプロジェクトフォルダ]

       +assets

          |unityファイル

   +UWP

          |VisualStudioソリューションファイル

          +[プロジェクトフォルダ]

こんな感じにUnity関連とUWP関連が別フォルダになるようにしていて、その2つのフォルダをアプリ名フォルダの下に作っています。

こうすることでまとめてドンっと開発環境渡したいときは[アプリ名フォルダ]まるごとzipにして渡してしまえばいいですね。

githubにあげるときも同様ですが、Unity環境とUWP環境で除外したいファイルが違ったりするので、UnityプロジェクトフォルダとUWPフォルダにそれぞれ.gitignoreを記述しておくとよいでしょう。

 

Unityプロジェクトを新規作成するときの考慮点

そのためには、HoloLensアプリを作るときにUnityを立ち上げたら、例えば次のように[Project Name]欄に記載する値と、[Location]欄に記載するフォルダ名の最後をまずは一致させておきます。

image

HoloToolkit-Unityの追加

Unityプロジェクトができあがったら、提携作業としてまずはHoloToolkit-Unityをアセットとして追加します。

githubのreleaseにアセットパッケージファイルがあるのであらかじめダウンロードしておきます。

2017/09/06現在、私が使っている環境は、

Unity 5.6.2f1

なので、HoloToolkit-Unityもv1.5.8.0になります。

image

[Assets]-[Import Package]-[Custom Package]メニューでダウンロードしたアセットパッケージファイルを指定します。

image

アセットが追加されるとメニューなども拡張されるので、HoloToolkitメニューからいつものConfigurationをやっておきましょう。

シーンの保存

Unityのシーンを保存したいときは、プロジェクト名と同じ名前で保存しています。

image

Build Settings (2017年9月編)

HoloLensに搭載されたOSはまだWindows 10 Anniversary Updateなので、開発環境がCreators UpdateやFall Creators Updateだったりした場合には、UWP SDKとして10.0.14393.0を明示的に選択します。

image

また、[Unity C# Projects]チェックもデフォルト状態ではついていないのでこれもつけておきます。

UWPソリューションを出力するときの考慮点

image

UWPフォルダは最初できていないので[新しいフォルダー]をクリックしてフォルダを作成して名前を「UWP」にします。

UWPのソリューション構成は次のように3つのプロジェクトから構成されます。

image

*ここでVisual Studio 2015 Update 3を使っていると特に問題なく、HoloLensをUSBで接続した途にビルドタイプ「x86」にして出力先を「Device」にすればHoloLensでアプリが立ち上がります。

 

さて、現状のUnity 5.6.2f1からだとVisual Studio 2017を使うとエラーでビルドが失敗します(15.3.3でも失敗する)。

原因は、上2つのプロジェクトのcsprojファイルで記載されている

RunSerializationWeaver

の実行プロセスで

System.Collections.Generic.KeyNotFoundException: 指定されたキーはディレクトリ内に存在しませんでした。

というエラーが発生して

UWP\GeneratedProjectsUWP\Assembly-CSharp-firstpass\bin\x86\Debug\Assembly-CSharp-firstpass.dll

UWP\GeneratedProjects\UWP\Assembly-CSharp\bin\x86\Debug\Assembly-CSharp.dll

が作成されないからです。

また、最後の1つのプロジェクトでも

UWP\Unity\Tools\AssemblyConverter.exeの実行プロセスで

System.Collections.Generic.KeyNotFoundException: 指定されたキーはディレクトリ内に存在しませんでした。

というエラーが発生します。

 

どうやらこれを解決するためには、Unity 5.6ならばVisual Studio 2015にするか、Visual Studio 2017にしたいならUnity側をUnity 2017.1.0p5にするしかないようです。

でも、Unity 2017用のHoloToolKit-Unity (Unity 2017用だとMixedRealityToolkit-Unity) は、Pre-releaseなんですよね。

HololensのSpatialMappingのメッシュをきれいにする

HoloLens Toolkit-UnityあらためMixed Reality Toolkit-UnityのSpatialMappingを使うと空間認識を行って、Unity空間の中に現実世界の床や壁を反映してくれます。

SpatialMapping

やり方は簡単で、[SpatialMapping]-[Prefabs]から[SpatialMapping]オブジェクトをHierarchyウィンドウにドラッグアンドドロップするだけであとは自動的に良しなにやってくれます。

20170823_124703_HoloLens

起動するとすぐに空間認識が始まって、その進行に合わせて不定形のメッシュが描画されていきます。

 

SpatialUnderstanding

SpatialMappingを使うと手軽に空間メッシュ表示が得られますが、平面に合わせてもう少し綺麗に賽の目で表示してほしいときがあると思います。そういったときはSpatialUnderstandingを「追加」します。

やり方は、[SpatialUnderstanding]-[Prefabs]から[SpatialUnderstanding]オブジェクトをHierarchyウィンドウにドラッグアンドドロップします。

あとは以下の点を修正するのみです。

  1. SpatialMapping側でメッシュ描画は不要なのでSpatialMappingオブジェクトの[Draw Visual Meshes]プロパティのチェックを外す

 

20170823_130049_HoloLens

SpatialMappingオブジェクトが動作していることを前提としてSpatialUnderstandingオブジェクトは動作するので、SpatialMapping側の[Auto Start Observer]プロパティのチェックを外したりすると動かなくなりますのでご注意ください。

 

動作環境:

Unity 5.6.2f1 + Visual Studio 2017 Update 3

ターゲットバージョン Windows 10 Anniversary Edition (10.0.14393)

Visual Studio 2017 Update 3がリリースされました。

blogs.msdn.microsoft.com

Visual Studio 2017 Update 3 (Ver 15.3.0)がリリースされました。

 

サイトからダウンロードでもいいのですが、Visual Studio 2017をインストールしたときにインストールされるVisual Studio Installerを立ち上げるとUpdate 3の更新を求められるので、サクッと更新してから画面上の[変更]ボタンを押して各種必要なものをUpdate 3に置き換えていくのがいいでしょう。

とはいえ、UnityとかはUpdate 3よりも更新が進んでいるので、必要に応じて、Visual Studio Installerからインストールした後に、プログラムの追加と削除からUnityをアンインストールしてUnityのサイトからUnity 2017をダウンロードしてインストールしてあげるといいでしょう。

それでは、よりVisual Studioライフを!