Win32 APIをてなずけよう
-
Upload
kouji-matsui -
Category
Software
-
view
5.112 -
download
3
Transcript of Win32 APIをてなずけよう
Win32 APIを手なずけよう!2015.12.12 プロ生@名古屋 KOUJI MATSUI (@KEKYO2)
自己紹介
けきょ (@kekyo2)
ロードバイク乗り
Microsoft MVP for Visual Studio and Development Technology
認定スクラムマスター・スクラムプロダクトオーナー
Center CLRオーガナイザー
今日のお題
.NETからWin32 APIを使って、.NETだけでは難しいことをしよう
巷ではUWPが流行ってますが…
デスクトップアプリケーションが避けられない場面はあるはずです!!◦最近はやりのIoT (Out of box unitと通信する)
◦ Microsoft KinectやIntel RealSenseカメラ
◦ USB機器(libusb)
◦ OpenGL / DirectX
◦サードパーティ製ライブラリ群
… そしてWin32 API
Win32 APIとなかよくする
と言いながら、C++でがりがり書くのは色々つらい。
C#から、どうやってWin32 APIにアクセスするか?
これが出来れば、いろんなことに応用できる!!
デスクトップを駆けるプロ生ちゃん
ウインドウの上を走ってくよ~
WPFだけではどうにもならない…
デスクトップ上のどこにウインドウがあるのか?
表示されているウインドウが全て列挙出来れば、ウインドウの上の縁の座標が分かる。
あとは計算で何とかなりそう?
②ウインドウの上辺が分かるので③上に乗るような感じで横に移動させる
①ウインドウの座標が分かれば
落ちた時の着地点
落ちた時の着地点は、現在位置→次の位置(等加速度運動)で決まる線分と、ウインドウ上辺が交差するところ。
①現在の座標
②次の座標
③ウインドウの上辺と交差する座標→全てのウインドウを検査する
考え方はおk?
ウインドウを調べる
デスクトップ上のウインドウを全て列挙するには、「EnumWindows」APIを使います。
https://msdn.microsoft.com/ja-jp/library/cc410851.aspx又は、EnumWindowsでググる
C#からWin32 APIは直接呼べません
EnumWindowsを呼べば、すべてのウインドウの位置が分かる。
でもC#のコードで”EnumWindows”と書いても、もちろん呼び出せない。
こういう時には、「P/Invoke」という機能を使います。
P/Invokeするには
Win32 APIに対応するP/Invokeの定義をC#で書きます。
EnumWindows APIの定義(C言語による)
EnumWindows APIの定義(P/Invoke C#)
P/Invokeの定義
APIがどのDLLに定義されているか?(DllImport属性)
API名はほとんどの場合C言語のAPI名と同じ
引数と戻り値の並びは同じだけど、型は要注意
ぴよぴよ
どうやって書けば?
そんなP/Invoke初心者のために「pinvoke.net」
コミュニティベースで、Win32 APIのP/Invoke定義を蓄積
pinvoke.net
例:「EnumWindows dllimport」とかでググると、大抵トップに出てくる。
コミュニティベースの定義なので、定義の質はまちまち。
複数載ってたりする(俺はこんな定義は我慢ならない、と思ったのかも)ので、良さげなやつを選択する。
この定義をベースに、細かく修正するという手法はアリ。
主に型定義によるばらつきが多い感あるあと、過剰な属性か足りないか…
EnumWindows P/Invokeの詳細
コールバック関数はデリゲートとして定義できる
SetLastErrorでエラーコードを返すAPIの場合は、これを追加する
EnumWindowsを使う
EnumWindowProcデリゲートに相当する実装。列挙されたウインドウハンドルをリストに蓄積します。
APIが失敗するとfalseを返すので、その場合はGetHRForLastWin32Errorでエラーコードを取得して、対応する例外をThrowExceptionForHRでスローします。
ウインドウの矩形を得るには
ウインドウハンドルからウインドウの矩形座標を得るには、
GetWindowRect APIを使います。
RECT構造体が必要(LPRECTはRECTへのポインタ)
ウインドウの矩形を得るには
RECT構造体のP/Invoke表現です。これもpinvoke.netで探せます。
ウインドウハンドルからウインドウの矩形座標を得るには、
GetWindowRect APIを使います。
GetWindowRectを使う
呼び出すだけ。エラー処理はEnumWindowsと同じ。
その他必要なAPI
ウインドウが可視状態かどうか→ IsWindowVisible◦見えていないウインドウは除外します。
デスクトップ全体の矩形を取得する→ SystemParametersInfo◦画面外まで移動したかどうかを判定するのに使います。
ウインドウの矩形を再設定する→ SetWindowPos◦プロ生ちゃんアイコンの移動に使用します。(WPFデータバインディングでの移動に不備があるため)
WPFウインドウからハンドルを得る
WPFのウインドウクラスからウインドウハンドルを取得すれば、WPFウインドウに対して、Win32 APIを適用できます。
WindowInteropHelperクラスを使って、Windowクラスのハンドルを操作
内部でSetWindowPos APIを呼び出す
総仕上げ
デスクトップ上のウインドウ群の矩形座標が手に入ったので上辺群を抽出
歩行中と落下中をステートマシンで管理
落下中は交点座標を計算→ 結果が得られれば着地!
上辺の左端を超えたら落下
画面外に出たら最初の座標にリセット
アイコン(透過PNG)で透過ウインドウを作って表示
歩行時はアイコンを切り替えてアニメーション
タイマーで定期的にステートマシンを実行
デモ
もっと面白くするために
アニメーションパターンを増やしたいね(レベル低)◦せっかく色々イメージがあるので…
反対にも移動したいね(レベル低)◦上辺の端まで来たら気まぐれで反転するとか
ちゃんと終われるようにしたい(レベル低)◦タスクトレイに常駐!
ウインドウ移動に追従したいね(レベル中)◦ウインドウを移動したら、上辺に乗っかったまま移動とか
ウインドウのZオーダーを認識したい(レベル高)◦裏に回っているウインドウにも着地してしまうよ◦手前ウインドウにさえぎられて移動できない場合は反転とか
ご清聴ありがとうございました!
GitHub: Pronama.InteropDemo
https://github.com/kekyo/Pronama.InteropDemo
スライドはブログに上げます
http://www.kekyo.net/
第五回Center CLR年末会やります (2015.12.26)
名古屋市中生涯学習センターhttps://centerclr.doorkeeper.jp/events/34349