WGGの活動log

都内でゲーム開発だったりVRだったりをしてるかもしれないエンジニアです. WGGは「ワグ」と読みます

Windows10のショートカットキーが重い件(Superfetch)

最近,Windowsに備わってるショートカットキー登録機能を多用するようにしました.

f:id:wgg00sh:20170130174547p:plain

ショートカットキー登録

【Windows10】 自分でショートカットを設定。効率化で差をつけよう。
interprism.hatenablog.com


よく使うファイル(ブラウザの.lnkなど)に対して,即時に起動するショートカットキーを設定することができます.
Ctrl,Shift,Altと,アルファベットなどの組み合わせで設定できます.
(実行中のアプリケーションと干渉する場合もあるので注意:Ctrl+Shift+Sなんかは名前を付けて保存と被ったり)

で,このショートカットキーを登録したファイルを,デスクトップかスタートメニューの中に入れておくと,そのキーを押した瞬間に実行されます.
僕はデスクトップに物は置かないのでスタートメニュー安定ですね.

ここに置くとショートカットキーが使用できるようになります
C:\ProgramData\Microsoft\Windows\Start Menu


と,ここまで聞けば中々に便利な機能だったのですが...

めっちゃ反応が遅い

はい,大きな問題が見つかりました.
何故かキーを押しても実行されるまでにタイムラグが存在するのです.
僕の場合は約1.5秒~2秒ほどの遅延が起こりました.
すぐに起動するために使う機能なのに,このような遅延は認めません

原因を探す

とりあえず,いつものMicrosoftのコミュニティを見に行ってみると,同じ現象が起こっている人がいました.
answers.microsoft.com

この中を覗いていると,こんな書き込みが

Windows7Windows8.xの時にもショートカットキーが反応しなくなる事がよくありましたが、これらはタスクバー通知領域のアイコンがアニメーションを行っている間に起きる事が大半でした。
常駐ものが通知領域アイコンを書き換えるとしばらくの間シェルが反応がしなくなるんですね。
通知領域アイコンを書き換えるアプリなるべく隠すようにして、なだめなだめ、何年も使ってきましたw

ずっと放置されてきた上記のバグがWindows10で治っているとはとても思えませんが、
Windows10ではこれに加えて更に
  「ストアアプリなどが中断状態になっているとショートカットキーの反応が鈍くなる」
という病気が追加されてしまったようです。

なんか,意味わからないですね...
更に続きに,

恐らく
SearchUI.exe / ShellExperienceHost.exe / Microsoft.Photos.exe / WinStore.Mobile.exe / Video.UI.exe
あたりが「中断」状態で見つかると思います。

f:id:wgg00sh:20170130180415p:plain
ありました.
調べたところ,SearchUIはWin+Qで出てくる検索機能を制御してるらしく,消すべきではないようでした.(Cortanaとは別).
ShellExperienceHostも,シェルまわりの制御にかかわっているようで,そこそこの頻度で端末を開く自分にとっては消すべきではなさそうでした.
さっきのSSには映っていませんでしたが,時々「Calclator」や「SystemSettings」といったプログラムも中断状態で見つかることがありました.

解決案1:強引に消す

ってことでここまで得られた情報から,「中断状態のアプリを完全に消すと,ショートカットキーの遅延が解消する」らしいことが分かったので,さっそく強引ですが,中断状態のアプリを終了するスクリプト(ps1)を書いてみました

$task=
  "Microsoft.Photos",
  "SystemSettings",
  "Calculator",
  "Video.UI",
	
for($i=0;$i -le $task.length-1;$i++)
{
  stop-process -name $task[$i] | out-null
}

これをショートカットキーに登録して,他のショートカットキーが遅延すると感じたときは,このスクリプトを呼び出してやると暫くの間は遅延が解消されます.
しかし,中断中のアプリを強引に消したりと,これ根本的な解決になってないですね...

また調べる

こんな書き込みが
sakebear.ddo.jp

原因は"Superfetch"サービスです。

Superfetchサービスについて,知らなかったので少し調べてみました.
とりあえず,Wikipediaから

Windows SuperFetch(ウィンドウズ スーパーフェッチ)とはWindows VistaWindows 7Windows 8/8.1、Windows 10に搭載されている、パフォーマンスの向上に関するディスクキャッシュ・メインメモリ管理機能である。

ユーザーの操作パターンと、アプリケーション(オフィスアプリケーション等)やバックグラウンドプロセス(ウイルス検索など)との挙動を記録・分析し、予測により効率的なメモリ管理を行う
例として、ユーザーが操作していない時間帯に、ウイルス検索がバックグラウンドで実施され、アプリケーションが使用するメモリがスワップアウトされたとする。SuperFetchはこれらの挙動を監視して、ウイルス検索が終了した後に、スワップアウトされたアプリケーションの使用メモリを再び、自動的に(予測的に)スワップインさせる。

Windows SuperFetch - Wikipedia

確かにこれっぽいですね
恐らくこいつがストアアプリを終了しても中断状態で留めていたのでしょう
ただ便利そうなこともしてるっぽいです.

Superfetchを止めてみる

Win+X→Gで,「コンピューターの管理」を起動→"コンピューターの管理"→"サービスとアプリケーション"→"サービス"の順に選択します.Superfetchの「スタートアップの種類」が恐らく自動になっているので,手動または無効に変更します.

これで起動時にSuperfetchが実行されないので,ショートカットキーの遅延がなくなりました

まとめ

Superfetchを起動しないようにしたら,ショートカットキーが素早く実行できるようになりました.
ですが,Superfetch実行しないことによる弊害も考えられるので,もう少し詳しく調べたいですねー

Windows 10でシャットダウン時にエラーが出るようになった(DDE Server Window)

最近,PCをシャットダウンするときにこんなメッセージが出るようになりました(シャットダウン中にてSSが撮影できないので直撮り).

OS:Windows10 Home
バージョン:1607

f:id:wgg00sh:20170127184606p:plain


正直この手のエラーは放置しておくと後にどうなるかわからないし,原因の特定もし辛くなるので早急に解決しようと思いました.
以下その時行った対応のメモ書きです.

1.イベントビューワから確認

こういうメッセージなどはログが保存されているはず...
[Win+R]でファイル名を指定して実行→"eventvwr"でOK
色々探し回ったら「Windowsログ」→「システム」の中に見つかった.

f:id:wgg00sh:20170127185457p:plain
f:id:wgg00sh:20170127185504p:plain

2.ググる

どういったエラーが起きているかはこれで分かったので,調べてみます.

answers.microsoft.com

ここを見て,別の問題ですが対応例が載っていました

1.クリーンブートで常駐ソフトの影響が有るかチェックした→改善出来ず失敗
2.ディスククリーンを実施して影響しそうな不要ファイルを削除した→改善出来ず失敗
3.regeditエディターによるデーターの変更/削除→効果なし失敗 (googl検索参照)
4.別アカウントを立ち上げてみたがまったく同じエラーが出て→失敗

とりあえずすぐに確認できる4から試してみました.すると,メインのアカウントからサインアウトする時にも同じメッセージが発生し,別のアカウントからサインアウト/シャットダウンするときには発生しませんでした.
つまり,この時点で「シャットダウン時の問題」ではなく,「サインアウト時の問題」だったことがわかりました.

つまり,PC自体の問題ではなく,普段使っているアカウントの設定に問題がありそう,ということが推測できます.

3.もっとググる

DDE serverなどで更に調べてたらこんなページを見つけました
answers.microsoft.com

When I turn off Taskbar/Automatically hide the tasbar in desktop mode, then the error is solved.

「『デスクトップモードでタスクバーを自動的に隠す』をオフにするとこの問題は解決しました.」
えっマジか...
今回のメッセージが出るようになる少し前にちょうどタスクバーを自動的に隠すように変更したところでした.
一度タスクバーを自動的に隠すをオフにしてみると,あっさりサインアウト,シャットダウン時にメッセージは出なくなって解決しました.
確かにこの設定はアカウントごとに変えられる部分ですね...
ですが別のアカウントでタスクバーを自動的に隠すようにしても,サインアウト時に今回のメッセージは表示されませんでした,何故だ...

4.直ったが根本的な解決に至らず

とりあえず今回のトラブルは解決したのですが,何故タスクバーを自動的に隠すようにするだけでエラーが起こるようになるのか,はっきりとわかりませんでした.今は丁度テスト期間で時間もあまり割けないのでまた今度調べてみます.

CTF SECCON TOWERに挑んでみました

解けなかったのでwriteupじゃないです.感想です.


12/10 15:00~12/11 15:00までの間,「SECCON 2016 Online CTF」というセキュリティの大会が行われていました.

僕はセキュリティについてほとんど勉強をしたことがなかったのですが,とあるチームに入って参加してみました.

CTFとは

キャプチャー・ザ・フラッグ - Wikipedia

与えられた問題文,データから,プログラムの脆弱性を見つけるなどして隠されたFlagを手に入れろってルールです
例えば,暗号化された文章が用意されて,それを復号化するとか,
Webアプリケーションが用意されて,そこに不正アクセスするとか...
そんな感じのセキュリティの知識を競う大会です.

SECCON TOWER

まぁ,予想はしてたのですが,素人の僕がいきなり挑んで勝てる問題は殆ど無かったです.
でも面白そうな問題が1問,それがこの「SECCON TOWER」でした.

PNG over Telegraph

PNG over Telegraph
Analyze signal in this video.
You will able to get PNG, if you success to decode it.
https://youtu.be/Y6voaURtKlM

Youtubeの動画が与えられて,この動画からPNG画像を手に入れろという問題です
動画を再生してみると...
f:id:wgg00sh:20161211180044p:plain

なんかよくわからない機械がぐるぐる回ってます.50分間それが流れるだけの動画でした.

解いてみる

チームメイトと考えていたら,「動画初めに書かれている英文と動きが対応しているのでは?」と推測したので,
動画の0:12~1:10頃に書かれる英文と,動きを眺めてみると,「1つの姿勢=1つの文字」と対応しているっぽいことがわかりました.
動画内の全てのアルファベットと,動きを対応付けてみたら,下のようになりました.

f:id:wgg00sh:20161211181922p:plain

足りない文字がありますね...
でも近辺の文字から推測できそうです.
A~Hが子の腕が同じ姿勢で中心が45度回りの1つのグループ,
I~QのうちJを除いた8つが同じく1つのグループ,
R~Yも1つのグループっぽいです.

f:id:wgg00sh:20161211181940p:plain

Zは推測できませんでした...

動画から姿勢を抜き出す

流石に50分の動画を見続けるのは苦痛なので,プログラムで全ての動きを抽出してみました.
c++とopencv3.1を使用しています

void capture()
{
  VideoCapture video("SECCON TOWER 2016.mp4");

  const int OFFSET = 15;
  const int START_POS = 2250 + OFFSET;
  const double FPS = 29.97;
  video.set(CV_CAP_PROP_POS_FRAMES, START_POS);
  int i = 0;
  while (1)
  {
    Mat frame;
    i++;
    video >> frame;
    video.set(CV_CAP_PROP_POS_FRAMES, START_POS + i * FPS);
    if (frame.empty() || waitKey(30) >= 0 || video.get(CV_CAP_PROP_POS_AVI_RATIO) == 1) {
      break;
    }
    string fName = "image/"+to_string(i)+".jpg";
    imwrite(fName, frame);
  }
}

できあがったのがこれ↓
f:id:wgg00sh:20161211182930p:plain
3000枚近くの画像が生成されました.

自動で識別する

この3000枚の画像を手作業でアルファベットに置き換えていては時間が足りません.
そこで,画像を与えたらどの文字なのか返してくれる処理を作ります.
考え方としては,
「『入力画像』と『25種類のサンプル画像』を比較して,最も似ているものが,対応する文字」
と決めつけます.
まずは画像に無駄な部分が多すぎるので機械だけが映るようにトリミングします.
f:id:wgg00sh:20161211183459p:plain

そして,先に作った姿勢ー文字の対応表を見ながら25枚のサンプル画像を探し出します.
同じ文字であれば,別の画像でも殆ど同じように映ると予測しています.

類似度計算

入力画像,サンプル画像に対してそれぞれ,グレースケール化をした後に画像の類似度を計算します.
25枚のサンプル画像との類似度で最も高いものを選別します.

void convert1(Mat &mat)
{
  cvtColor(mat, mat, CV_BGR2GRAY);
}

void similarly()
{
  const int FIRST = 3;
  const int LAST = 2982;
  const int CHARA = 25;

  int channels[] = { 0 };
  int dimNum = 1;
  int binNum = 64;
  int binNums[] = { binNum };
  float range[] = { 0,256 };
  const float *ranges[] = { range };

  int sampleNum[CHARA] =
  {16,11,271,252,634,4,
    570,652,12,1014,27,102,44,
    856,2059,514,41,2018,992,53,84,
    959,33,104,686,};
  MatND sampleHist[CHARA];
  for (int i = 0; i < CHARA; i++) {
    string fName = "resize/" + to_string(sampleNum[i]) + ".jpg";
    Mat mat = imread(fName);
    convert1(mat);
    calcHist(&mat, 1, channels, Mat(), sampleHist[i], dimNum, binNums, ranges);
  }

  for (int i = FIRST; i <= LAST; i++) {
    string fName = "resize/" + to_string(i) + ".jpg";
    Mat mat = imread(fName);
    MatND hist;
    double similarly;
    convert1(mat);
    calcHist(&mat, 1, channels, Mat(), hist, dimNum, binNums, ranges);

    int max = 0;
    int maxPos = -1;
    for (int j = 0; j < CHARA; j++) {
      similarly = compareHist(hist, sampleHist[j], CV_COMP_INTERSECT);
      if (max < similarly) {
        max = similarly;
        maxPos = j;
      }
    }

    char c = 'A' + maxPos;
    cout << c;
  }
  cout<<endl;
}

実行結果
f:id:wgg00sh:20161211184356p:plain

「目視したのと全然違う...」
どうやら計算誤差が発生して希望通りの符号を返してくれませんでした.

誤差の原因

動画の前半と後半の画像を見比べてみました

f:id:wgg00sh:20161211184831p:plainf:id:wgg00sh:20161211184840p:plain

↓横に並べます
f:id:wgg00sh:20161211184919p:plain

「なんかずれてる...」

もうダメぽ

というわけで,カメラの位置が時間経過で動くことに気づいて,それを補正するトリミングを実装する途中で時間切れになってしまいました...

敗因

一番大きいのは類似度計算に頼った点かもしれないですね
画像の状態が変化
すると敏感に反応するので
子の腕の黒色部分の位置と向きを入力画像から識別するマッチングが実装できれば結果は変わったかも...

腕木暗号

www.silex.jp
今回出題された問題は「腕木通信」と呼ばれる情報の伝達方法の一つらしいです.
あと正しく解読できればCTFおなじみのQRコードの画像が生成されたらしいですが,自分にはできませんでした...

おわりに

学校の授業でちょうど最近まで画像処理の実験をやっていたので,その成果を実践できる良い機会でした.
できれば正解してチームに貢献したかったのですが解けなくて悔しかったです.

初めてCTFに挑戦したのですがとても楽しかったのでまた機会があればやってみたいですね~

過去に接続した無線LANに自動で接続するPowerShell Script書いた

最近PowerShellで遊んでいます.




前置き

Windowsを使ってると,時々突然WiFiが切れてイラっとすることがありました.
もしくは,起動したときに普段使いの無線LANに繋がっていない時がありました.
再接続するにはタスクバーからインターネットアクセスを選んで,接続したいネットワークを選んで,接続ボタンを押す必要があります

f:id:wgg00sh:20161111130338p:plain
f:id:wgg00sh:20161111130501p:plain
f:id:wgg00sh:20161111130544p:plain

これって結構面倒じゃないですか?

コマンド入力するか,アイコンをダブルクリックするだけで勝手にWiFiに繋いでくれる,そんなことができたらいいな~って思ったのでちょっと書いてみました

完成したスクリプト

Windows無線LANの設定などを変更するので,.ps1ファイルで作成します

chcp 65001

$profiles
$lans
$i
$length
$result
$successMessage="Connection request was completed successfully."

netsh wlan disconnect
$profiles=(netsh wlan show profiles)
$length=$profiles.length

for($i=0; $i -lt $length;$i++)
{
    if($profiles[$i] -match ": ")
    {
        $lanName=$profiles[$i].Split(":")[1].Split(" ")
        echo($lanName[1])
        $result=(netsh wlan connect name=($lanName[1]))
        echo $result
        if($result -eq $successMessage)
        {
            echo(" `n` `n` Connection successed !!")
            exit
        }
        echo(" `n``n` Connection failed...")
    }
}

↑のコードを適当なファイルに記述して,拡張子.ps1で保存しPowerShellで実行すれば登録されている無線LANに自動で繋いでくれます

実行ポリシーの変更

...のですが,PowerShellはデフォルトではスクリプトを実行できません.セキュリティとかの問題ですね
僕が前に書いた記事とか↓に実行ポリシーを変更する方法が書いてあるので,必要に応じて変更してみてください
wgg.hatenablog.jp
qiita.com

まだアイコンダブルクリックで実行できない

PowerShellスクリプトは,アイコンをダブルクリックしてもメモ帳などのエディタが開くだけで実行してくれません.
ですが,従来のコマンドプロンプトのbatファイルはダブルクリックで実行できます
そこで作成したPoweShellスクリプトを実行するためのコマンドプロンプトのバッチファイルを作ります

@echo off
powershell -Command "***.ps1"
.ps1に作成したPowerShellスクリプトのパスを渡します

拡張子を.batで保存すれば,そのbatファイルをダブルクリックするだけでPowerShellスクリプトが実行できるようになります
アイコンからじゃなくコマンドで実行したいって場合は環境変数弄るとできます

コードの説明

batファイルの方はPowerShellを起動して,引数のスクリプトを実行しているだけなので省略します

chcp 65001

文字コードの設定です
実行する環境によって文字コードが違った場合,実行したコマンドの返り値が変わったり文字化けしたりする場合があります
なので,どこでも同じように実行するために環境の統一ですね

次の6行は変数宣言です
一部無くても大丈夫ですが,一応

netsh wlan disconnect

無線LANの接続を終了します
この後で接続するので,一旦切りますね

$profiles=(netsh wlan show profiles)

(netsh wlan show profiles)の実行結果を変数$profilesに代入します
(netsh wlan show profiles)のみ実行すると,実行結果が出力されます
PowerShellScriptでは,コマンドの実行結果は返り値として扱われるので,変数に代入することで実行結果を保存することができます
f:id:wgg00sh:20161111150758p:plain
↑こんな感じで,右下の隠し部分に登録済みのネットワークが表示されます
また,変数$profilesにはこの出力結果が配列として1行ずつ格納されます.

for($i=0; $i -lt $length;$i++)

c言語とかで書くなら

for(i=0;i<length;i++)

になるいつものfor文です
$profilesを1行ずつ操作していきます.

if($profiles[$i] -match ": ")

(netsh wlan show profiles)の実行結果から,セミコロン+空白(: )の右に無線LANの名前が書かれていることが分かったので,それを含む行に対してのみ次の処理を行います

$lanName=$profiles[$i].Split(":")[1].Split(" ")

1行毎に,セミコロンで区切った後,その後ろ側を空白で再度区切ります
かなり雑に作ってるので,もっとスマートな書き方がありそうです
しかもこの書き方だと無線LANの名前に空白が含まれていたらそこも分割してしまいます.
これを実行すると,$lanNameには
$lanName[0]=" " (空白スペース1つのみ)
$lanName[1]="***" (ネットワークの名前)
となるので,$lanName[1]を利用して,次に接続要求を行います

$echoはいわゆるprintfなので省略

$result=(netsh wlan connect name=($lanName[1]))

(netsh wlan connect name= STR)でSTRに対して接続要求を行います
$result=...としているので,その実行結果を変数$resultに格納します
これは,成功したか失敗したかを判定するのに使用します

if($result -eq $successMessage)
  • eqは == です,同一かどうか判定しています.

実行結果が成功時に出力される文字列なら接続に成功したとみなして処理を終了,
失敗していたらforのカウントを進めて次のネットワークで再接続します

終わりに

こんな感じで,使うかわからないスクリプトを作成することができました.
自分の環境でしか試していないのでもしかしたら不具合起きるかもしれません.
というか自分の環境でも接続できないはずのネットワークに対して成功時のメッセージが出たりと,不具合が出ることがありました

あとは,このコードだと登録順に接続するので,あまり使いたくないネットワークに勝手に接続してしまうかもしれません
その場合は,$profilesを手書きして,優先度の高いネットワークから順に書くなどすると良いかもしれませんね
また,この方法だけだと,公共のWiFiによくあるWebページを開いて,そこで再度認証するタイプに対応できないので,必要ならそこも対応する必要がありますね