tagCANDY CGI VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板 [ツリー表示へ]   [Home]
一括表示(VB6.0)
タイトルSetParentの子ウインドウのハンドルの取得について
記事No14348
投稿日: 2010/01/07(Thu) 18:44
投稿者まつもと
いつも参考にさせていただいております。

Form1、Form2を用意し、SetParentにてForm1の上にForm2を乗せて動作させています。

Form2ではライブラリを使用して、ライブラリの中で自プロセスの全ウインドウに対し
ウインドウハンドルを元に処理をさせたいと考えています。
しかし、Form2のウインドウハンドルを取得する方法がわからずに困っています。

SetParentで子供になっているウインドウのハンドルをスレッドIDから取得する方法は
ありませんでしょうか?

<以下調査した内容です>
・EnumThreadWindowsでForm2のハンドルが見つからない。
・GetForegroundWindowで最上位のウィンドウを取得して、GetWindowで順番にウィン
 ドウを見ていってもForm2のハンドルが見つからない。

わかりにくい質問で申し訳ありませんが、よろしくお願いいたします。

[ツリー表示へ]
タイトルRe: SetParentの子ウインドウのハンドルの取得について
記事No14349
投稿日: 2010/01/07(Thu) 18:55
投稿者花ちゃん
> わかりにくい質問で申し訳ありませんが、よろしくお願いいたします。

自分で理解されているのなら、注意事項をよく読んでから投稿して下さい。
この掲示板の投稿画面や掲示板の上部にも書いてありますよ。

>・EnumThreadWindowsでForm2のハンドルが見つからない。
どこから(どこにコードを書いているのか)取得しているのですか?
(別 EXE とか、同プロジェクトとか)

当掲示板をご利用になる場合は、必ず【掲示板ご利用に際し】をよく読んでからご利用願います。

質問される前に[当サイト内外の検索]又は[ログビューア]を使って必ず、下調べをして下さい、そうでないとレスが付きません。
環境等が書かれていなかったり、速やかに返信されない質問は、ここのルールを読んでいないと見なされ、レスが付きません。

[ツリー表示へ]
タイトルRe^2: SetParentの子ウインドウのハンドルの取得について
記事No14350
投稿日: 2010/01/07(Thu) 19:17
投稿者まつもと
> > わかりにくい質問で申し訳ありませんが、よろしくお願いいたします。
>
> 自分で理解されているのなら、注意事項をよく読んでから投稿して下さい。
> この掲示板の投稿画面や掲示板の上部にも書いてありますよ。
>
> 当掲示板をご利用になる場合は、必ず【掲示板ご利用に際し】をよく読んでからご利用願います。
>
> 質問される前に[当サイト内外の検索]又は[ログビューア]を使って必ず、下調べをして下さい、そうでないとレスが付きません。
> 環境等が書かれていなかったり、速やかに返信されない質問は、ここのルールを読んでいないと見なされ、レスが付きません。

すみません、環境等を記入しておりませんでした。
開発環境はVB6.0 SP6です。
OSはXP、Vistaの双方で同じ現象が発生しております。
VB経験自体は4年間ほどになります。

また、過去の事例やGoogleでの検索ではSetParentの子ウインドウのハンドルを
取得する方法が見つからなかったので、投稿させていただきました。

質問内容が複雑でしたので、簡単に記入いたします。
<質問内容>
SetParentの子ウインドウからDLLを呼んでいる。
DLL内で呼び元のウインドウ(=SetParentの子ウインドウ)のハンドルを取得したい。

呼び元のウインドウからDLLに対してハンドルを渡す口を設けて、そこを経由して渡せば
対応できますが、DLL側の修正だけで対応したいと考えています。

[ツリー表示へ]
タイトルRe^3: SetParentの子ウインドウのハンドルの取得について
記事No14351
投稿日: 2010/01/07(Thu) 19:49
投稿者花ちゃん
>GetWindowで順番にウィンドウを見ていってもForm2のハンドルが見つからない。

 何を持ってForm2 と識別しているのですか?

> 対応できますが、DLL側の修正だけで対応したいと考えています。

Form2 のキャプションタイトルが決まっているなら、そこから取得する事も可能ですし
Form2 の 表示位置が解るのなら、WindowFromPoint API関数で取得できます。
Form2 をアクティブにできるなら、そこからも取得できます。
どのような状態(又は、識別方法)を作れるかで取得方法も違ってきます。
貴方の傍で、その状態を見ている訳ではないので、詳しい状況等を書いて頂かないと
適切な判断は出来ません。

取得例
  http://hanatyan.sakura.ne.jp/bbs_gif/20100107-1.gif

キャプションタイトルが解っているのなら
  http://hanatyan.sakura.ne.jp/bbs_gif/20100107-2.gif

起動中のアプリのWindow の一覧を取得する場合、制限等がかかっていると取得できません。
表示されていても、非表示の状態になり取得できなかったり、オーナーウィンドウと
みなされず、取得できない等の制限がかかる場合がありますので、一覧を取得する場合は
注意して下さい。
いずれにしても、Form1 や Form2 と識別出来る物が必要です。(キャプションタイトルの
一部でもよいので)

[ツリー表示へ]
タイトルRe: SetParentの子ウインドウのハンドルの取得について
記事No14355
投稿日: 2010/01/07(Thu) 23:38
投稿者Starfish

> SetParentで子供になっているウインドウのハンドルをスレッドIDから取得する方法は
> ありませんでしょうか?

 Form1のウィンドウハンドルを探してから、Form1の子ウィンドウの中から
Form2のウィンドウハンドル調べることになるかと思います。

 直接、Form2のウィンドウハンドルを調べることは難しいのではないかと思います。

[ツリー表示へ]
タイトルRe^2: SetParentの子ウインドウのハンドルの取得について
記事No14356
投稿日: 2010/01/07(Thu) 23:57
投稿者まつもと
花ちゃん様、Starfish様、ご回答どうもありがとうございます。

>花ちゃん様
 FindWindowではトップレベルウインドウの検索しか行えず、SetParentの子ウインドウ
 は検索できないようでした。

 「Form2」をアクティブにするという方法で、アクティブ後にGetActiveWindowをやれ
 ば取れそうなのですが、Form2から呼んでいるDLL内でForm2をアクティブにするという
 処理はどのようにすれば行えますでしょうか?

>Starfish様
 上記の方法でうまくいかない場合には、Form1のウインドウハンドルを探してから、
 EnumChildWindowsでForm1の子ウインドウを探すような方法を考えてみます。

[ツリー表示へ]
タイトルRe^3: SetParentの子ウインドウのハンドルの取得について
記事No14357
投稿日: 2010/01/08(Fri) 07:26
投稿者花ちゃん
> >花ちゃん様
>  FindWindowではトップレベルウインドウの検索しか行えず、SetParentの子ウインドウ
>  は検索できないようでした。

FindWindowで取得できると言いましたっけ。

FindWindow は、旧タイプなので FindWindowEx を使用すれば
FindWindowEx でも子ウインドウは検索できますよ。(条件させ揃えば)

Private Declare Function FindWindowEx Lib "user32" Alias _
    "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, _
    ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Sub Command1_Click()
    Dim hTargetWindow As Long
    Dim hChildWindow  As Long
    'ウインドウのハンドルを取得
    hTargetWindow = FindWindowEx(0, 0, vbNullString, "TestForm1")
    If hTargetWindow = 0 Then Exit Sub
    '子ウインドウのハンドルを取得
    hChildWindow = FindWindowEx(hTargetWindow, 0, vbNullString, "TestForm2")
    Label1.Caption = "TestForm2 のハンドルは:" & hChildWindow
End Sub
http://hanatyan.sakura.ne.jp/bbs_gif/20100107-2.gif

キャプションタイトルはどうなっていますか?
Form1 や Form2 と識別できる何かがありますか?
Form1 の起動はどのようにしているのですか、その時にハンドルは取得できませんか?
その辺が解らないと取得する方法が決められないのでは。

 下記は、直接 Form2 のハンドルを取得しております。(こちらも前提条件があります)
 http://hanatyan.sakura.ne.jp/bbs_gif/20100107-1.gif

このように色々取得する方法がありますが、No.14351 にも書いておりますが、
Form1 や Form2 と識別出来る物が必要ですし、ある程度の前提条件も必要ななるので
その辺がこちらでは、解らないので的確な取得方法は決められないかと。

[ツリー表示へ]
タイトル解決しました。
記事No14364
投稿日: 2010/01/08(Fri) 18:03
投稿者まつもと
Form1=親ウインドウ:Captionを持っている
Form2=子ウインドウ:Captionを持っていない

という状況でしたので、やはり直接子ウインドウを検索はできませんでした。
以下の方法にて解決いたしました。

@親ウインドウのキャプションが特定の文字を含むものを検索。
A@の中でスレッドIDが一致するウインドウの子ウインドウをEnumChildWindowsで列挙。
Bその中で最初に取れたフォームオブジェクトをForm2と特定。

花ちゃん様、Starfish様、いろいろとご助言ありがとうございました。

[ツリー表示へ]
タイトルRe: 解決しました。
記事No14365
投稿日: 2010/01/08(Fri) 18:41
投稿者花ちゃん
解決されたのならいいのですが、

> Form1=親ウインドウ:Captionを持っている
> Form2=子ウインドウ:Captionを持っていない
Captionを持っていないなら、クラス名を設定すればいいのでは。
(クラス名は変わりませんので前もって調べて置いて下さい)

> という状況でしたので、やはり直接子ウインドウを検索はできませんでした。

キャプション名がないならクラス名を設定すれば、取得できましたよ。(試した結果)
下記よりは、こちらの方がまだ確実で簡単かと。
hChildWindow = FindWindowEx(hTargetWindow, 0, "ThunderFormDC", vbNullString)
念の為、Form1 のハンドルと同じでないか確認しておけば、より確実かと。

> 3.その中で最初に取れたフォームオブジェクトをForm2と特定。
必ず、最初に表示される保証はあるのでしょうか?

[ツリー表示へ]
タイトルRe^2: 解決しました。
記事No14367
投稿日: 2010/01/08(Fri) 21:21
投稿者まつもと
> キャプション名がないならクラス名を設定すれば、取得できましたよ。(試した結果)
> 下記よりは、こちらの方がまだ確実で簡単かと。
> hChildWindow = FindWindowEx(hTargetWindow, 0, "ThunderFormDC", vbNullString)
> 念の為、Form1 のハンドルと同じでないか確認しておけば、より確実かと。

花ちゃん様ご助言ありがとうございます。

本プログラムは複数同時に立ち上げることができるのですが、FindWindowExですと前面
の方しか検索できないと思います。
使い方が悪いのでしょうか?


> > 3.その中で最初に取れたフォームオブジェクトをForm2と特定。
> 必ず、最初に表示される保証はあるのでしょうか?

Form1の子ウインドウでクラス名が「ThunderRT6FormDC」のもの(1つしか取れないと
考えていたので最初に取れたものとしました)をForm2と特定できると考えています。

これだとまずいでしょうか?

[ツリー表示へ]
タイトルRe^3: 解決しました。
記事No14368
投稿日: 2010/01/08(Fri) 22:45
投稿者花ちゃん
> 本プログラムは複数同時に立ち上げることができるのですが、FindWindowExですと前面
> の方しか検索できないと思います。
> 使い方が悪いのでしょうか?

何か勘違いしていませんか?
オーナーウィンドウであるForm1 のハンドルは取れたのですよね。
だったら、そのハンドルを指定して子ウィンドウであるForm2 のクラス名を検索する
事でFindWindowExで取得できるはずですが。


> Form1の子ウインドウでクラス名が「ThunderRT6FormDC」のもの(1つしか取れないと
Form1 と Form2 とは同じクラス名だったりしませんか?

> 考えていたので最初に取れたものとしました)をForm2と特定できると考えています。

A@の中でスレッドIDが一致するウインドウの子ウインドウをEnumChildWindowsで列挙。
Bその中で最初に取れたフォームオブジェクトをForm2と特定。

クラス名を照合されているのならいいのですが、それなら、EnumChildWindowsで列挙する
までもないのではないでしょうか? FindWindowEx だけで取得できますが。

[ツリー表示へ]
タイトルRe^4: 解決しました。
記事No14369
投稿日: 2010/01/09(Sat) 15:35
投稿者まつもと
> オーナーウィンドウであるForm1 のハンドルは取れたのですよね。
> だったら、そのハンドルを指定して子ウィンドウであるForm2 のクラス名を検索する
> 事でFindWindowExで取得できるはずですが。
>
> > Form1の子ウインドウでクラス名が「ThunderRT6FormDC」のもの(1つしか取れないと
> Form1 と Form2 とは同じクラス名だったりしませんか?
>
> > 考えていたので最初に取れたものとしました)をForm2と特定できると考えています。
>
> A@の中でスレッドIDが一致するウインドウの子ウインドウをEnumChildWindowsで列挙。
> Bその中で最初に取れたフォームオブジェクトをForm2と特定。
>
> クラス名を照合されているのならいいのですが、それなら、EnumChildWindowsで列挙する
> までもないのではないでしょうか? FindWindowEx だけで取得できますが。

FindWindowとFindWindowExの使い方を混同してました。
FindWindowExでForm1のウインドウハンドルとForm2のクラス名を引数に検索したら同じ
結果が得られました。
こちらの方がソースもすごくすっきりしました。

本当にありがとうございました。

[ツリー表示へ]