#はじめに
RPAにはいくつかの基本機能があります。
その実装方法をひとつひとつ、丁寧にお伝えしていこうと思います。
記念すべき第1回目は、マウス動作の記録と再生のうち記録機能の説明をします。
#使用環境
Visual Studio 2019 Community Edition
Windows 10 pro
#全体構成
最終的には以下のような構成になります。
- DaphRPAHook.dll
- マウスメッセージをフックする
- DaphRPA.exe
- 記録を開始し、フックしたマウスメッセージを保存する
#処理の流れ
マウス動作の記録は、以下の処理の流れで行います。
- DaphRPA.exeを起動
- 録画再生ボタン付きのダイアログを表示
- ダイアログ初期化処理でメッセージフックのマウスイベントキャプチャを開始
- DaphRPAHook.dllでマウスイベントをフックし記憶
- 録画停止ボタンで、記憶したマウスイベントをファイルに保存
この処理の流れに従って実装していきます。
######が、その前に、理解しておくべき技術の説明をします。
#メッセージフック
この記録機能を実装するためにまず必ず知っておかなければいけないことは、Windowsがメッセージのやり取りによって動作しているという事実です。
例えば、マウスを動かしたときやキーボードで文字を入力したときに、メッセージが送信されます。各ウィンドウはそのメッセージをウィンドウプロシージャというもので受け取り、そのメッセージに応じた処理を実行しています。
####ウィンドウプロシージャについて
以下はWin32でウィンドウを作成するときのクラス登録で指定するWNDCLASS構造体の定義です。
typedef struct tagWNDCLASS {
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
} WNDCLASS, *PWNDCLASS;
この中の WNDPROC lpfnWndProc
という部分が、上記で説明したウィンドウプロシージャの定義です。
各ウィンドウはここで定義されたコールバック関数で処理を受け取りウィンドウごとの処理を実行します。
以下が、ウィンドウプロシージャの実装例です。
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_LBUTTONDOWN:
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
break;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
上記の例では、二つのウィンドウメッセージに対する処理が記述されています。一つはWM_LBUTTONDOWN
で、マウスの左ボタン押下メッセージで、二つ目は、WM_DESTROY
でウィンドウ破棄メッセージです。
####ウィンドウメッセージを視覚的に確認する
ウィンドウメッセージを実際にその目で確認することもできます。
ウィンドウメッセージを確認するには、Spy++
というツールを使います。
#####Spy++
Spy++はVisual Studioに標準で付属されたツールで、以下のパスに配置されています。
・32bit用
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools\spyxx.exe
・64bit用
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools\spyxx_amd64.exe
※Visual Studioのパスはそれぞれの環境で読み替えてください。
アイコンがスパイっぽくてかっちょいいです。
起動すると以下のような画面が現れます。
メッセージをスパイしたい対象のウィンドウを選びます。
以下のアイコンをクリックすると、
以下のようなウィンドウを選択するためのダイアログが表示されます。
このターゲットをマウスでドラッグして、対象のウィンドウにドロップしてOKを押すと、メッセージのキャプチャが始まります。
※始まらない場合は64bit版か32bit版かで試してみてください。
上記は、Excelに対するメッセージをキャプチャしてみた例です。ものすごい勢いで、メッセージが到達しているのがわかると思います。
真ん中下あたりにWM_LBUTTONDOWNというメッセージが出力されているのがわかると思います。上の方で説明したWindowProcでは、このメッセージに対して処理を行うようにすることができます。Excelでもおそらく、これらのメッセージに対していろいろな処理を内部で行っていると思います。
####グローバルフック
ウィンドウのフックには、ローカルフックとグローバルフックの2種類があります。
ローカルフックは自分自身のメッセージしかフックできませんが、グローバルフックは、別名「システムフック」と呼ばれるだけあって、すべてに対するメッセージをフックすることができます。
マウス起動キャプチャでは、自分のウィンドウに対する以外のマウスの動作もすべてフックする必要があるので、グローバルフックを使用します。
HHOOK SetWindowsHookEx(
int idHook,
HOOKPROC lpfn,
HINSTANCE hmod,
DWORD dwThreadId
);
SetWindowsHook
関数は、フックチェーンにフック処理を入れ込みます。つまり、メッセージの横取りが開始されます。Windows上でやり取りされているすべてのメッセージに対して、そのメッセージを横取りすることができるようになるかなりすごい関数です。
第一引数には、どんな種類のメッセージをフックするかを指定します。マウス動作記録では、マウスのメッセージをフックする必要があるため、WH_MOUSE_LL
を指定します。
第二引数には、フックプロシージャを指定します。これはウィンドウを作成するときに指定するウィンドウプロシージャのようなもので、フックしたメッセージをここで処理するコールバック関数を指定します。
グローバルフックの場合は、第三にNULL、第四引数に0を指定します。
####グローバルフックのDLL化
グローバルフックは、DLLとして実装する必要があります。なぜならば、グローバルフックは、様々なプロセスにくっついて動作するからです。このあたりの動作は、Process Explorer
等で確認することができますので、実際に動作させたときに確認してみたいと思います。
#つづく
概念的な説明はこのくらいにして、次回からは実際に実装していきます。
その1の2につづきます。
https://qiita.com/yasunari_matsuo/items/a1d294f09ac21e9508b6
この記事のプロジェクトは以下にアップしています。記事が進むごとに下記プロジェクトも成長します。
https://github.com/yasunarim/DaphRPA
#参考にしたサイト
プログラミング入門サイト
https://bituse.info/winapi/1
フックの仕組み
http://www.kab-studio.biz/Programing/Codian/DLL_Hook_SClass/06.html