喫茶XRAYトップページ


[6323] 今度はグローバルフックに返信 削除
2012/9/6 (木) 17:39:23 Taki
マスターこんばんは。Takiです。

今、パソコンのマウス操作を記録するプログラムを作っています。
例えば、スタートボタンをクリックしたら「スタート」、すべてのプログラムを
クリックしたら「すべてのプログラム」・・・のようにです。

その情報を得るのにIAccessibleが非常に役立っています。

ところが問題があります。

「メモ帳」を「閉じる」とメモ帳のウィンドウが消えるので、記録されるのが
「デスクトップ」になってしまうのです。
メニューを選んだ時も同じで、「コピー」をクリックすると、メニューが消えるので
記録は「Edit」になってしまいます。

今はタイマーでif((GetAsyncKeyState(VK_LBUTTON) and $8000) = 0) を監視しています。
この方法では情報を得る前に対象が消えてしまうので、やはりメッセージのフックを
使うべきなのかなと思っています。

マスターの「290_グローバルフック WH_GETMESSAGE」サンプルを教材にして色々と
勉強しましたが、DLLのplHookGetMessageUnit中のMyHookProc関数の中身が分かりません。

nCodeが負の時はCallNextHookEXで処理するとか、nCode=HC_ACTIONの時に処理するとかは
msdnとかにもそのように書かれているので何も考えないようにそのように・・・

分からない所は、wParam=PM_REMOVEの時にメッセージ情報をDLLからアプリケーションに
返して(PostMessageして)ありますよね。
説明には「この関数を通過後メッセージキューからメッセージが削除される」とあります。
「この関数を」の関数はMyHookProcのことですか。

それと、私のメッセージ処理に対するイメージは、メッセージを覗いたら
inherited WndProc(Message)で後処理するといった事なのですが、そうした命令が無いのも
理解できないのです。

上のメッセージフックの仕組みに対する疑問とは別に、メッセージを本来のウィンドウに
届くのを待たせるようなコードが書けるのかという事が最大の問題です。

フックのコールバック関数に重い処理は書くなと書いてあったし、DLLにIAccessibleの
コードを・・・なんて考えたくもありません。

何か良い方法は無いでしょうか。

[6324] Re:今度はグローバルフックに返信 削除
2012/9/6 (木) 17:54:43 Mr.XRAY
▼ちはっ!  Takiさん

> 「メモ帳」を「閉じる」とメモ帳のウィンドウが消えるので、記録されるのが
> 「デスクトップ」になってしまうのです。


そうなんですよね.
「閉じる」を検出したときは,そのウィンドウがないので,
実際には検出できないんですよね.
どうしてこんな仕様になっているんでしょうね.

本来操作の記録には,WH_JOURNALRECORD というフックがあるのですが,
これは,Vista 以降では使えないし.

> 何か良い方法は無いでしょうか。

というわけでがんばってください!! (笑)

>nCodeが負の時はCallNextHookEXで処理するとか、nCode=HC_ACTIONの時に処理するとかは
>msdnとかにもそのように書かれているので何も考えないようにそのように・・・


nCodeが負の時は,Windows が処理するので,そうしておかないと,
まずいようです.
そのため,サンプルでは,わさわざ最初の部分で,この処理をして抜けている
コードにしてあります.

>説明には「この関数を通過後メッセージキューからメッセージが削除される」とあります。
>「この関数を」の関数はMyHookProcのことですか。


後で確認いたしますです.
その他も後で.(^^;

[6325] Re2:今度はグローバルフックに返信 削除
2012/9/6 (木) 20:55:53 Taki
▼ マスター お世話になります。

inherited WndProc(Message)に相当する命令が分かりました。

CallNextHookExなのですね。

http://komina.so.land.to/index.php?Windows%2FAPI%2F%A5%A4%A5%D9%A5%F3%A5%C8%A5%D5%A5%C3%A5%AF

CallNextHookExって何をしているのでしょうね?

msdnによると「現在のフックチェーン内の次のフックプロシージャに、フック情報を渡します。」
登録したフック関数はMyHookProc1個だけだから、次のフックプロシージャって無いのでは?

逆に言えば、複数のフック関数を登録できるということ?
あ〜 踏み込んではいけない領域に踏み込んだみたい。

「何か良い方法・・・」を考えてみました。

メモ帳の「閉じる」をクリックする。
「閉じる」をクリックしたことをメッセージフックで知る。
メモ帳へのメッセージを殺す。
「閉じる」ボタンの情報をIAccessibleで得る。
メモ帳へ「閉じる」のメッセージをねつ造して(こそっと)送る。
メモ帳は消える。めでたし

・・・できそうにないですね。(T_T)

[6326] Re3:今度はグローバルフックに返信 削除
2012/9/6 (木) 23:18:19 Mr.XRAY
▼ Takiさん

本題の方はさて置いて(置くなちゅうの!)

> CallNextHookExって何をしているのでしょうね?

これは,msdnの記事の通りで,
起動中,あるいはこれから起動するアプリも含めて)
Windows のアプリ(目に見えているものとは限らない)にメッセージを送るわけです.
これをしないと,同じフックを使っているアプリが処理できなくなります.
つまり,フックを使っているのは,自分のアプリだけではないということです.
サービスプログラムなんかは,もしかしたらフックのオンパレードかも
知れません.

意識的にCallNextHookEx をしないこともあります.
実は,このサイトにそのようなコードがあるのです.
どれかは,ナイショです(笑)


[6327] Re4:今度はグローバルフックに返信 削除
2012/9/6 (木) 23:20:14 Mr.XRAY
> Windows のアプリ(目に見えているものとは限らない)にメッセージを送るわけです.
> これをしないと,同じフックを使っているアプリが処理できなくなります.


この意味で,フック内でメッセージを処理する場合は
基本的に,PostMessageなんですね.

ためしに,SendMessage を使うと,サンプルによっては,
面白いことになります.


[6328] Re5:今度はグローバルフックに返信 削除
2012/9/7 (金) 18:18:47 Taki
▼ マスター お世話になります。

> つまり,フックを使っているのは,自分のアプリだけではないということです.

そうですか。
他のアプリが先にフックを設定していたら自分のアプリで止めると変なことに
なってしまいますね。
メッセージの内容を途中で変更しても同じことが言えるのでは。

やはり踏み込んではいけない領域ですね。


> この意味で,フック内でメッセージを処理する場合は
> 基本的に,PostMessageなんですね.
>
> ためしに,SendMessage を使うと,サンプルによっては,
> 面白いことになります.


PostMessageはポストに手紙を投函するだけなのでさっさと帰れますが、
Sendmessageは相手の家まで手紙を届けないといけないのでなかなか
帰って来れません。

制御が返ってこないということは「面白いこと」では済まないような気も・・・。

今回の問題はメッセージフックでも解決できない気がしてきました。(;_;)

でも、メッセージフックの勉強にはなりました。
ずーっとメッセージ関係の処理は避けていたので一歩前進できた気分です。

[6329] Re6:今度はグローバルフックに返信 削除
2012/9/7 (金) 21:00:10 Mr.XRAY
▼ Takiさん

> PostMessageはポストに手紙を投函するだけなのでさっさと帰れますが、
> Sendmessageは相手の家まで手紙を届けないといけないのでなかなか
> 帰って来れません。


おおっ! これは使えるフレーズですね.
これから,もし,PostMessage と SendMessage の説明が必要な場面が
あったら使わせていただきます.

Halbow さんのコードをよく見てみると,PostMessage で受ける部分と,
その処理の部分を別のプロシージャーにしています.
こんなのも,ちょっとした「ノウハウ」なんじゃないかと思います.
単なる tips だけでは説明しにくい部分ですね.

ワード,エクセル操作フォームExでは,受けた処理が追いつかない
場合は,フラグを使って処理しています.

[6330] Re7:今度はグローバルフックに返信 削除
2012/9/8 (土) 11:36:16 Taki
▼ マスター 報告です。

マスターのサンプルプログラム 260_グローバルフック(キー・マウス)より
03_WH_MOUSE_LLとWH_KEYBORD_LLをいじってみました。

DLLを使用しないで済むのが良いのと、マウスフックのコールバック関数の
PostMessageをSendMessageに変えたらどんなおもしろいことがあるのかなと
興味がでまして・・・。

それと、フックしたマウス情報を受け取る関数 TForm1.WMApp100に
sleepも入れてみました。

LButtonDownでは両方ともWindowのキャプションはメモ帳でしたが、
LButtonUpでは違う結果になりました。(^_^)v

[6331] マスター 質問です。返信 削除
2012/9/8 (土) 23:15:03 Taki
▼ マスター 度々ですみませんが質問です。

報告で使った低レベルのマウスフックとキーフックのサンプルですが、
マウスフックやキーフックのコールバック関数内に直接操作内容をListViewに
表示するコードは書いてはいけないのでしょうか。

DLLを使ってないので自分から自分にメッセージを送る事が?です。

メッセージを留めないという意味ではこうするべきなのかもしれませんが。

[6332] Re:マスター 質問です。返信 削除
2012/9/8 (土) 23:41:41 Mr.XRAY
▼ Takiさん,どうもどうも,留守にしていたもんで.

> マウスフックやキーフックのコールバック関数内に直接操作内容をListViewに
> 表示するコードは書いてはいけないのでしょうか。


> DLLを使ってないので自分から自分にメッセージを送る事が?です。

全く問題ありませんです.ハイ.
表示そのものに時間がかかりますが,受け取れなかった分は表示できない
だけです,でも,人のキー操作の速度より,TListViewの描画の方が
はるかに速いハズです.通常のディスプレイ画面に表示する領域ぐらいは
問題ないと思います.何万行も表示するディスプレイだと問題あるかも?

それに,メッセージはキューに格納されて,順番に取り出されますから,
もし,メッセージの処理が追いつかないのであれば,操作終了後,
TListView にはキュー内のメッセージがなくなるまで表示続けることに
なります.強制的にキューに溜まったメッセージを削除すれば別ですが.

[キーバッファ等のクリア例]
http://mrxray.on.coocan.jp/Delphi/plSamples/840_CancellLockDisable.htm#08
この例はあまりよくないです.
実際には,KEY_FIRST,KEY_LAST というのを使った方が,よりベターてす.


[6333] ゴメンなさい.間違えました返信 削除
2012/9/9 (日) 00:02:23 Mr.XRAY
わわっ,スミマセン.間違えました.

>マウスフックやキーフックのコールバック関数内に直接操作内容をListViewに

コールバック関数内に書く,というのはやめた方がいいです.
問題あります.
必ずPostMesssge で送信して,このメッセージを憂げ取る
プロシージャーを作成して,処理してください.
やってもかまいませんが,動作は保証できません.

よく読まないでゴメンなさい.

[6334] Re:ゴメンなさい.間違えました返信 削除
2012/9/9 (日) 11:25:41 Taki
▼ マスター お世話になります。

> わわっ,スミマセン.間違えました.
>
> コールバック関数内に書く,というのはやめた方がいいです.
> 問題あります.


了解しました。

コールバック関数はあちら(Windows)の世界で呼び出される関数だから
こちらの世界のListViewに直結するコードは書かない方がいいのでしょうか。

メッセージを使ってスレッド間のデータの受け渡しをするのが安全なの
かなと推測(納得)します。

マスターがオーダーを間違ってあわてているのを見てしまいました。(^c^)

[6335] Re2:ゴメンなさい.間違えました返信 削除
2012/9/9 (日) 13:44:41 Mr.XRAY
▼ Takiさん

> コールバック関数はあちら(Windows)の世界で呼び出される関数だから
> こちらの世界のListViewに直結するコードは書かない方がいいのでしょうか。


そういうことだと思います.

> メッセージを使ってスレッド間のデータの受け渡しをするのが安全なの
> かなと推測(納得)します。


ですね.
 
> マスターがオーダーを間違ってあわてているのを見てしまいました。(^c^)

ハハハッ.
誤字脱字のMr.XRAYが,誤字脱字に「誤読」が含まれてしまいました.
まっ,今に始まったことじゃないですけどね.

INCM/CMT
Cyclamen v3.82