tagCANDY CGI VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板 [ツリー表示へ]   [Home]
一括表示(VB6.0)
タイトルwithEventsで生成したInternetExplorerが捕捉できない
記事No16096
投稿日: 2015/04/04(Sat) 21:02
投稿者はなまるき
環境:Windows7

withEventsで生成したIEが下記の方法で捕捉できませんでした。

    Dim objShell As Object
    Dim objShellWindows As Object
    Dim objIE As Object
    
    Set objShell = CreateObject("Shell.Application")
    Set objShellWindows = objShell.Windows
    For Each objIE In objShellWindows

  Next

withEvents既に開いている複数のIEのhwndとLocationURLを調べたいのですが
何か方法は無いでしょうか?

[ツリー表示へ]
タイトルRe: withEventsで生成したInternetExplorerが捕捉できない
記事No16098
投稿日: 2015/04/05(Sun) 11:49
投稿者花ちゃん
どのように起動した IE が取得できないのか?
他の人が再現できるコードを投稿して頂けませんか。
私が試した限りでは取得できましたので。

[ツリー表示へ]
タイトルRe^2: withEventsで生成したInternetExplorerが捕捉できない
記事No16103
投稿日: 2015/04/09(Thu) 17:04
投稿者はなまるき
> どのように起動した IE が取得できないのか?
> 他の人が再現できるコードを投稿して頂けませんか。
> 私が試した限りでは取得できましたので。

やろうとしていることは、
@DB内のURLリストから複数のサイトを開きます。
 ・開くサイトはランダム
 ・手動で閉じたときに確実に終了させるためにwithEventsで
   onQuitイベントを起こす
 
AさらにDB内のURLリストからランダムにサイトを開く

 このときに、既に開かれているかどうかのチェックと、
もし開かれているならそのhWndを取得してShowWindowで
表示するという動きをさせていのですができません。
なぜランダムかというと、それは開いたかどうか覚えて
いないような人が使っても二重起動しないためです。


Private WithEvents objIE As InternetExplorer

Private Sub mnuBlogDisp_Click()
    'BlogURL取得
    Dim BlogURL As String
    BlogURL = GetBlogURL
    'Blog表示
    Set objIE = OpenIE(BlogURL)
    Call ShowWindow(objIE.hWnd, SW_MAXIMIZE)
End Sub

Public Function OpenIE(strURL As String) As Object
    On Error Resume Next
    Dim objIE As Object
    Set objIE = CreateObject("InternetExplorer.application")

    With objIE
        .Visible = True
        Call CloseWindow(.hWnd)
        .navigate (strURL)
    End With
    Set OpenIE = objIE
End Function

Private Sub objIE_OnQuit()
    Set objIE = Nothing
End Sub

[ツリー表示へ]
タイトルRe: withEventsで生成したInternetExplorerが捕捉できない
記事No16102
投稿日: 2015/04/06(Mon) 09:31
投稿者魔界の仮面弁士
> withEventsで生成したIEが下記の方法で捕捉できませんでした。

生成……ですか?

「WithEvents」も「CreateObject("Shell.Application")」も、
IE (InternetExplorer) の インスタンスを『生成』するためのものではありませんよ。

Windows プロパティで得られる ShellWindows コレクションは、
現在起動されている InternetExplorer オブジェクト(≠WebBrowser オブジェクト)を
列挙するコレクションを返すためのものですし、WithEvents ステートメントは、
単一のオブジェクトで発生したイベントを受け取るためのものです。


> withEvents既に開いている複数のIEのhwndとLocationURLを調べたいのですが
その目的であれば、イベントの出番が無いので、WithEvents は不要かと思います。
「For Each objIE In objShellWindows」から「Next」までのループブロックの中で、
objIE.hwnd や objIE.LocationURL を調べるだけのはずです。

それとも、そのようにして絞り込んだ InternetExplorer オブジェクトを、
別途用意した WithEvents に代入しようとしたものの、そもそも列挙されなかったとか、
あるいは、WithEvents 変数へ代入したときに実行時エラーになってしまったということでしょうか。


もしそうだとしたら、調査のために得た hwnd や LocationURL が、そもそも間違っていたという
可能性もありますが、それらはどのようにして得たものなのでしょうか。

あるいは、それらの値は正しいが、列挙されてこないようだとすると、 KB940998 などといった
環境依存の問題も考えられます。その場合はたとえば、
> Set objShell = CreateObject("Shell.Application")
> Set objShellWindows = objShell.Windows
という部分を
 Set objShellWindows = GetObject("new:9BA05972-F6A8-11CF-A442-00A0C90A8F39")
に書き換えてみたら結果は変わりますか?


もしくは、折角 hwnd まで分かっているのなら、ShellWindows コレクションから列挙するのではなく、
"Internet Explorer_Server" のウィンドウに WM_GETOBJECT メッセージを送って ObjectFromLresult で
IHTMLDocument2 インターフェイスを直接受け取るという手もあります。

http://hpcgi1.nifty.com/MADIA/VBBBS/wwwlng.cgi?print+200904/09040020.txt

[ツリー表示へ]
タイトルRe^2: withEventsで生成したInternetExplorerが捕捉できない
記事No16104
投稿日: 2015/04/09(Thu) 17:15
投稿者はなまるき
> 「WithEvents」も「CreateObject("Shell.Application")」も、
> IE (InternetExplorer) の インスタンスを『生成』するためのものではありませんよ。

すみません。言葉を知りませんでした。起動でよろしかったのでしょうか

> Windows プロパティで得られる ShellWindows コレクションは、
> 現在起動されている InternetExplorer オブジェクト(≠WebBrowser オブジェクト)を
> 列挙するコレクションを返すためのものですし、WithEvents ステートメントは、
> 単一のオブジェクトで発生したイベントを受け取るためのものです。

単一のオブジェクトだというのもわかるんですけど、たとえば複数のサイトを同一処理で
で起動した場合、objIEの中身?はどうなるのでしょうか?
2つ3つ開いてみましたが、結果として1つもLocationURLを取得できませんでした。
起動方法は花ちゃんさんのほうに返信していますのでそちらを参照いただけますで
しょうか。


> その目的であれば、イベントの出番が無いので、WithEvents は不要かと思います。
よその質問サイトで、IEを確実に終了するためにonQuitイベントで処理したほうがいいと
あったのでそうしました。実際エラーが出ていましたので。


>  Set objShellWindows = GetObject("new:9BA05972-F6A8-11CF-A442-00A0C90A8F39")
> に書き換えてみたら結果は変わりますか?
これからやってみます

[ツリー表示へ]
タイトルRe^3: withEventsで生成したInternetExplorerが捕捉できない
記事No16105
投稿日: 2015/04/09(Thu) 19:14
投稿者魔界の仮面弁士
> すみません。言葉を知りませんでした。起動でよろしかったのでしょうか

No16096 で提示頂いたコードは、「起動済みのエクスプローラーとInternet Explorerを列挙する処理」であって、
「Internet Explorerやエクスプローラーを新たに起動するための処理」では無いですよね。

No16103 で再提示頂いた OpenIE については「起動」で良いと思いますけれども。


> 単一のオブジェクトだというのもわかるんですけど、たとえば複数のサイトを同一処理で
> で起動した場合、objIEの中身?はどうなるのでしょうか?

最初の質問にある ShellWindows での列挙の話をしておられるのでしょうか。
それともそれとは関係なく、IE の起動方法について質問しておられるのでしょうか?


前者だとすれば、objIE は個別に得られることになります。
最近の IE は、一つのウィンドウ内に複数のタブページで閲覧することもできますよね。
この状態になっている場合、それぞれのタブごとに、別々の InternetExplorer オブジェクトの
インスタンスが得られます。

後者だとすれば、「同じ IE 上で別のサイトを開きたい」のか、
「サイトごとに別の IE を起動したいのか」で話が変わってきます。

同じ IE で開くようにしたいのであれば、
  If objIE Is Nothing Then
   Set objIE = OpenIE(新しいURL)
  Else
   Call objIE.Navigate2(新しいURL)
  End If
のようにすれば OK です。

毎回、新たな IE を起動したいなら
  Set 新たなIEインスタンス = CreateObject("InternetExplorer.Application")
  新たなIEインスタンス.Visible = True
  Call 新たなIEインスタンス.Navigate2(新しいURL)
ということになりますが、この場合、それぞれのインスタンスごとに
WithEvents 変数を用意しておく必要があるため、その点は注意が必要ですね。


> 結果として1つもLocationURLを取得できませんでした。
> 起動方法は花ちゃんさんのほうに返信していますので
いままで提示頂いたコードの中に、LocationURL が使われているものは
どこにも見当たらないのですが…。どういうコードを書いているのか分からないと、
間違っている箇所を指摘することは難しいです。

[ツリー表示へ]
タイトルRe^4: withEventsで生成したInternetExplorerが捕捉できない
記事No16106
投稿日: 2015/04/10(Fri) 15:31
投稿者はなまるき
すみません。おっしゃるとおりきちんとコードを提示できていませんでした。

Private WithEvents objIE as InternetExplorer

Private sub Command1_Click
    Dim strURL as string
    strURL=List1.Text

    Dim objShell As Object
    Dim objShellWindows As Object
    Dim objIE As Object
    
    Set objShell = CreateObject("Shell.Application")
    Set objShellWindows = objShell.Windows
    For Each objIE In objShellWindows
    If InStr(objIE.LocationURL, strURL) <> 0 Then
           Call ShowWindow(objIE.hWnd, SW_MAXIMIZE)
       goto Exit_Sub
        End If
  Next

    set objIE=OpenIE(strURL)

Esit_Sub:

End Sub

Public Function OpenIE(strURL As String) As Object
    Dim objIE As Object
    Set objIE = CreateObject("InternetExplorer.application")

    With objIE
        .Visible = True
        Call CloseWindow(.hWnd)
        .navigate (strURL)
        Do While .Busy = True Or .readyState <> 4
            DoEvents
        Loop
    End With
    Set OpenIE = objIE
End Function


Private Sub objIE_OnQuit()
    Set objIE = Nothing
End Sub


既に開いていたらそれを、なければNavigateとしたいのですが、上の方法で起動した
IEはいずれもキャッチできませんでした。

[ツリー表示へ]
タイトルRe^5: withEventsで生成したInternetExplorerが捕捉できない
記事No16109
投稿日: 2015/04/10(Fri) 18:15
投稿者魔界の仮面弁士
これ、実際のコードをそのまま貼った物では無いですよね。
実行するまでも無くコンパイルエラーになりそうな箇所さえありますし…。


それはさておき:

> Private WithEvents objIE as InternetExplorer
フォームモジュールレベルの変数「objIE」と

> Private sub Command1_Click
>     Dim objIE As Object
プロシージャーレベルの変数「objIE」が競合していますよね。


ですから、Command1_Click 内で幾ら objIE を参照しても、
それは WithEvents 変数とは無関係になってしまう、ということです。


このコードには、他にもいろいろな問題点を抱えていますが、とりあえず
今回の主題である WithEvents の件から片付けてしまいましょうか。

そのためにまずは、For Each で使われているループ変数と、
WithEvents のための変数を、別の変数名に置き換えることから
はじめてみてください。



> 既に開いていたらそれを、なければNavigateとしたいのですが
まず、この仕様自体もかなり曖昧になっていますよ。

たとえば、IE が 2 つ起動されていたと思ってください。
A は Apple、B は Google を表示している状態です。

ここで新たに、Microsoft のサイトを開きたいとした場合、

 (1) A で開く(Apple のサイトは見えなくなる)
 (2) B で開く(Google のサイトは見えなくなる)
 (3) C で開く(新たにもうひとつ IE を開く)
 (4) A または B で開く(既存のウィンドウのいずれかで開く)

のどれにしたいのでしょうか?


仮に(4) だとしたら、A と B を区別する必要は無いので、
LocationURL や HWND の出番は無いはずです。

一方、(1) や (2) だとするのなら、どういう時に A (あるいは B)を
選択するのか明らかにしてもらわないと、仕様が曖昧すぎて回答できないです。
とはいえ、「極力同じ IE を使い続ける」のが目的なのだとすれば、
WithEvents 変数一つだけで事足りますので、そもそも For Each は不要となります。


さて、問題は (3) のケース。もしもこのパターンを望んでいるんだとしたら、
再度、同じURL(Microsoft のサイト)を開きなおしたい場合に、

 (5) C を再利用してそこに Navigate
 (6) C とは別に D のウィンドウを開く

のどちらにしたいのかが、今までの質問からは読み取れませんでした。


もし (6) なのだとしたら、そもそも For Each での列挙は不要でしょう。
常に新しい IE を起動するだけなので、WithEvents も For Each も不要で、
毎回 OpenIE を呼び出すだけで事足ります。


一方 (5) の場合はどうかというと、これは現状のコードでは不十分に見えます。
たとえばユーザーが、A で Apple ではなく Microsoft を表示し始めてしまい、
C では Microsoft ではなく、Amazon に遷移させていたとします。
この場合、LocationURL で判断すると、C ではなく A で Navigate しちゃいますよね。

その場合は A で表示したい、というのであればそれでも良いですが、
問題は先ほど表示した C で表示させたいケース。LocationURL に加えて HWND を
併用すれば良いかといえば、これも怪しいところ。一つの IE 上で複数のタブが開かれていた場合、
同じウィンドウハンドルを持つ複数の InternetExplorer が存在することがありえるからです。

もし、HWND も LocationURL も合致するウィンドウが複数あったら、
そのなかのどれを Navigate するのか、曖昧なままですよね。

[ツリー表示へ]
タイトルRe^6: withEventsで生成したInternetExplorerが捕捉できない
記事No16111
投稿日: 2015/04/10(Fri) 22:02
投稿者はなまるき
> > Private sub Command1_Click
> >     Dim objIE As Object
> プロシージャーレベルの変数「objIE」が競合していますよね。

すみません、書き間違いです。実際はそうなっていません。



> そのためにまずは、For Each で使われているループ変数と、
> WithEvents のための変数を、別の変数名に置き換えることから
> はじめてみてください。

書き方って難しいですね。For Eachのコードは標準モジュールに書いています。
それ以外はフォームモジュールです。
なので競合はしていないかと。

>
> > 既に開いていたらそれを、なければNavigateとしたいのですが
> まず、この仕様自体もかなり曖昧になっていますよ。
>
> たとえば、IE が 2 つ起動されていたと思ってください。
> A は Apple、B は Google を表示している状態です。
C で開くです




> さて、問題は (3) のケース。もしもこのパターンを望んでいるんだとしたら、
> 再度、同じURL(Microsoft のサイト)を開きなおしたい場合に、
>
>  (5) C を再利用してそこに Navigate
>  (6) C とは別に D のウィンドウを開く
>
> のどちらにしたいのかが、今までの質問からは読み取れませんでした。
開きなおす必要は無く、ウィンドウをアクティブにするだけです。


>一つの IE 上で複数のタブが開かれていた場合、
> 同じウィンドウハンドルを持つ複数の InternetExplorer が存在することがありえるからです。

想定している範囲はあくまでもアプリで起動したIEです。
タブも単一を想定しており、その後ユーザーがほかのサイトに移動したとしてもそれを考慮する
つもりはありません。

[ツリー表示へ]
タイトルRe^7: withEventsで生成したInternetExplorerが捕捉できない
記事No16114
投稿日: 2015/04/11(Sat) 01:00
投稿者魔界の仮面弁士
> 書き方って難しいですね。For Eachのコードは標準モジュールに書いています。
> それ以外はフォームモジュールです。
> なので競合はしていないかと。
VB6 では、WithEvents を標準モジュールに書けないので、
フォームモジュール等に置く、というのは分かりますが…いずれにせよ
各コードが何処においてあるかは、今回の本質では無いように思います。


そもそも、For Each は何のために必要なのでしょうか?

毎回 For Each でのサーチが必要なのだとすれば、それは、
複数起動されている IE を扱っているという事を意味しますよね。

ですが現在のコードは、WithEvents で管理している IE は一つだけのようです。
それゆえ終了検知も、特定の1インスタンスしか拾えないことになりますが、
それで十分なのであれば、For Each の出番自体が無くなってしまいます。


あるいは、たとえば10個のIEを扱うなら、WithEvents も10個用意しておかないと無意味ですし、
自アプリから起動したものを拾うだけなら、For Each で再列挙の必要もなさそう。

もしも IE の同時起動数が不定で、WithEvents を事前に用意できないなら、
「コントロール配列」のようにイベントを管理するコレクションクラスを
独自に用意してそこに集約させるとか、あるいはイベントシンクを直接 Advise するなど、



> タブも単一を想定しており、その後ユーザーがほかのサイトに移動したとしてもそれを考慮する
> つもりはありません。
であれば、No16105 の方法をベースにして対処できないでしょうか?

ShellWindows だと、アプリ以外で起動されたものまで拾ってしまいますが、
アプリで起動した IE だけを管理すれば良いのなら、そもそも列挙しなおす必要は無いわけで。


VB6 入りの環境が手元にないので、掲示板に直書きのコードですが、
イメージ的にはこんな感じ。
最大化等のコード等は省いていますので、必要に応じて追加してみてください。

Option Explicit
Private WithEvents IE As InternetExplorer
Private Sub Command1_Click()
 If IE Is Nothing Then
    Set objIE = OpenIE(List1.Text)
 Else
  IE.Navigate2 List1.Text
 End If
End Sub
Private Sub IE_OnQuit()
 Set IE = Nothing
End Sub
Private Sub Form_QueryUnload(…
 If Not IE Is Nothing Then IE.Quit
End Sub

[ツリー表示へ]
タイトル解決しました
記事No16115
投稿日: 2015/04/11(Sat) 08:56
投稿者はなまるき
> もしも IE の同時起動数が不定で、WithEvents を事前に用意できないなら、
> 「コントロール配列」のようにイベントを管理するコレクションクラスを
> 独自に用意してそこに集約させるとか、あるいはイベントシンクを直接 Advise するなど、

おそらく1つのobjIEに対して複数起動していたため拾えなかったのかと思います。
最後に起動したものくらいは拾えてもおかしくないと思ったのですが、まったく
拾えなかったので何か別の理由があるのかもと考えていました。
コントロール配列を使用してみます。

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

[ツリー表示へ]
タイトルRe: 解決しました
記事No16118
投稿日: 2015/04/11(Sat) 17:34
投稿者魔界の仮面弁士
> おそらく1つのobjIEに対して複数起動していたため拾えなかったのかと思います。

No16111 で書かれていた フォーム変数、モジュール変数 の使い分けが
どうなっていたのか明らかにされていないので、どこに問題があったのかは分からず仕舞いですが

『1 つの objIE に対して複数』というのが
  Set objIE = OpenIE(URL1)
  Set objIE = OpenIE(URL2)
という状況だとしたら、URL1 側の IE の終了通知を拾えないのは自明ですね。
OnQuit の通知を受け取る前に、以前のインスタンスを捨ててしまう事になりますから。


一方、『1 つの objIE に対して複数』というのが
  Set objIE = OpenIE(〜)
で最後に起動された IE を
 Private WithEvents objIE1 As 〜
 Private WithEvents objIE2 As 〜
  Set objIE1 = objIE
  Set objIE2 = objIE
と割り当てていたという意味ならば、一つのインスタンスにイベントハンドラが何個あっても
OnQuit は各イベントハンドラーに等しく伝わるはずです。


> コントロール配列を使用してみます。
コントロール配列は使えないですよ。 (InternetExplorer はコントロールではありませんので)
コントロール配列「のような」イベント管理コレクションを自作する、という話です。

[ツリー表示へ]
タイトル解決できませんでした
記事No16119
投稿日: 2015/04/11(Sat) 23:42
投稿者はなまるき
> という状況だとしたら、URL1 側の IE の終了通知を拾えないのは自明ですね。
> OnQuit の通知を受け取る前に、以前のインスタンスを捨ててしまう事になりますから。

こちらです


> コントロール配列「のような」イベント管理コレクションを自作する、という話です。

クラス化してそれを配列にしましたが目的は達成できませんでした。

以下のコードにて

フォームモジュール
Private sub List1.Click()
    '変数については多少省略しています
  Dim strURL as string
    Dim ExistURL as string
    Dim ExistIE As Object

    strURL=List1.Text
    ExistURL=Text1.Text

    
    If IECheck(strURL, ExistURL, ExistIE) Then
        Call ShowWindow(ExistIE.hwnd, SW_MAXIMIZE)
        Set ExistIE = Nothing
    Else
        Dim objIE As Object
        Set objIE = OpenIE(strURL)
        IEInputTextbox objIE, IDElement, LoginID
        IEInputTextbox objIE, PasswordElement, Password
        If CheckboxElement <> vbNullString Then
            If ckReverse Then
                IECheckBoxClick objIE, CheckboxElement, True
            Else
                IECheckBoxClick objIE, CheckboxElement, False
            End If
        End If
        IEInputImageClick objIE, LogInElement, src
        
        Do While objIE.Busy = True Or objIE.ReadyState <> 4
            DoEvents
        Loop
        Call ShowWindow(objIE.hwnd, SW_MAXIMIZE)
        Set objIE = Nothing
    End If
End sub

標準モジュール
Public Function OpenIE(strURL As String) As Object

    Dim objIE As Object
    Set objIE = CreateObject("InternetExplorer.application")

    With objIE
        .Visible = True
        Call CloseWindow(.hwnd)
        .Navigate (strURL)
        Do While .Busy = True Or .ReadyState <> 4
            DoEvents
        Loop
    End With
    Set OpenIE = objIE
End Function

Public Function IECheck(strURL As String, Optional ExistsURL As String, Optional ExistIE As Object) As Boolean

    On Error GoTo Exit_Function
    
    Dim objShell As Object
    Dim objShellWindows As Object
    Dim objIE As Object
    Dim ret As Boolean
    
    Set objShell = CreateObject("Shell.Application")
    Set objShellWindows = objShell.Windows

    For Each objIE In objShellWindows
        Select Case ExistsURL
        Case vbNullString
            If InStr(objIE.LocationURL, strURL) <> 0 Then
                ret = True
                Set ExistIE = objIE
                Call ShowWindow(objIE.hwnd, SW_MAXIMIZE)
                GoTo Exit_Function
            End If
        Case Else
            If InStr(objIE.LocationURL, ExistsURL) <> 0 Then
                ret = True
                Set ExistIE = objIE
                GoTo Exit_Function
            End If
        End Select
    Next
    ret = False

Exit_Function:
    IECheck = ret
    Set objShell = Nothing
    Set objShellWindows = Nothing
    
End Function

Public Sub IEInputTextbox(objIE As Object, strElement As String, Value As String)
    
    On Error Resume Next
    
    Dim objInput As Object
    Dim str1 As String
    
    For Each objInput In objIE.document.getElementsByTagName("Input")
  
        If InStr(1, objInput.outerhtml, strElement, vbTextCompare) <> 0 Then
            objInput.Value = Value
            Exit For
        End If
    Next

End Sub

Public Sub IECheckBoxClick(objIE As Object, Name As String, Value As Boolean)

    Dim objCK As Object
    
    For Each objCK In objIE.document.getElementsByTagName("Input")
        If InStr(objCK.outerhtml, Name) <> 0 Then
            objCK.Checked = Value
        End If
    Next
End Sub

Public Function IEInputImageClick(objIE As Object, Element As String, Optional imageSrc As String)
    
    Dim objInput As Object

    For Each objInput In objIE.document.getElementsByTagName("Input")
        Select Case imageSrc
        Case vbNullString
            If InStr(objInput.outerhtml, Element) <> 0 Then
                objInput.Click
                Exit For
            End If
        Case Else
            If InStr(objInput.src, imageSrc) <> 0 And InStr(objInput.outerhtml, Element) Then
                objInput.Click
                Exit For
            End If
        End Select
    Next
End Function

まず、OpenIEにてIEを起動後、同じサイトを起動しIECheckでチェックしてみました。
すると次のようなことが起こりました。
ローカルウィンドウでobjShellWindowsをチェックしてみたところ、
カウントが増える場合と増えない場合があることがわかりました。
それは同一サイトでおこります。
イメージとしては、

パターン1
@Yahooのさいとを開く→ objShellWindowsのcountが増える
A閉じずに再度Yahooのサイトを開く → 同じWindowが最前面に表示される
B閉じずに再度Yahooのサイトを開く → 同じWindowが最前面に表示される

パターン2
@Yahooのさいとを開く→ objShellWindowsのcountが増えない
A閉じずに再度Yahooのサイトを開く → 新しいYahooサイトのWindowが最前面に表示される
B閉じずに再度Yahooのサイトを開く → 新しいYahooサイトのWindowが最前面に表示される

どういう場合にこの違いが生まれるのかがわかりません。
ご教示よろしくお願いします。

[ツリー表示へ]
タイトルRe: 解決できませんでした
記事No16120
投稿日: 2015/04/12(Sun) 00:40
投稿者魔界の仮面弁士
> クラス化してそれを配列にしましたが目的は達成できませんでした。
クラスは最低でも2本作る必要があります。アダプタパターンなら3種類かな。

1 つは IE のイベントを受信するためのクラスで、もう一つは、
複数生成されるそれらのクラスを管理し、自作イベントを RaiseEvent しなおすクラスです。


> カウントが増える場合と増えない場合があることがわかりました。
> どういう場合にこの違いが生まれるのかがわかりません。
新規セッションか別セッションかの違いですかね?
私も情報を持ち合わせてはいません。

今回は自分で起動した IE しか管理する必要が無いとのことですので、
動作に不安のある ShellWindows に頼るのではなく、
御自身で管理するようにしてみては如何でしょう。


ShellWindows に対する動作は、IE のバージョンによっても異なるので、
あまり細かい動作を突き詰めても、徒労に終わってしまうと思います。
(Spartan 登場後はどうなるのだろう?)


> Private sub List1.Click()
ピリオドでは無く、アンダーバーですよね。

検証のためのコードなのであれば、実際に動作するコードを提示して欲しい所です。
コードの内容に揺れがあると、環境依存なのかコードの問題なのか追跡できなくなりますし。

自分は VB6 環境をもはや持ち合わせていないので試せませんけれども。

[ツリー表示へ]
タイトルRe^2: 解決できませんでした
記事No16126
投稿日: 2015/04/13(Mon) 22:33
投稿者はなまるき

> ShellWindows に対する動作は、IE のバージョンによっても異なるので、
> あまり細かい動作を突き詰めても、徒労に終わってしまうと思います。

これで納得しました。
きちんと制御できるはずなのになぜできないのかを考えていたので、
できないとわかれば自分で管理するようにします。

[ツリー表示へ]
タイトルRe^5: withEventsで生成したInternetExplorerが捕捉できない
記事No16121
投稿日: 2015/04/12(Sun) 03:28
投稿者魔界の仮面弁士
> For Each objIE In objShellWindows
>     If InStr(objIE.LocationURL, strURL) <> 0 Then
>        Call ShowWindow(objIE.hWnd, SW_MAXIMIZE)
>        goto Exit_Sub
>     End If
> Next
> Set objIE = OpenIE(strURL)

このコードは、
 ・LocationURL が一致するものがあれば、それを ShowWindow で最大化表示する
 ・見つからなければ、OpenIE を呼び出して、新しい IE を最小化状態で起動する。
というものですよね。


新しいサイトを表示するためには、Command1 ボタンを 2 回押すか、もしくは
Command1 ボタンを押した後でタスクバーのボタンを押す必要があるので
2 度手間な気がするのですが、それ自体は意図した動作なのでしょうか?

しかも、ShowWindow しているだけでアクティブ化の制御は行っていないので、
複数の IE がいずれも SW_MAXIMIZE 状態になっていたとすると、
Command1 を再度押しても、ウィンドウは非アクティブのままで前面表示されないでしょうし…。

[ツリー表示へ]
タイトルRe^6: withEventsで生成したInternetExplorerが捕捉できない
記事No16125
投稿日: 2015/04/13(Mon) 22:31
投稿者はなまるき

> Command1 を再度押しても、ウィンドウは非アクティブのままで前面表示されないでしょうし…。

なぜかSetWindowPosが効かないんですよね・・・

[ツリー表示へ]
タイトルRe^7: withEventsで生成したInternetExplorerが捕捉できない
記事No16128
投稿日: 2015/04/13(Mon) 23:34
投稿者魔界の仮面弁士
> > Command1 を再度押しても、ウィンドウは非アクティブのままで前面表示されないでしょうし…。
> なぜかSetWindowPosが効かないんですよね・・・

SetForegroundWindow はどうでしたか?

[ツリー表示へ]
タイトルRe: withEventsで生成したInternetExplorerが捕捉できない
記事No16122
投稿日: 2015/04/12(Sun) 04:24
投稿者魔界の仮面弁士
やりたい事が理解できているか自信が無いですが、こういうことで良いのかな。

IE の OnQuit イベントの受信は、クラスモジュール CBrowser で行わせています。
で、それをコレクションで束ねた物を、ShellWindows 代わりに使うという寸法です。

OnQuit されたことを自作コレクションに伝えるイベント管理クラスは、面倒なので省略。
イベント通知するかわりに、Form1 自身のメソッドをコールバックすることで代用しています。
複数フォームを持つアプリの場合は、管理クラスも作った方が良いでしょうね。


※当方には Win7 + VB6 な環境が無いので未チェックです。

'==== クラスモジュール「CBrowser」
Option Explicit

Public Owner As Form1
Private WithEvents IE As InternetExplorer

Private Sub Class_Initialize()
    Set IE = New InternetExplorer
    IE.Visible = True
End Sub

Public Property Get Browser() As InternetExplorer
    Set Browser = IE
End Property

Private Sub Class_Terminate()
    Set Owner = Nothing
    IE.Quit     'アプリ終了時にIEを閉じたくないなら「Set IE = Nothing」
End Sub

Private Sub IE_OnQuit()
    'IEが終了したら、管理クラス(この場合はForm1)に通知する
    If Not Owner Is Nothing Then
        Call Owner.OnIEQuit(IE)
    End If
    Set IE = Nothing
End Sub


'==== フォーム「Form1」
'Command1 と List1 を貼り、List1 には URL を並べておく
Option Explicit

Private mCols As Collection     '起動されたIE群を管理するコレクション
Private Declare Function ShowWindow Lib "User32" (ByVal HWND As OLE_HANDLE, ByVal nCmdShow As Long) As Long
Private Declare Function CloseWindow Lib "User32" (ByVal HWND As OLE_HANDLE) As Long

Private Sub Form_Initialize()
    Set mCols = New Collection
End Sub

Private Sub Command1_Click()
    Const SW_SHOWMAXIMIZED = 3&
    
    Dim strURL As String
    strURL = List1.Text

    Dim oBrowser As CBrowser
    For Each oBrowser In mCols
        If InStr(oBrowser.Browser.LocationURL, strURL) <> 0 Then
            'すでに開いているURLなら最大化する
            '(アクティブ化のコードは用意しなくて良いのかな?)
            Call ShowWindow(oBrowser.Browser.HWND, SW_SHOWMAXIMIZED)
            Exit Sub
        End If
    Next
    'まだ開いてないページなら新規に開く(ただし最小化で)
    Call OpenIE(strURL)
End Sub

'自作クラス CBrowser からの終了通知を受け取るためのコールバック
Friend Sub OnIEQuit(ByVal sender As InternetExplorer)
    Dim n As Long
    For n = 1 To mCols.Count
        If mCols(n).Browser Is sender Then
            '終了したIEをコレクションから取り除く
            Call mCols.Remove(n)
            Exit For
        End If
    Next
End Sub

'IEを起動し、コレクションで管理する
Public Sub OpenIE(ByVal strURL As String)
    Dim oBrowser As CBrowser
    Set oBrowser = New CBrowser
    Set oBrowser.Owner = Me      'コールバック先のクラス
    Call mCols.Add(oBrowser)     '自作コレクションに追加
    Call CloseWindow(IE.HWND)    '最小化
    Call oBrowser.Browser.Navigate2(strURL)
End Sub

[ツリー表示へ]
タイトルRe^2: withEventsで生成したInternetExplorerが捕捉できない
記事No16130
投稿日: 2015/04/14(Tue) 15:44
投稿者はなまるき
> Private WithEvents IE As InternetExplorer
クラスモジュール側にWithEventsがあったのでこれを削ったのですが、
onQuitでイベントが起きませんでした。

そのため、
For Each oBrowser In mCols
        If InStr(oBrowser.Browser.LocationURL, strURL) <> 0 Then

のところで、
「オートメーションエラーです」
「起動されたオブジェクトはクライアントから切断されました」とエラーが出ます。

どうやってイベントを捕らえればいいでしょうか?


それと、アプリ以外で起動したIEもこれで管理するには、
どのようにすれば可能でしょうか?

[ツリー表示へ]
タイトルRe^3: withEventsで生成したInternetExplorerが捕捉できない
記事No16131
投稿日: 2015/04/14(Tue) 15:57
投稿者はなまるき
> For Each oBrowser In mCols
>         If InStr(oBrowser.Browser.LocationURL, strURL) <> 0 Then
>
> のところで、
> 「オートメーションエラーです」
> 「起動されたオブジェクトはクライアントから切断されました」とエラーが出ます。
>
> どうやってイベントを捕らえればいいでしょうか?


すみません間違えてました。
当初標準モジュールに書いていたためエラーとなり、削除後にクラスモジュールに
ペーストしたためこのような事態となりました。
お恥ずかしい限りです。

[ツリー表示へ]
タイトルRe^3: withEventsで生成したInternetExplorerが捕捉できない
記事No16132
投稿日: 2015/04/14(Tue) 17:25
投稿者魔界の仮面弁士
> それと、アプリ以外で起動したIEもこれで管理するには、
> どのようにすれば可能でしょうか?

最初の ShellWindows 案に戻ることになるでしょうね。

もしくは InternetExplorer オブジェクトを保持する方式ではなく、
起動の都度、EnumWindows 等で IE を列挙してから、それらの子ウィンドウに対して
http://hpcgi1.nifty.com/MADIA/VBBBS/wwwlng.cgi?print+200904/09040020.txt
で DOM を取り出し、そこから IHTMLWindow2::location 経由で URL を貰ってきて
起動済み判定を行うよう書き換えてみるとか。

[ツリー表示へ]
タイトル解決しました
記事No16133
投稿日: 2015/04/14(Tue) 17:42
投稿者はなまるき
> 最初の ShellWindows 案に戻ることになるでしょうね。

ですよね。
ここまで付き合っていただいてありがとうございました。
非常に勉強になりました。

[ツリー表示へ]