座標から子ウィンドウハンドルを取得するには?


にょい君  2008-05-29 05:00:08  No: 139795  IP: 192.*.*.*

VB2003 + Framework1.1 + WindowsXP-PRO(SP2)
上記の環境で、ウィンドウハンドルの取得方法の
WindowFromPoint
ChildWindowFromPoint
を試しているのですが、WindowFromPointは正常に取得できるようなのですが、
ChildWindowFromPointの値がどのようなウィンドウで試してもいつも0しか返ってこなくて、
うまく機能していないようなのですが、下記のコードでの間違いを見付けることが
できないのですが、訂正箇所をご教授頂けませんでしょうか。

フォームにはButton1、TextBox1〜4  が配置してあり、
Button1をクリックすると
   Timer1.Interval = 10
   Timer1.Start()
のようにタイマーがスタートして、マウスポインタの位置のウィンドウハンドルが
TextBox3,4に表示されるようになっています。

Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Timer1.Tick
    Dim res As Integer
    Dim parent As Integer = res
     TextBox1.Text = System.Windows.Forms.Cursor.Position.X.ToString()
     TextBox2.Text = System.Windows.Forms.Cursor.Position.Y.ToString()
     res = WindowFromPoint(TextBox1.Text, TextBox2.Text)
     TextBox3.Text = Hex(res)
     res = ChildWindowFromPoint(parent, TextBox1.Text, TextBox2.Text)
     TextBox4.Text = Hex(res)
End Sub

編集 削除
にょい君  2008-05-29 05:02:34  No: 139796  IP: 192.*.*.*

APIの宣言部分はこのようになっています。

Declare Function WindowFromPoint Lib "user32.dll" (ByVal x As _ 
 Integer, ByVal y As Integer) As Integer

Declare Function ChildWindowFromPoint Lib "user32.dll"  _ 
(ByVal hwnd As Integer, ByVal x As Integer, ByVal y As Integer) As Integer

宜しくお願い致します。

編集 削除
ウーム  2008-05-29 09:24:55  No: 139797  IP: 192.*.*.*

>>WindowFromPointは正常に取得できるようなのですが

WindowFromPointに渡す引数はStringではなくてIntegerなはずだけど
それでも正常に取得できてるのなら
res = ChildWindowFromPoint(res, TextBox1.Text, TextBox2.Text)
でなんとかなるかも・・・・

編集 削除
 2008-05-29 10:34:22  No: 139798  IP: 192.*.*.*

WindowFromPointの引数はスクリーン座標で
ChildWindowFromPointの方はクライアント座標です。

ScreenToClientなりで変換しないと駄目なのでは?

で、こちらが本題ですがWindowFromPointは
「指定された座標を含むウィンドウのハンドルを取得します」
なので、たとえばフォーム上のボタンの座標を指定すれば
ボタンのウィンドウハンドルが取得されるはずです。

両方取得したいときはGetAncestor等で親のハンドルを
取得する必要があるのではないでしょうか。

SPY++等のツールを使うと簡単に確認できるので
使ってみてください。

編集 削除
にょい君  2008-05-31 00:18:02  No: 139799  IP: 192.*.*.*

ウーム様、と様、ご回答ありがとうございます。

ウーム様
その方法でも0ばかりがかえってきてしまします。
思考錯誤した残骸のparent変数が残ったまま質問してしまいました。
申し訳ございません。


と様
ScreenToClientを調べてみようと思います。
でもどこの位置でも0ばかりですので、座標をシフトしても
やっぱりだめなのでは?と思っております。
WebBrowser上のボタンを押したいためにハンドルの取得を試みているのですが、
SPY++で探しても目的のボタンのハンドルが出てこないようです。

編集 削除
Hongliang  2008-05-31 09:32:12  No: 139800  IP: 192.*.*.*

> WebBrowser上のボタンを押したいためにハンドルの取得を試みているのですが、
WebBrowser 上のオブジェクトは、基本的に全てただの絵です。WebBrowser がそれっぽく描いてるだけです。ウィンドウではありませんからハンドルも持っていません。
自分の管理下の WebBrowser なら、HtmlDocument.GetElementFromPoint などを使って input (または button) 要素を取得し、InvokeMember で click する、と言う手順を踏んでください。

編集 削除
Hongliang  2008-05-31 09:34:48  No: 139801  IP: 192.*.*.*

あ、.NET 1.1 か。
mshtml の IHTMLDocument.elementFromPoint とか IHTMLElement.click とかに置き換えないと駄目だな。

それとも別プロセスに介入したいのでしょうか?

編集 削除
魔界の仮面弁士  2008-05-31 09:49:28  No: 139802  IP: 192.*.*.*

> WebBrowser上のボタンを押したいためにハンドルの取得を試みているのですが、
そもそも、ウィンドウ ハンドル自体が存在していないからです。

Hongliang さんが書かれたように、HTML の DOM を使って操作するか、
IAccessible インターフェイスの accDoDefaultAction メソッドを使って
ボタンを押すようにしてみてください。

編集 削除
にょい君  2008-05-31 17:25:46  No: 139803  IP: 192.*.*.*

Hongliang様、魔界の仮面弁士様、ご回答ありがとうございます。

Windows上のボタンなどはどんなものでもハンドルを持っていると
思っていたので、何らかの方法で取得するのだと思っておりましたが
この場合はだめなのですね・・・

フォームの送信ボタンなどの押下は
AxWebBworse1.Document.forms(1).elements(i).Click()
などの方法でやったことがあるのですが、
今回はAdobe Flash Playerの再生、停止ボタンなどなのですが、
現在はマウスポインタを移動させて、クリックイベントを発生させる
という方法で行っているのですが、これだと一回のクリックで
停止、再生が出来ないことがあり、再生、停止が逆転してしまったりと
不都合があり他の方法をいろいろ模索しておりました。

Hongliang様と魔界の仮面弁士様から頂いたご回答の中に初めて見る
言葉がありましたので(elementFromPoint、IAccessible、accDoDefaultAction 等)
まずはそちらを調べてみたいとおもいます。

また何かご指摘等がございましたら、レス頂けたら幸いです。

編集 削除
魔界の仮面弁士  2008-05-31 18:39:58  No: 139804  IP: 192.*.*.*

IAccessible インターフェイスのテストツールを紹介しておきます。
http://www.microsoft.com/downloads/details.aspx?familyid=3755582a-a707-460a-bf21-1373316e13f0&displaylang=en
http://msdn.microsoft.com/ja-jp/library/cc402091.aspx

[Accessible Explorer] の "Select with Mouse" アイコンを使って、
そのフラッシュのボタンが反応するかどうかを確認してみてください。
そして、[Inspect] の "Do Default Acition" アイコンを使って、
そのボタンが押下可能かどうかをチェックしてみてください。

反応する場合は、IAccessible.accDoDefaultAction が使えるはずです。
反応しない場合は、おそらく IAccessible では解決できないと思われるので、
SendInput 等でマウス操作をシミュレートするなどの手段が必要かも知れません。

編集 削除
にょい君  2008-05-31 21:34:23  No: 139805  IP: 192.*.*.*

魔界の仮面弁士様
すごいツールを教えて頂きありがとうございます。
相当な時間、試行錯誤して悩んでいたので、このツールを試して
ボタンを押す動作をさせることが出来て感動しています。
この先なにをすれば良いのか全く分からない状態ですが、
頑張ってなにがどうなっているのか調査してみようと思います。
ありがとうございました。

編集 削除
魔界の仮面弁士  2008-05-31 22:27:23  No: 139806  IP: 192.*.*.*

おぉ、IAccessible に対応していましたか。
であれば、このあたりが使えそうです。

(1) AccessibleObject クラスを得るためのControl.AccessibilityObject プロパティ。
(2) 座標からIAccessibleを得るAccessibleObjectFromPoint API。
(3) ウィンドウハンドルからIAccessibleを得るAccessibleObjectFromWindow API。

今回の場合だと、(1) か (2) かな。

編集 削除
にょい君  2008-06-01 23:17:00  No: 139807  IP: 192.*.*.*

魔界の仮面弁士様。ご回答ありがとうございます。
3つの方法について調べてみたいと思います。
便利そうな方法を教えて頂きましてありがとうございます。

編集 削除