C#(WPF)とDLLでシステムコマンドをグローバルフックする
先日、BUFFALO製のマウスやキーボードを他の機器にBlueToothを飛ばせる製品を購入しました
BlueTooth製品の入力を別のBlueToothとして飛ばしたりできて非常に面白いし使いやすい商品!
・・・・だった・・のですが!
飛ばす元でAltキーを単発で押すとメニューにフォーカスが移ってしまい、
気付かないうちに設定を変更してしまうという問題に直面しました
「その動きだけ制約加えるソフト作成してみよっかな」と思い立って作り始めたのですが
・どうもグローバルフックが必要 しかもDLL化しないとダメ。言語はもう忘れ気味のC++
・資料が古いものばかり DEFファイルなんてほとんど作ったことないよ・・・
・APP側がC#で作成されているサンプルが少ない
・フック横取りして無効化しているのはキー入力ばかりでシステム系のものが見当たらない
ということでブログに書くことにしました!
製作環境はVS2015の無料のやつです
まずはDLLから始めます
新規作成 > C++のWin32プロジェクト > 名前はHook > OK > 次へ >DLLにチェック > 完了
dllmain.cppを以下に書き換える(ヘッダー追加するまでエラーでてるけど気にしない)
次にソリューションのヘッダーファイルを右くり > 追加 > 新しい項目 > Hook.h を作成
中身は以下
ビルドしたらDLL完成
次にC#側でAPPを作成開始!
新規作成 > WPFアプリケーション > LockAltMenuという名前で作成
常駐ソフトにするので、まずはソリューションにあるMainWindowsを削除
App.xaml内 の StartupUri="MainWindow.xaml" という部分も削除
App.xaml.csを以下に書き換える
参照にSystem.Windows.FormsとSystem.Drawingを追加
プロジェクト右クリック > プロパティ > リソース > icon.ico という適当な画像をドラッグしてアイコンリソースを作成
最後に先ほど作ったDLLを実行ファイルと同じ場所に移動※!これで完成!!
※ 同じ断層に作成してある場合はプロジェクトプロパティのビルド前イベントに
Copy "../../../../Hook\Debug\Hook.dll" $(TargetDir)Hook.dll と追加しておくと便利
【解説らしきもの】
ソースがすべてですが、注意点だけ抜き出しておきます
・フック内容を書き換えたい場合はSetWindowsHookExの第一引数に気をつけろ!
・グローバルフックDLLをC#で扱う場合、DllImportはエントリポイントまで記入しないと動作しない
・似たような方法でDLLインジェクション+サブクラス化を検討している場合は、SetWindowLongPtr(GWL_WNDPROC指定)で拾えるシステムコマンドの種類は少ないので実装前に確認したほうが無駄な時間を食わずに済むよ!
・操作したいターゲットが決まっている場合はSetWindowsHookExの第3,4引数を変えてローカルフックにする(コメント参照)
・実験に失敗したらOS再起動しないと治らなくなるので注意されたし!
技術が古いためか動作しないサンプルもチラホラあり、簡単にできると思ったのに意外に大変だった orz
誰かのお役に立てば幸いです