C# と VB.NET の質問掲示板

わんくま同盟

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

ツリー一括表示

AddHandler Eventの別スレッドについて /TanuTanu (19/03/11(Mon) 14:26) #90434
Re[1]: AddHandler Eventの別スレッドについて /魔界の仮面弁士 (19/03/11(Mon) 18:02) #90439
│└ Re[2]: AddHandler Eventの別スレッドについて /TanuTanu (19/03/11(Mon) 20:50) #90440
Re[1]: AddHandler Eventの別スレッドについて /Azulean (19/03/11(Mon) 21:06) #90441
  └ Re[2]: AddHandler Eventの別スレッドについて /TanuTanu (19/03/12(Tue) 11:11) #90444
    ├ Re[3]: AddHandler Eventの別スレッドについて /PANG2 (19/03/12(Tue) 12:31) #90446
    │└ Re[4]: AddHandler Eventの別スレッドについて /TanuTanu (19/03/12(Tue) 13:17) #90452
    ├ Re[3]: AddHandler Eventの別スレッドについて /魔界の仮面弁士 (19/03/12(Tue) 14:24) #90454
    │└ Re[4]: AddHandler Eventの別スレッドについて /魔界の仮面弁士 (19/03/12(Tue) 14:31) #90455
    │  └ Re[5]: AddHandler Eventの別スレッドについて /魔界の仮面弁士 (19/03/12(Tue) 15:03) #90456
    │    └ Re[6]: AddHandler Eventの別スレッドについて /TanuTanu (19/03/12(Tue) 17:37) #90458
    │      └ Re[7]: AddHandler Eventの別スレッドについて /魔界の仮面弁士 (19/03/12(Tue) 18:32) #90461
    │        └ Re[8]: AddHandler Eventの別スレッドについて /TanuTanu (19/03/12(Tue) 19:54) #90463
    │          ├ Re[9]: AddHandler Eventの別スレッドについて /魔界の仮面弁士 (19/03/13(Wed) 09:51) #90469
    │          └ Re[9]: AddHandler Eventの別スレッドについて /TanuTanu (19/03/13(Wed) 09:32) #90468
    │            └ Re[10]: AddHandler Eventの別スレッド /TanuTanu (19/03/13(Wed) 14:49) #90473
    │              └ Re[11]: AddHandler Eventの別スレッド /魔界の仮面弁士 (19/03/13(Wed) 16:03) #90475
    └ Re[3]: AddHandler Eventの別スレッドについて /PANG2 (19/03/13(Wed) 16:01) #90474
      └ Re[4]: AddHandler Eventの別スレッドについて /TanuTanu (19/03/13(Wed) 16:55) #90476
        ├ Re[5]: AddHandler Eventの別スレッドについて /TanuTanu (19/03/13(Wed) 20:27) #90477
        │└ Re[6]: AddHandler Eventの別スレッドについて /魔界の仮面弁士 (19/03/15(Fri) 11:55) #90511 解決済み
        └ Re[5]: AddHandler Eventの別スレッドについて /PANG2 (19/03/14(Thu) 18:59) #90492
          └ Re[6]: AddHandler Eventの別スレッドについて /TanuTanu (19/03/15(Fri) 10:28) #90508 解決済み
            └ Re[7]: AddHandler Eventの別スレッドについて /TanuTanu (19/03/18(Mon) 16:52) #90531
              └ Re[8]: AddHandler Eventの別スレッドについて /魔界の仮面弁士 (19/03/18(Mon) 18:18) #90533
                └ Re[9]: AddHandler Eventの別スレッドについて /TanuTanu (19/03/19(Tue) 20:43) #90543
                  └ Re[10]: AddHandler Eventの別スレッドについて /TanuTanu (19/03/20(Wed) 14:04) #90547
                    └ Re[11]: AddHandler Eventの別スレッドについて /TanuTanu (19/03/20(Wed) 23:14) #90556
                      ├ Re[12]: AddHandler Eventの別スレッドについて /PANG2 (19/03/21(Thu) 07:17) #90557
                      └ Re[12]: AddHandler Eventの別スレッドについて /魔界の仮面弁士 (19/03/21(Thu) 10:39) #90558
                        └ Re[13]: AddHandler Eventの別スレッド /TanuTanu (19/03/22(Fri) 12:36) #90583
                          ├ Re[14]: AddHandler Eventの別スレッド /PANG2 (19/03/22(Fri) 13:20) #90588
                          └ Re[14]: AddHandler Eventの別スレッド /魔界の仮面弁士 (19/03/22(Fri) 15:03) #90589
                            └ Re[15]: AddHandler Eventの別スレッド /TanuTanu (19/03/22(Fri) 16:21) #90590
                              └ Re[16]: AddHandler Eventの別スレッド /魔界の仮面弁士 (19/03/22(Fri) 17:17) #90591
                                └ Re[17]: AddHandler Eventの別スレッド /TanuTanu (19/03/22(Fri) 20:17) #90592 解決済み


親記事 / ▼[ 90439 ] ▼[ 90441 ]
■90434 / 親階層)  AddHandler Eventの別スレッドについて
□投稿者/ TanuTanu (4回)-(2019/03/11(Mon) 14:26:17)

分類:[VB.NET/VB2005 以降] 

2019/03/11(Mon) 14:31:28 編集(投稿者)
2019/03/11(Mon) 14:31:21 編集(投稿者)

度々、質問してしまい申し訳ありません。
欲が出てしまい『■90409 VB.NETのHTMLDocumentイベントについて』 で追加しましたイベント
を別スレッドで動作させたいのですが出来ますでしょうか?

下記コードでは、buttonをクリックした後、webページダイアログが表示され
そのwebページダイアログを閉じた後にMessageBoxが表示されてしまい困っております。

何卒、ご教授の程宜しくお願いいたします。


Dim Button As mshtml.IHTMLElement = doc.all.item("button")
Event1 = DirectCast(Buttoni, mshtml.HTMLInputTextElementEvents2_Event)
AddHandler Event1.onclick, AddressOf WebDisp_click

Private Function WebDisp_click(ByVal e As mshtml.IHTMLEventObj) As Boolean

Dim t As New System.Threading.Thread(New System.Threading.ThreadStart(AddressOf DoSomething))
t.SetApartmentState(System.Threading.ApartmentState.STA)
t.Start()

End Function

Private Sub DoSomething()

MessageBox.Show("webDisp_onclick")

End Sub

開発環境、使用言語、開発者LV:VS2017、VB.NET、ビギナー
[ □ Tree ] 返信 編集キー/

▲[ 90434 ] / ▼[ 90440 ]
■90439 / 1階層)  Re[1]: AddHandler Eventの別スレッドについて
□投稿者/ 魔界の仮面弁士 (2098回)-(2019/03/11(Mon) 18:02:21)
No90434 (TanuTanu さん) に返信
> Dim Button As mshtml.IHTMLElement = doc.all.item("button")
この場合、Option Strict Off にしないとコンパイルできなくなりますね。


> Event1 = DirectCast(Buttoni, mshtml.HTMLInputTextElementEvents2_Event)
変数名が違うようですが、ここの "Buttoni" とその直前の "Button" は同じものですか?


> AddHandler Event1.onclick, AddressOf WebDisp_click
この Event1 はローカル変数でしょうか。クラスのインスタンスフィールドでしょうか。
ローカル変数だとしたら、GC されて切断されることを防ぐため、フィールド変数に変更して
イベント通知が不要になるまで、インスタンスを保持しておく必要があります。


> 下記コードでは、buttonをクリックした後、webページダイアログが表示され
元の Web ページ側にダイアログ表示のスクリプトがあるのだと思いますが、
JavaScript 側で既に onclick イベントが割り当てられている場合、
そちらの処理が先に発生し、VB 側に通知されるのはその後になるかと思います。
(イベントの割り当て方法にもよりますが)


> Private Function WebDisp_click(ByVal e As mshtml.IHTMLEventObj) As Boolean
戻り値を返し忘れていますよ。


> 欲が出てしまい『■90409 VB.NETのHTMLDocumentイベントについて』 で追加しましたイベント
> を別スレッドで動作させたいのですが出来ますでしょうか?
button 要素 の onclick イベントに割り当てたいようですが、どの部分をどのスレッドで動作させたいのでしょうか。

(1) WebDisp_click を、UI スレッド上で実行したい
(2) WebDisp_click を、特定のワーカースレッドで呼び出したい
(3) WebDisp_click を、その都度、新しいスレッドで呼び出したい
(4) Sub DoSomething が、UI スレッド上で呼びだされるようにしたい
(5) Sub DoSomething が、特定のワーカースレッドで呼び出したい
(6) Sub DoSomething が、その都度、新しいスレッドで呼び出したい
(7) 「MessageBox」の呼び出し部のみを、UI スレッドで実行させたい
(8) 「MessageBox」の呼び出し部のみを、特定のワーカースレッドで呼び出したい
(9) 「MessageBox」の呼び出し部のみを、その都度、新しいスレッドで呼び出したい

イベントの発火にしろ、デリゲートの呼び出しにせよ、それが実行されるスレッドは、
「イベント通知を受け取る側/デリゲートインスタンスの生成側」でコントロールするものではなく、
「イベントを発生させる側/デリゲートでメソッドを呼び出す側」でコントロールするものかと。


たとえば RaiseEvent だとしたら、基本的には「イベントの発生元」のスレッドが使われるので、
他スレッドへのイベント通知が必要なら、ISynchronizeInvoke を使うなどします。


呼び出し元に頼らず、イベントを受け取った側で他のスレッドに処理したいなら、
自身を該当スレッド上で Invoke しなおすことで対処してみてください。
たとえば、常に UI スレッド上で処理を行いたいなら、InvokeRequired で判定して Invoke しなおすとか。
[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90439 ] / 返信無し
■90440 / 2階層)  Re[2]: AddHandler Eventの別スレッドについて
□投稿者/ TanuTanu (5回)-(2019/03/11(Mon) 20:50:47)
魔界の仮面弁士 様

お世話になっております。
返信遅れ申し訳ありません。
自分がもしかしてとんでもなく難しい事しようとしているのでは?
と暫く思考停止になっていました。

ご教授いただいた下記内容でトライしてみようと思います。
>常に UI スレッド上で処理を行いたいなら、InvokeRequired で判定して Invoke しなおすとか。

まだ調査始めたばかりですがC#ばかりでVBの参考サイトが少なく苦慮しておりますが
いろいろ調べてみようと思います。
この度はご教授頂けて本当に助かりました。
解決致しましたら改めてご報告致しますので宜しくお願いいたします。


[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90434 ] / ▼[ 90444 ]
■90441 / 1階層)  Re[1]: AddHandler Eventの別スレッドについて
□投稿者/ Azulean (1041回)-(2019/03/11(Mon) 21:06:30)
ご自身がやりたいことを端的に書かないと、迷走しますよ。

No90434 (TanuTanu さん) に返信
> 下記コードでは、buttonをクリックした後、webページダイアログが表示され
> そのwebページダイアログを閉じた後にMessageBoxが表示されてしまい困っております。

本題はこの部分ですよね?

現状:ボタンクリック後、Web ページダイアログの次に MessageBox が表示される
希望:ボタンクリック後、MessageBox が表示され、Web ページダイアログが表示される、または MessageBox だけが表示される

この希望の実現方法に、実は「別スレッド」と言うことは関係していません。
知らない状態でそれに気づくことは難しいと思いますが、なおのこと、「現状と実現したいこと」と「試したこととどうなったか」は明確に分離しておかないと、脱線・迷走します。


なお、この「希望」の認識が合っていた場合、魔界の仮面弁士さんの以下の部分が現状を説明していますs。

> 元の Web ページ側にダイアログ表示のスクリプトがあるのだと思いますが、
> JavaScript 側で既に onclick イベントが割り当てられている場合、
> そちらの処理が先に発生し、VB 側に通知されるのはその後になるかと思います。
[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90441 ] / ▼[ 90446 ] ▼[ 90454 ] ▼[ 90474 ]
■90444 / 2階層)  Re[2]: AddHandler Eventの別スレッドについて
□投稿者/ TanuTanu (6回)-(2019/03/12(Tue) 11:11:41)
Azulean 様

ご教授ありがとうございます。

■現状

@ある画面のボタンを手動でクリック
Aそのボタンのonclick イベント発生
B上記ScriptによりWebページダイアログ表示
C手動でWebページダイアログ閉じる
DMessageBox.Show("webDisp_onclick")作動

■実現したい事

@ある画面のボタンを手動でクリック
Aそのボタンのonclick イベント発生
B上記ScriptによりWebページダイアログ表示 & MessageBox.Show("webDisp_onclick")作動

---------------------------------

■試した事

WithEvents doc As mshtml.HTMLDocumentClassでfocusoutイベントをキャッチし
MessageBox.Show("webDisp_onclick")を作動。
この方法では上記実現したい事は実現しますが、ボタンをクリックしなくても
フォーカスアウトする度にイベントが発生してしまうので
MessageBox.Show("webDisp_onclick")の作動条件式が必要になります。

---------------------------------

もし可能であれば、focusoutイベントではなくボタンクリックのAttachEventHandler等で実現したい。

魔界の仮面弁士 様、Azulean 様のご解答では
> そちらの処理が先に発生し、VB 側に通知されるのはその後になるかと思います。
であるように基本不可能と思って間違いないでしょうか?
であれば上記■試した事で作動条件式を作っていく方法で進めたいと思います。

今回、多くの事を教えて頂いたのでそちらも学習したいと思います。
ありがとうございました。
[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90444 ] / ▼[ 90452 ]
■90446 / 3階層)  Re[3]: AddHandler Eventの別スレッドについて
□投稿者/ PANG2 (266回)-(2019/03/12(Tue) 12:31:54)
2019/03/12(Tue) 12:36:54 編集(投稿者)
No90444 (TanuTanu さん) に返信
>>そちらの処理が先に発生し、VB 側に通知されるのはその後になるかと思います。
> であるように基本不可能と思って間違いないでしょうか?

C#/WebBrowser でイベントの発生順を変えてみました。

private void Form1_Load(object sender, EventArgs e)
{
	this.webBrowser1.DocumentText
		= "<html><body><input id=button1 type=button onclick=\"alert('hello1')\"></body></html>";
}

private void webBrowser1_DocumentCompleted(object sender, EventArgs e)
{
	HtmlElement button = webBrowser1.Document.GetElementById("button1");
#if false
	button.Click += delegate {
		MessageBox.Show("hello2");
	};
#else
	string script = ((dynamic)button.DomElement).attributes("onclick").value; //onclickイベントのスクリプト
	button.SetAttribute("onclick", "");//onclickイベントをクリア
	button.Click += delegate {
		MessageBox.Show("hello2");
		webBrowser1.Navigate("javascript:" + script);//元のonclickイベントを実行
	};
#endif
}

[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90446 ] / 返信無し
■90452 / 4階層)  Re[4]: AddHandler Eventの別スレッドについて
□投稿者/ TanuTanu (7回)-(2019/03/12(Tue) 13:17:24)
PANG2 様

ご教授ありがとうございます。

その方法は禁断だったのですが・・・

魔界の仮面弁士 様、Azulean 様の下記コメにもあるようにその方法しか残されていないのかもしれませんね。
特にビギナーの私にはそれが一番シンプルですし、、、

>イベントの発火にしろ、デリゲートの呼び出しにせよ、それが実行されるスレッドは、
>「イベント通知を受け取る側/デリゲートインスタンスの生成側」でコントロールするものではなく、
>「イベントを発生させる側/デリゲートでメソッドを呼び出す側」でコントロールするものかと。

もう暫く検討してみて対処方法が他になければPANG2 様にご教授頂いた方法で進めようと思います。

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

[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90444 ] / ▼[ 90455 ]
■90454 / 3階層)  Re[3]: AddHandler Eventの別スレッドについて
□投稿者/ 魔界の仮面弁士 (2100回)-(2019/03/12(Tue) 14:24:57)
No90444 (TanuTanu さん) に返信
この掲示板では、新規投稿時の注意書きに
 『半角カナは使用しないでください。文字化けの原因になります。』
と記載されておりますので、以後の投稿では、
カタカナを全角表記に統一していただけるとありがたいです。


> @ある画面のボタンを手動でクリック

具体例となるものが欲しかったのですが……とりあえずこちらで提示してみます。

下記は onclick 時に、JavaScript 側で confirm メソッドが呼ばれており、
それによって Web ページダイアログが表示される仕様になっています。
ダイアログで OK するとページ遷移、Cancel では何もしないというものです。
https://www.javadrive.jp/javascript/event/sample2_1.html


対してこちらは、onclick と addEventListener の併用です。
Web ページダイアログを表示させるコードは含まれていませんが、
ボタンを押すたびにテキストが書き込まれるようになっています。
https://ozepon.github.io/onclick_vs_addEventListener/



> もし可能であれば、focusoutイベントではなくボタンクリックのAttachEventHandler等で実現したい。

mshtml に、そんなメソッドありましたっけ?

もしかして、System.Windows.Forms.HtmlElement クラスの AttachEventHandler のことでしょうか。
No90410 はマネージ WebBrowser の話であり、今回のような、 COM の InternetExplorer や WebBrowser には
直接的には関係ありません。(マネージ版も内部で COM を呼んでいるので、間接的には関係ありますが)


IHTMLDocument3 の attachEvent メソッドや、
IEventTarget の addEventListener メソッドの事だとしたら、
レンダリングされている HTML ドキュメントに応じて、
 IE5〜IE8 モードの場合 → attachEvent のみをサポート
 IE9〜IE10 モードの場合 → attachEventとaddEventListenerをサポート
 IE11 モードの場合 → addEventListener のみをサポート
だったはず。

また、イベントは登録した順に割り当てられるものであり、発生順を変えることは基本的にできません。

onclick だけなら、イベントの付け外しも比較的容易なのですが、
attachEvent / addEventListener の場合、detachEvent / removeEventListener するには、
登録したリスナー(イベントハンドラとなる function オブジェクト)を入手する手段が必要で。

同一要素に対してイベントを割り当てるのではなく、
親要素・子要素に対してイベントを割り当てるという手はありますが、
いずれにせよ、ページの作りにも左右される事になると思います。
https://qiita.com/hosomichi/items/49500fea5fdf43f59c58
https://qiita.com/landrunner/items/ab162e305fa2e279c219
[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90454 ] / ▼[ 90456 ]
■90455 / 4階層)  Re[4]: AddHandler Eventの別スレッドについて
□投稿者/ 魔界の仮面弁士 (2101回)-(2019/03/12(Tue) 14:31:26)
2019/03/12(Tue) 14:41:42 編集(投稿者)

No90452 (TanuTanu さん) に返信
> 魔界の仮面弁士 様、Azulean 様の下記コメにもあるようにその方法しか残されていないのかもしれませんね。

スレッド管理の話とイベントの発生順の話は無関係ですよね…?


質問内容は「イベントの発生順を変更したい」ということではないのでしょうか。

それともイベントの発生順は JavaScript → VB の順番のままで構わないので、
VB 側のイベント処理を「別スレッドで処理させたい」という質問なのでしょうか。



No90454 (魔界の仮面弁士 ) に追記
> また、イベントは登録した順に割り当てられるものであり、発生順を変えることは基本的にできません。
>
> onclick だけなら、イベントの付け外しも比較的容易なのですが、

とりあえず
 https://www.javadrive.jp/javascript/event/sample2_1.html
に対するサンプル。


Option Strict On
Public Class Form1
 Private doc As mshtml.HTMLDocument
 Private yahooButton As mshtml.IHTMLElement
 Private Event1 As mshtml.HTMLInputTextElementEvents2_Event

 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
  Dim o As Object = GetIEDocument( ターゲットのHWND ) ' No90411 を参照
  doc = DirectCast(o, mshtml.HTMLDocument)
  yahooButton = DirectCast(doc.all.item("yahoo"), mshtml.IHTMLElement)
  Event1 = DirectCast(yahooButton, mshtml.HTMLInputTextElementEvents2_Event)
  AddHandler Event1.onclick, AddressOf WebDisp_click
 End Sub

 Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
  yahooButton.click()
 End Sub

 Private Function WebDisp_click(ByVal e As mshtml.IHTMLEventObj) As Boolean
  MsgBox("webDisp_onclick", MsgBoxStyle.SystemModal)
  Return True
 End Function
End Class


この場合、input type="button" に対する onclick が割り当て済みなので、
その後で VB からイベントにアタッチしても、JavaScript 側の処理が先に実行されます。
そのため VB の WebDisp_click が呼ばれるのは、Web ページダイアログが閉じられた後になります。


上記の順番を入れ替えて、VB 側で捕らえてから JavaScript 側の処理を実行させるようにするなら、たとえばこんな感じ。


Option Strict On
Public Class Form1
 Private doc As mshtml.HTMLDocument
 Private yahooButton As mshtml.IHTMLElement
 Private Event1 As mshtml.HTMLInputTextElementEvents2_Event
 Private yahooButton_onclick As Object

 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
  Dim o As Object = GetIEDocument( ターゲットのHWND ) ' No90411 を参照
  doc = DirectCast(o, mshtml.HTMLDocument)
  yahooButton = DirectCast(doc.all.item("yahoo"), mshtml.IHTMLElement)

  yahooButton_onclick = yahooButton.onclick '元の function オブジェクト
  yahooButton.onclick = Nothing '割り当てクリア

  Event1 = DirectCast(yahooButton, mshtml.HTMLInputTextElementEvents2_Event)
  AddHandler Event1.onclick, AddressOf WebDisp_click
 End Sub

 Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
  yahooButton.click()
 End Sub

 Private Function WebDisp_click(ByVal e As mshtml.IHTMLEventObj) As Boolean
  MsgBox("webDisp_onclick", MsgBoxStyle.SystemModal)

  Return CBool(CallByName(yahooButton_onclick, "[DispId=0]", CallType.Method, e)) '元の onclick 処理をここで呼び出す
 End Function
End Class
[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90455 ] / ▼[ 90458 ]
■90456 / 5階層)  Re[5]: AddHandler Eventの別スレッドについて
□投稿者/ 魔界の仮面弁士 (2102回)-(2019/03/12(Tue) 15:03:23)
2019/03/12(Tue) 15:51:52 編集(投稿者)

No90455 (魔界の仮面弁士) に追記
> それともイベントの発生順は JavaScript → VB の順番のままで構わないので、
> VB 側のイベント処理を「別スレッドで処理させたい」という質問なのでしょうか。

たとえば『AddHandler Event1.onclick, AddressOf WebDisp_click』の割り当てによって
WebDisp_click が呼ばれた際に、メッセージボックスを非同期で表示したいのなら、先ほどの

 Private Function WebDisp_click(ByVal e As mshtml.IHTMLEventObj) As Boolean
   'これを閉じるまでフォームを操作できない
   MsgBox("webDisp_onclick", MsgBoxStyle.SystemModal)
   Return True
 End Function

というコードの代わりに

 Private Function WebDisp_click(ByVal e As mshtml.IHTMLEventObj) As Boolean
   Task.Run(Sub()
          'これを開いたままでもフォームを操作できる
          MsgBox("webDisp_onclick", MsgBoxStyle.SystemModal)
        End Sub)
   Return True
 End Function

などと書くことができます。
[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90456 ] / ▼[ 90461 ]
■90458 / 6階層)  Re[6]: AddHandler Eventの別スレッドについて
□投稿者/ TanuTanu (8回)-(2019/03/12(Tue) 17:37:53)
魔界の仮面弁士 様

サンプル、説明、ソース等々何から何までご教授頂き誠にありがとうございます。
半角カナの件は注意して書く様に致します。

今回、頂いたソースですが、下記の行でエラーが発生しました。

yahooButton.onclick = Nothing '割り当てクリア

エラー:System.NotImplementedException: 'メソッドまたは操作は実装されていません。'

ビルドは出来ましたが、HTML読み込み時にyahooButtonでエラー発生しました。

対処方法をご教授頂きたく存じます。
宜しくお願いいたします。

※Option Strict ON にするとエラー多発の為、OFFにしておりますが、これとは関係ないと思っていいでしょうか?

[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90458 ] / ▼[ 90463 ]
■90461 / 7階層)  Re[7]: AddHandler Eventの別スレッドについて
□投稿者/ 魔界の仮面弁士 (2103回)-(2019/03/12(Tue) 18:32:32)
No90458 (TanuTanu さん) に返信
> ※Option Strict ON にするとエラー多発の為、OFFにしておりますが、これとは関係ないと思っていいでしょうか?
当方では、On/Off どちらでも動いていますね。何が違うのだろう?
後ほど、別の PC でもテストしてみます。

なおテスト前には、Internet Explorer 側で [F5] を押すなどして、ページを読み込みなおしておいてください。
先のコードには、クリアした onclick イベントを復元する処理を仕込んでいないためです。
(復元していないため、処理成功後に VB 側を終了させると yahoo ボタンの onclick が無反応になります)


> 今回、頂いたソースですが、下記の行でエラーが発生しました。
> yahooButton.onclick = Nothing '割り当てクリア

その直前までは実行できているのですね。
下記の処理で、メッセージボックスには何が表示されますか?

yahooButton_onclick = yahooButton.onclick
Dim b1 = IsDBNull(yahooButton_onclick)
Dim b2 = IsNothing(yahooButton_onclick)
If b1 OrElse b2 Then
  MsgBox($"DBNull={b1}, Nothing={b2}")
Else
  MsgBox(CallByName(yahooButton_onclick, "toString", CallType.Method))
  yahooButton.onclick = DBNull.Value
End If


> エラー:System.NotImplementedException: 'メソッドまたは操作は実装されていません。'
改変を防止するようなセキュリティソフト等でブロックされているとか…?
[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90461 ] / ▼[ 90469 ] ▼[ 90468 ]
■90463 / 8階層)  Re[8]: AddHandler Eventの別スレッドについて
□投稿者/ TanuTanu (9回)-(2019/03/12(Tue) 19:54:56)
魔界の仮面弁士 様

何度もお手数お掛けし申し訳ありません。
ご教授頂いた件、下記の通りとなります。

■Option Strict ON にするとエラー多発の件

以下のようなエラーが多数発生してしまいます。

エラー BC30574 Option Strict On では、遅延バインディングを使用できません。
CreateObject("Shell.Application").Windows

エラー BC30512 Option Strict On では 'Object' から 'InternetExplorer' への暗黙的な変換は許可されていません。
objIE.LocationName

エラー BC30512 Option Strict On では 'Integer' から 'IntPtr' への暗黙的な変換は許可されていません。
PWnd = FindWindowExA(0, 0,・・・

■下記の処理で、メッセージボックスには何が表示されますか?

下記が表示されました。
※ボタン名称は非公開にしております。

function onclick()
{
on Click ボタン名称()
}

■改変を防止するようなセキュリティソフト等でブロックされているとか…?

セキュリティソフトが入っております。

■試しに実施した事

yahooButton.onclick = Nothing 削除してみました。
MsgBox("webDisp_onclick", MsgBoxStyle.SystemModal)は表示されますが、ボタンクリックで表示されるWEBページダイアログが表示されません。

イベントの復元を実装すれば希望する動作になりそうな感じがします。
しかし私には復元方法が解りません。

不躾で申し訳ありませんが何卒宜しくお願いいたします。



[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90463 ] / 返信無し
■90469 / 9階層)  Re[9]: AddHandler Eventの別スレッドについて
□投稿者/ 魔界の仮面弁士 (2107回)-(2019/03/13(Wed) 09:51:47)
2019/03/13(Wed) 14:39:48 編集(投稿者)

No90463 (TanuTanu さん) に返信
> CreateObject("Shell.Application").Windows

えぇ…。(−ー;
別スレッドである No90411 を含め、今までこんなコードの話は
出ていなかったように思うんですが、どこかで言及されていましたっけ?


上記をレイトバインドで処理したいのであれば、
過去ログの No47158 , No35068 あたりを探ってみてください。


というか上記を使っているのなら、わざわざ API を駆使して
>>> 下記サイトのGetIEDocumentでHTMLDocumentを取得しております。
のような方法を取る必要は無いと思いますよ。

Windows プロパティから得たコレクションを列挙することで、
個々の InternetExplorer オブジェクトを取得できるので、
その Document プロパティにアクセスすれば、
HTMLDocument のインスタンスを得ることができますよね。


> エラー BC30512 Option Strict On では 'Object' から 'InternetExplorer' への暗黙的な変換は許可されていません。
> objIE.LocationName
objIE 変数が As Object なのだとしたら、As SHDocVw.InternetExplorer にしてください。

この場合、参照設定として、
 ・"Microsoft Internet Controls" (SHDocVw)
 ・"Microsoft Shell Controls And Automation" (Shell32)
が必要です。


参照設定を加えずに Option Strict On のままにしたいのであれば、
先日の回答 ( No90410 , No90461 )や、上記過去ログ ( No35068 )などのように、
CallByName を経由してアクセスする必要があります。


> エラー BC30512 Option Strict On では 'Integer' から 'IntPtr' への暗黙的な変換は許可されていません。
> PWnd = FindWindowExA(0, 0,・・・
IntPtr 型の引数に 「0」という Integer 値を渡しているからでしょう。
ここは IntPtr.Zero とすべきです。

さらに言えば、FindWindowExA API ではなく FindWindowExW API を用いた方が望ましいと思います。


> 下記が表示されました。
> ※ボタン名称は非公開にしております。
だとしたら、ターゲットにしているページが間違っています。

取得した HTMLDocument が、先の No90454 で示した
>> https://www.javadrive.jp/javascript/event/sample2_1.html
になっていることを再度確認してみてください。

このページから取得した yahoo ボタンであれば、下記の内容が表示されるはずなんですが…。

---------------------------
function onclick(event)
{
kakunin(1)
}
---------------------------


上記の URL でも問題が生じるなら、環境依存の問題がありそうです。

上記の URL では成功したけれども、目標としている URL だと失敗するのなら、
jQueryのイベントハンドラが使われているなど、そのページ固有の
別の問題がある可能性があるので、具体的な URL なり、
正確なページの内容(HTML & JavaScript)が分からない事には、
情報不足過ぎて答えようが無いです。
[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90463 ] / ▼[ 90473 ]
■90468 / 9階層)  Re[9]: AddHandler Eventの別スレッドについて
□投稿者/ TanuTanu (10回)-(2019/03/13(Wed) 09:32:09)
 魔界の仮面弁士 様

 お世話になっております。
 本日、教えて頂いたコードを駆使してトライしておりますが、下記コードReturn値のエラーで躓いております。

 ■エラー内容
 
 System.Runtime.InteropServices.InvalidComObjectException
 Message=基になる RCW から分割された COM オブジェクトを使うことはできません。


 ■試した内容

Private Function WebDisp_click(ByVal e As mshtml.IHTMLEventObj) As Boolean

 Task.Run(Sub()
'これを開いたままでもフォームを操作できる
MsgBox("webDisp_onclick", MsgBoxStyle.SystemModal)
End Sub)

 Return CBool(CallByName(yahooButton_onclick, "[DispId=0]", CallType.Method, e))

End Function

"[DispId=0]"のところを元のメソッド名にしたりして、いろいろ変えてみましたが同じエラーになります。

 ご教授頂きたく存じます。
 宜しくお願いいたします。

[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90468 ] / ▼[ 90475 ]
■90473 / 10階層)  Re[10]: AddHandler Eventの別スレッド
□投稿者/ TanuTanu (11回)-(2019/03/13(Wed) 14:49:00)
2019/03/13(Wed) 14:59:10 編集(投稿者)
2019/03/13(Wed) 14:58:24 編集(投稿者)

魔界の仮面弁士 様

大変お世話になっております。
新プロジェクトにて■No90455 を試す事にしました。

下記コードにてPWnd1、PWnd2、PWnd3ともに0になってしまいます。
VB.NETでクラス、タイトル、ハンドル列挙する方法が解らず
このようなコードになってしまいました。

初歩的な事で申し訳ありませんがご教授頂きたく存じます。
宜しくお願いいたします。

Option Strict On ・・・プロジェクトプロパティでOnするとエラーになる為、ここに直接記載
Public Class Form1

Dim PWnd1 As IntPtr
Dim PWnd2 As IntPtr
Dim PWnd3 As IntPtr
Dim aShell As SHDocVw.ShellWindows

Private doc As mshtml.HTMLDocument

Private yahooButton As mshtml.IHTMLElement
Private Event1 As mshtml.HTMLInputTextElementEvents2_Event

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

PWnd1 = FindWindowExW(IntPtr.Zero, IntPtr.Zero, vbNullString, "JavaScript テスト")・・・FindWindowExWに変更しました。

Debug.WriteLine(PWnd1)

PWnd2 = FindWindowExW(IntPtr.Zero, IntPtr.Zero, "IEFrame", "JavaScript テスト")

Debug.WriteLine(PWnd2)

PWnd3 = FindWindowExW(IntPtr.Zero, IntPtr.Zero, "Internet Explorer_TridentDlgFrame", "JavaScript テスト")

Debug.WriteLine(PWnd3)

    ・・・








[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90473 ] / 返信無し
■90475 / 11階層)  Re[11]: AddHandler Eventの別スレッド
□投稿者/ 魔界の仮面弁士 (2108回)-(2019/03/13(Wed) 16:03:49)
2019/03/13(Wed) 16:33:20 編集(投稿者)

No90473 (TanuTanu さん) に返信
> PWnd1 = FindWindowExW(IntPtr.Zero, IntPtr.Zero, vbNullString, "JavaScript テスト")・・・FindWindowExWに変更しました。

API 宣言はどうなっていますか?

それと IE11 が対象なら、タイトル部には
"JavaScript テスト - Internet Explorer"
などの文字列になるんじゃないかな…。


> VB.NETでクラス、タイトル、ハンドル列挙する方法が解らず
> このようなコードになってしまいました。

確認するだけなら、spyxx_amd64.exe / spyxx.exe を使うのが簡単です。
プログラムから列挙するなら EnumWindows API です。

ただ、ビギナーの段階で API を多用したコードを書く事はあまりお奨めしません。

InternetExplorer を対象に捉えるなら、API を使うのではなく、
CreateObject("Shell.Application").Windows 相当の処理を用いた方が手っ取り早いかと。

IE ではなく、その他のアプリ上で使われている WebBrowser 内のドキュメントを捕らえるなら、
No90411 の GetIEDocument のように WM_HTML_GETOBJECT + ObjectFromLresult が必要ですが。
[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90444 ] / ▼[ 90476 ]
■90474 / 3階層)  Re[3]: AddHandler Eventの別スレッドについて
□投稿者/ PANG2 (267回)-(2019/03/13(Wed) 16:01:02)
No90444 (TanuTanu さん) に返信

> ■実現したい事
>
> @ある画面のボタンを手動でクリック
> Aそのボタンのonclick イベント発生
> B上記ScriptによりWebページダイアログ表示 & MessageBox.Show("webDisp_onclick")作動

本当のやりたい事は何ですか?
Webページダイアログへの自動応答でしょうか?

Webページダイアログとは何でしょうか?
@confirm関数
Awindow.openによる別窓
BshowModalDialogによるモーダルダイアログ
Cjavascriptによる擬似モーダルダイアログ
が思いつきます。

@は、
javascript:function confirm() {return true;}
を流し込んでconfirm関数を無力化できます。

ABは
NewWindowイベントで拾えるかな。

Cは、
DOMで制御できるでしょう。
[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90474 ] / ▼[ 90477 ] ▼[ 90492 ]
■90476 / 4階層)  Re[4]: AddHandler Eventの別スレッドについて
□投稿者/ TanuTanu (12回)-(2019/03/13(Wed) 16:55:51)
PANG2 様

気に留めて頂きありがとうございます。
内容を整理し改めてPANG2様にご教授頂いた下記コードの方法で出来るか試しましたが、
VB.NETを触り始めて日が浅い事、小生の知識が乏しい故にVB.NETへの変換が出来ませんでした。
又、既に表示されたIEを制御しているのでGetIEDocumentを使用しておりますが、
webBrowser1の部分をどのように改造すれば良いのか、+= delegateの部位をどのように
改造すれば良いのかも解らず心苦しいばかりでございます。

ご質問の件ですがCのjavascriptによる擬似モーダルダイアログだと思います。
onclickイベント=自作onclickイベント+元のonclickイベントにする事が目的です。

何卒、ご教授賜りたく存じます。

string script = ((dynamic)button.DomElement).attributes("onclick").value; //onclickイベントのスクリプト
button.SetAttribute("onclick", "");//onclickイベントをクリア
button.Click += delegate {
MessageBox.Show("hello2");
webBrowser1.Navigate("javascript:" + script);//元のonclickイベントを実行
[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90476 ] / ▼[ 90511 ]
■90477 / 5階層)  Re[5]: AddHandler Eventの別スレッドについて
□投稿者/ TanuTanu (13回)-(2019/03/13(Wed) 20:27:51)
魔界の仮面弁士 様

大変お世話になっております。
ご教授頂いた方法で少し前進致しました。

FindWindowExWの値は0ですが、FindWindowではハンドル値取得できました。

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

PWnd1 = FindWindowExW(IntPtr.Zero, IntPtr.Zero, "TabThumbnailWindow", "JavaScript テスト - Internet Explorer")
PWnd2 = FindWindow("TabThumbnailWindow", "JavaScript テスト - Internet Explorer")

Debug.WriteLine(PWnd1)
Debug.WriteLine(PWnd2)

Dim o As Object = GetIEDocument(PWnd2) ' No90411 を参照
doc = DirectCast(o, mshtml.HTMLDocument)
yahooButton = DirectCast(doc.all.item("yahoo"), mshtml.IHTMLElement)
Event1 = DirectCast(yahooButton, mshtml.HTMLInputTextElementEvents2_Event)
AddHandler Event1.onclick, AddressOf WebDisp_click

End Sub

その結果、yahooButton = DirectCast(doc.all.item("yahoo"), mshtml.IHTMLElement)の行にて下記エラーが発生致しました。

 エラー:System.NullReferenceException
HResult=0x80004003
Message=オブジェクト参照がオブジェクト インスタンスに設定されていません。

******************************

 現在、取り組んでいる案件は、下記の通りです。
 
 WEBページ・・・CreateObject("Shell.Application").Windowsで対応しております。
  ↓
 上記WEBページから派生したWEBページダイアログ ・・・ GetIEDocument で対応(現在、ここのボタンクリックのイベントを対応しております。)
  ↓
 上記WEBページダイアログから派生したWEBページダイアログ ・・・ GetIEDocument で対応

何卒、ご教授の程、宜しくお願いいたします。

[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90477 ] / 返信無し
■90511 / 6階層)  Re[6]: AddHandler Eventの別スレッドについて
□投稿者/ 魔界の仮面弁士 (2113回)-(2019/03/15(Fri) 11:55:19)
2019/03/15(Fri) 12:07:39 編集(投稿者)

解決済みで閉じられているので、いちおうチェックは付けた状態に戻しておきます。


No90477 (TanuTanu さん) に返信
> その結果、yahooButton = DirectCast(doc.all.item("yahoo"), mshtml.IHTMLElement)の行にて下記エラーが発生致しました。

その行のどの部分に問題があるのかを確認してみてください。

NullReferenceException とは、インスタンスが空の時、すなわち
オブジェクトが Nothing である場合に、
そのメンバーを操作しようとして発生する例外ですよね。


If doc Is Nothing Then
 MsgBox("doc が空だった")
ElseIf doc.all Is Nothing Then
 MsgBox("doc.all が空だった")
ElseIf doc.all.item("yahoo") Is Nothing Then
 MsgBox("doc.all.item(""yahoo"") が空だった")
Else
 MsgBox("いずれも空ではなさそう")
 yahooButton = DirectCast(doc.all.item("yahoo"), mshtml.IHTMLElement)
End If




> FindWindowExWの値は0ですが、FindWindowではハンドル値取得できました。
> PWnd1 = FindWindowExW(IntPtr.Zero, IntPtr.Zero, "TabThumbnailWindow", "JavaScript テスト - Internet Explorer")

示されているのが結果だけで、要因となりうる情報が隠されたままなので、修正すべき箇所を指摘できないです。(^^;

あえてもう一度質問させていただきます。
『その API (FindWindowEx および FindWindowExW) の宣言部はどうなっていますか?』( No90475 の再掲 )


少なくとも当方では、下記の API 宣言で取得できています。

' Imports System.Runtime.InteropServices

' === 案1 ===
<DllImport("user32", CharSet:=CharSet.Unicode, SetLastError:=True)>
Private Shared Function FindWindowExW(hwndParent As IntPtr, hwndChildAfter As IntPtr, lpszClass As String, lpszWindow As String) As IntPtr
End Function

' === 案2 ===
<DllImport("user32", CharSet:=CharSet.Auto, SetLastError:=True)>
Private Shared Function FindWindowEx(hwndParent As IntPtr, hwndChildAfter As IntPtr, lpszClass As String, lpszWindow As String) As IntPtr
End Function

' === 案3 ===
Private Declare Unicode Function FindWindowExW Lib "user32" (hwndParent As IntPtr, hwndChildAfter As IntPtr, <MarshalAs(UnmanagedType.LPTStr)> lpszClass As String, <MarshalAs(UnmanagedType.LPTStr)> lpszWindow As String) As IntPtr

' === 案4 ===
Private Declare Auto Function FindWindowEx Lib "user32" (hwndParent As IntPtr, hwndChildAfter As IntPtr, <MarshalAs(UnmanagedType.LPTStr)> lpszClass As String, <MarshalAs(UnmanagedType.LPTStr)> lpszWindow As String) As IntPtr




宣言が間違っていて、IntPtr.Zero が返却されてしまうパターン。

' === 没1 ===
<DllImport("user32", EntryPoint:="FindWindowExW", SetLastError:=True)>
Private Shared Function FindWindowEx(hwndParent As IntPtr, hwndChildAfter As IntPtr, lpszClass As String, lpszWindow As String) As IntPtr
End Function

' === 没2 ===
<DllImport("user32", SetLastError:=True)>
Private Shared Function FindWindowExW(hwndParent As IntPtr, hwndChildAfter As IntPtr, lpszClass As String, lpszWindow As String) As IntPtr
End Function

' === 没3 ===
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExW" (hwndParent As IntPtr, hwndChildAfter As IntPtr, lpszClass As String, lpszWindow As String) As IntPtr



正しい宣言ではないが、一応呼び出せてしまうパターン。

' === 非推奨1 ===
Private Declare Unicode Function FindWindowExW Lib "user32" (hwndParent As IntPtr, hwndChildAfter As IntPtr, lpszClass As String, lpszWindow As String) As IntPtr

' === 非推奨2 ===
Private Declare Unicode Function FindWindowEx Lib "user32" Alias "FindWindowExW" (hwndParent As IntPtr, hwndChildAfter As IntPtr, lpszClass As String, lpszWindow As String) As IntPtr



>  WEBページ・・・CreateObject("Shell.Application").Windowsで対応しております。
これを用いている部分のコードも見せていただけないでしょうか。

SHDocVw.ShellWindows を宣言しておきながら、FindWindowEx API や、GetIEDocument までも
追加で呼び出している理由が、どうしても分からなかったのです。

No90463 の発言より、「objIE.LocationName」を利用しているであろうことは推察できましたが、
目的は LocationName プロパティでウィンドウのタイトルを得ることだけなのでしょうか。
あるいは HWND プロパティからウィンドウハンドルも得ているとか?

objIE.Document プロパティを通じて HTMLDocument を得ることができるはずなので、
わざわざ GetIEDocument を呼び出す必要性は無いと思っています。( No90469 で指摘 )

(例)
http://jumbofoot.cocolog-nifty.com/yass_vbnet_tips/2007/02/shellhtmldocume_f1cd.html


WM_HTML_GETOBJECT でないと取得できない相手の場合は、API 宣言が必要になりますが、
その場合、今度は CreateObject("Shell.Application").Window を使う意味が分からない…。



>  上記WEBページから派生したWEBページダイアログ ・・・ GetIEDocument で対応(現在、ここのボタンクリックのイベントを対応しております。)

ここでいう『派生』とは何を示していますか? ページ遷移の事でしょうか?

ページが遷移したのであれば、以前の HTMLDocument はもう使えないので、
読み込みが完了したことを通知するための DocumentComplete イベントにて、
イベント引数 pDisp の Document プロパティを受け取るようにします。
(フレームを持つページの場合は、各フレームごとに発生することに注意)

あるいは、ターゲットとなる InternetExplorer オブジェクト(IWebBrowser2)を保持しておいて、
その Document プロパティを取得しなおすという方法も使えますが、いずれにせよ、
読み込みが完了する前に GetIEDocument なり Document プロパティなりで
HTMLDocument を得ていた場合、DOM が不完全な状態になっていることがあります。

なので、取得した HTMLDocument が、目的のページの内容を指しているかを
確認しておくことも重要です。(これも No90469 で指摘 )


それに、FindWindowEx を使うにしても、その使い方が不自然に思えます。
そもそも "TabThumbnailWindow" クラスを探している理由は何でしょうか?
先の GetIEDocument を使うことが目的なら、探すべきウィンドウは
"Internet Explorer_Server" クラスのウィンドウ(またはその親ウィンドウ)の
ハンドルであるはずですよね。


また、「WEBページダイアログ」とは何を指していますか?
キャプションが "JavaScript テスト - Internet Explorer" となる、 No90454
https://www.javadrive.jp/javascript/event/sample2_1.html だとすれば、
そもそもダイアログは存在していません。
別のページが対象なのかもしれませんが、その場合は、doc.all.item("yahoo") は存在しないかもしれませんし。

No90476 では「javascriptによる擬似モーダルダイアログ『だと思う』」とお答えいただきましたが、
それが具体的になんであるのか(たとえば jQuery の colorbox とか)や、
イベント割り当てが onclick なのかそれ以外なのかもはっきりしないままです。
解決済み
[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90476 ] / ▼[ 90508 ]
■90492 / 5階層)  Re[5]: AddHandler Eventの別スレッドについて
□投稿者/ PANG2 (268回)-(2019/03/14(Thu) 18:59:01)
2019/03/14(Thu) 18:59:46 編集(投稿者)
No90476 (TanuTanu さん) に返信
> ご質問の件ですがCのjavascriptによる擬似モーダルダイアログだと思います。

jQueryの疑似ダイアログでしょうか?
ボタンのonclickもjQueryで実装しているなら難しいと思う。


WebBrowser上にダイアログが出現するのをtimerで監視するサンプル

private void timer1_Tick(object sender, EventArgs e)
{
	dynamic doc = webBrowser1.Document.DomDocument;
	dynamic titles = doc.getElementsByClassName("ui-dialog-title");
	foreach (dynamic title in titles) {
		if (title.innerText == "テストダイアログ1") {
			foreach (dynamic btn in title.parentnode.parentnode.getElementsByTagName("button")) {
				string s = btn.innerText;
				if (s.Contains("確認"))
					btn.click();
			}
		}
	}
}

[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90492 ] / ▼[ 90531 ]
■90508 / 6階層)  Re[6]: AddHandler Eventの別スレッドについて
□投稿者/ TanuTanu (14回)-(2019/03/15(Fri) 10:28:12)
魔界の仮面弁士 様
Azulean 様
PANG2 様

この度は、ご教授頂きありがとうございました。
小生の知識が乏しく、実現したい事が出来ませんでしたが
FOCUSOUTでの対応は出来るのでそちらで対応したいと思います。

今後、スキルを身につけた後、改めてトライしてみようと思います。

今回、ビギナーの私にとても親切にして頂いた事、感謝申し上げます。
ありがとうございました。
解決済み
[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90508 ] / ▼[ 90533 ]
■90531 / 7階層)  Re[7]: AddHandler Eventの別スレッドについて
□投稿者/ TanuTanu (15回)-(2019/03/18(Mon) 16:52:42)
!!

魔界の仮面弁士 様

このような未熟者にここまで親切にして頂いて何てお礼を申せばよいやら・・・
あれから何とかならないかと試行錯誤致しまして、TabThumbnailWindowではなくて
IEFRAMEを取得出来ました。
しかし、VBAではInternet Explorer_Serverまで辿り付いたのですが
VB.NETで子ウィンドウを列挙することが出来ません。
何卒、ご教授のほど宜しくお願いいたします。

又、■90511で教わった件は順次取り組んでまいります。


コードは下記の通りです。

Public Function EnumWindowCallBack(hWnd As IntPtr, lparam As IntPtr) As Boolean

Dim textLen As Integer = GetWindowTextLength(hWnd)
Dim tsb As New StringBuilder(textLen + 1)
Dim csb As New StringBuilder(256)

If 0 < textLen Then
GetWindowText(hWnd, tsb, tsb.Capacity)
GetClassName(hWnd, csb, csb.Capacity)

If tsb.ToString() = "JavaScript テスト - Internet Explorer" Then
If csb.ToString() = "IEFrame" Then
Debug.WriteLine(tsb.ToString())
Debug.WriteLine(csb.ToString())
Debug.WriteLine(hWnd)
hWnd_IEFRAME = hWnd

          EnumChildWindows(hWnd_IEFRAME, AddressOf EnumChildWindowsProc, IntPtr.Zero) ’IEFrame下のInternet Explorer_Serverを取得したいがここでエラーになります。

■エラー内容
BC31143 メソッド 'Public Function EnumChildWindowsProc(hWnd As IntPtr, lparam As IntPtr) As IntPtr' に、デリゲート 'Delegate Function API.EnumChildProc(hWnd As IntPtr, ByRef lParam As IntPtr) As Boolean' と互換性があるシグネチャがありません。


End If
End If

End If

Return True
End Function

Public Function EnumChildWindowsProc(hWnd As IntPtr, lparam As IntPtr) As Integer

Dim textLen As Integer = GetWindowTextLength(hWnd)
Dim tsb As New StringBuilder(textLen + 1)
Dim csb As New StringBuilder(256)

' クラス名取得
GetClassName(hWnd, csb, csb.Capacity)

Debug.WriteLine(csb.ToString())

' リターン
EnumChildWindowsProc = 1
End Function

<DllImport("user32")>
Function EnumChildWindows(
<[In]()> ByVal hWndParent As IntPtr,
<[In]()> ByVal lpEnumFunc As EnumChildProc,
<[In]()> ByRef lParam As IntPtr
) As Boolean
End Function


[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90531 ] / ▼[ 90543 ]
■90533 / 8階層)  Re[8]: AddHandler Eventの別スレッドについて
□投稿者/ 魔界の仮面弁士 (2115回)-(2019/03/18(Mon) 18:18:44)
No90531 (TanuTanu さん) に返信
> しかし、VBAではInternet Explorer_Serverまで辿り付いたのですが
> VB.NETで子ウィンドウを列挙することが出来ません。

VBA のコードを移植している、ということでしょうか。

それでは、VBA の API 宣言と VB2017 の API 宣言の
【両方】を見せてもらえますか?

提示をお願いする理由は、特に「ByVal」と「ByRef」の違いが重要だからです。


引数に ByVal も ByRef も書かなかった場合、
VBA では ByRef として解釈され、
.NET では ByVal として解釈される仕様であることにご注意ください。


> <DllImport("user32")>
> Function EnumChildWindows(
>  <[In]()> ByVal hWndParent As IntPtr,
>  <[In]()> ByVal lpEnumFunc As EnumChildProc,
>  <[In]()> ByRef lParam As IntPtr
>  ) As Boolean
> End Function


第4引数を ByRef IntPtr にしたのですね。
では、EnumChildProc の Delegate 宣言も見せてください。

AddressOf で指定した側が ByVal で、Delegate 定義が ByRef になっていて不整合を引き起こしていると思います。



' 参考資料1: https://dobon.net/vb/dotnet/process/enumwindows.html
 Public Delegate Function EnumWindowsDelegate(hWnd As IntPtr, lparam As IntPtr) As Boolean
 <DllImport("user32.dll")> _
 Public Function EnumWindows(lpEnumFunc As EnumWindowsDelegate, lparam As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
 End Function


' 参考資料2: https://smdn.jp/programming/tips/enumwindows/
 Private Delegate Function WNDENUMPROC(ByVal hWnd As IntPtr, ByVal lParam As IntPtr) As Boolean
 <DllImport("user32")> _
 Private Function EnumWindows(ByVal lpEnumFunc As WNDENUMPROC, ByVal lParam As IntPtr) As Boolean
 End Function


' 参考資料3: http://mt-soft.sakura.ne.jp/web_dl/vb-parts/enum_window/
 Private Delegate Function EnumerateWindowsCallback(ByVal hWnd As IntPtr, ByVal lParam As Integer) As Integer
 <DllImport("user32", EntryPoint:="EnumWindows")> _
 Private Shared Function EnumWindows(ByVal lpEnumFunc As EnumerateWindowsCallback, ByVal lParam As Integer) As Integer
 End Function


' 参考資料4: http://nonsoft.la.coocan.jp/SoftSample/VB.NET/SampleEnumWindows.html
 Private Delegate Function D_EnumWindowsProc(ByVal hWnd As Integer, ByVal lParam As Integer) As Integer
 Private Declare Function EnumWindows Lib "user32.dll" (ByVal lpEnumFunc As D_EnumWindowsProc, ByVal lParam As Integer) As Integer
[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90533 ] / ▼[ 90547 ]
■90543 / 9階層)  Re[9]: AddHandler Eventの別スレッドについて
□投稿者/ TanuTanu (16回)-(2019/03/19(Tue) 20:43:43)
魔界の仮面弁士 様

大変お世話になっております。
ご教授頂いたお蔭で■90455が当方でもようやく動作致しました。
ありがとうございます。明日、これを用いてWEBページダイアログのボタンイベントに取り掛かろうと思います。

ちなみに試行錯誤の結果、下記のようになりましたのでご報告致します。

'Option Strict On 'これオンすると遅延バインディング使用できませんと出る為、削除しました。

Public Class Form1

Dim o As Object
Dim aShell As SHDocVw.ShellWindows
Dim doc As mshtml.HTMLDocument
Dim yahooButton As mshtml.IHTMLElement
Dim Event1 As mshtml.HTMLInputTextElementEvents2_Event


Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click


EnumWindows(New EnumWindowsDelegate(AddressOf EnumWindowCallBack), IntPtr.Zero)

o = GetIEDocument(hWnd_IES) ' No90411 を参照

doc = DirectCast(o, mshtml.HTMLDocument)

Debug.WriteLine(doc.body.document.body.innerHTML)

yahooButton = DirectCast(doc.all.item("yahoo"), mshtml.IHTMLElement)

Event1 = DirectCast(DirectCast(doc.all.item("yahoo"), mshtml.IHTMLElement), mshtml.HTMLInputTextElementEvents2_Event)
AddHandler Event1.onclick, AddressOf WebDisp_click

End Sub

Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
yahooButton.click()
End Sub

Private Function WebDisp_click(ByVal e As mshtml.IHTMLEventObj) As Boolean
MsgBox("webDisp_onclick", MsgBoxStyle.SystemModal)
Return True
End Function


End Class

'***************************************************************************************

Imports System.Runtime.InteropServices
Imports System.Text

Module API

Public hWnd_IEFRAME As IntPtr
Public hWnd_IES As IntPtr


<DllImport("user32")>
Function GetClassName(
<[In]()> ByVal hWnd As IntPtr,
<Out()> ByVal lpClassName As StringBuilder,
<[In]()> ByVal nMaxCount As Integer
) As Integer
End Function

<DllImport("user32")>
Function EnumChildWindows(
<[In]()> ByVal hWndParent As IntPtr,
<[In]()> ByVal lpEnumFunc As EnumChildProc,
<[In]()> ByRef lParam As IntPtr
) As Boolean
End Function

<DllImport("user32")>
Function RegisterWindowMessage(
<[In]()> ByVal lpString As String
) As Integer
End Function

<DllImport("user32")>
Function SendMessageTimeout(
<[In]()> ByVal hWnd As IntPtr,
<[In]()> ByVal msg As Integer,
<[In]()> ByVal wParam As Integer,
<[In]()> ByVal lParam As Integer,
<[In]()> ByVal fuFlags As Integer,
<[In]()> ByVal uTimeout As Integer,
<Out()> ByRef lpdwResult As IntPtr
) As IntPtr
End Function

<DllImport("oleacc")>
Function ObjectFromLresult(
<[In]()> ByVal lResult As Int32,
<[In]()> ByRef riid As System.Guid,
<[In]()> ByVal wParam As Int32,
<Out(), MarshalAs(UnmanagedType.Interface)> ByRef ppvObject As Object
) As IntPtr
End Function

<DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Public Function GetWindowText(hWnd As IntPtr,
lpString As StringBuilder, nMaxCount As Integer) As Integer
End Function

<DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Public Function GetWindowTextLength(hWnd As IntPtr) As Integer
End Function

<DllImport("user32.dll")>
Public Function EnumWindows(lpEnumFunc As EnumWindowsDelegate,
ByVal lparam As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function

Delegate Function EnumWindowsDelegate(hWnd As IntPtr, ByVal lparam As IntPtr) As Boolean

Delegate Function EnumChildProc(hWnd As IntPtr, ByVal lParam As IntPtr) As Boolean

Public Function EnumWindowCallBack(hWnd As IntPtr, ByVal lparam As IntPtr) As Boolean

Dim textLen As Integer = GetWindowTextLength(hWnd)
Dim tsb As New StringBuilder(textLen + 1)
Dim csb As New StringBuilder(256)

If 0 <textLen Then
GetWindowText(hWnd, tsb, tsb.Capacity)
GetClassName(hWnd, csb, csb.Capacity)

If tsb.ToString() = "JavaScript テスト - Internet Explorer" Then
If csb.ToString() = "IEFrame" Then

hWnd_IEFRAME = hWnd

EnumChildWindows(hWnd_IEFRAME, AddressOf EnumChildWindowsProc, IntPtr.Zero)

End If
End If

End If

Return True
End Function

Public Function EnumChildWindowsProc(hWnd As IntPtr, lparam As IntPtr) As IntPtr

Dim textLen As Integer = GetWindowTextLength(hWnd)
Dim tsb As New StringBuilder(textLen + 1)
Dim csb As New StringBuilder(256)

GetClassName(hWnd, csb, csb.Capacity)

If csb.ToString() = "Internet Explorer_Server" Then

hWnd_IES = hWnd

End If

EnumChildWindowsProc = 1
End Function

'***********************************************************************

'IEオブジェクト取得メソッド

Function GetIEDocument(ByVal hWnd As IntPtr) As Object

Dim nMsg As Integer
Dim lRes As IntPtr
Dim IID_IHTMLDocument As System.Guid = New System.Guid("626FC520-A41E-11CF-A731-00A0C9082637")
Dim SMTO_ABORTIFHUNG As Integer = &H2
Dim spDoc As Object = Nothing

nMsg = RegisterWindowMessage("WM_HTML_GETOBJECT")

If nMsg <> 0 Then
SendMessageTimeout(hWnd, nMsg, 0, 0, SMTO_ABORTIFHUNG, 1000, lRes)
If Not lRes = IntPtr.Zero Then
ObjectFromLresult(lRes, IID_IHTMLDocument, 0, spDoc)
End If
End If

Return spDoc
End Function

End Module



[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90543 ] / ▼[ 90556 ]
■90547 / 10階層)  Re[10]: AddHandler Eventの別スレッドについて
□投稿者/ TanuTanu (17回)-(2019/03/20(Wed) 14:04:06)
魔界の仮面弁士 様

大変お世話になっております。
下記ご教授頂きたく存じます。
宜しくお願いいたします。


下記コードが「基になる RCW から分割された COM オブジェクトを使うことはできません。」のエラーになります。

Return CBool(CallByName(btn_Button_onclick, "[DispId=0]", CallType.Method, e)) 

Private Function WebDisp_click(ByVal e As mshtml.IHTMLEventObj) As Booleanの中では使えないのでしょうか?

https://elleneast.com/?p=2654に書いてますが、別スレッドだと難しいのでしょうか?

Private Sub DoSomething()の中にCallByName(btn_Button_onclick, "[DispId=0]", CallType.Method)を入れた時は
上記はエラーは出ませんが、勝手にクリックして次の画面が開いてしまいます。

※1 $(function(){のような記述はありませんでしたのでjQueryではないようです。
※2 onclickのところは右記のような記述でした。 <INPUT onclick=onClick***() ・・・>

VBコードは下記となります。(WIN APIは正常動作する為、省略)

Imports System.Runtime.InteropServices
Imports mshtml
Imports SHDocVw

Public Class Form1

Dim aShell As SHDocVw.ShellWindows
Dim objIE As Object

Dim WithEvents IE_1 As InternetExplorer

Dim IE_2 As HTMLDocument
Dim IE_2_2 As HTMLDocument
Dim IE_2_2_doc As mshtml.HTMLDocument
Dim btn_Button As mshtml.IHTMLElement
Dim btn_Button_onclick As Object

Dim Event1 As mshtml.HTMLInputTextElementEvents2_Event
Dim doc As mshtml.HTMLDocument
Dim frms2 As mshtml.FramesCollection


'最初の画面

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

aShell = CreateObject("Shell.Application").Windows

’For Each で回す
IE_1 = objIE
    ’next

End Sub

’最初の画面からWEBページダイアログ開くをキャッチ

Private Sub IE_1_DownloadComplete() Handles IE_1.DownloadComplete

Dim t As New System.Threading.Thread(New System.Threading.ThreadStart(AddressOf DoSomething))

t.SetApartmentState(System.Threading.ApartmentState.STA)

t.Start()

End Sub


Private Sub DoSomething()

System.Threading.Thread.Sleep(2000) 'WEBページダイアログ開くのを待つ

EnumWindows(New EnumWindowsDelegate(AddressOf EnumWindowCallBack), IntPtr.Zero)

IE_2 = GetIEDocument(hWnd_IES)

doc = DirectCast(IE_2, mshtml.HTMLDocument)

frms2 = CType(doc.frames.item(2), mshtml.FramesCollection)
IE_2_2 = CType(frms2.document, mshtml.HTMLDocument)

IE_2_2_doc = DirectCast(IE_2_2, mshtml.HTMLDocument)
btn_Button = DirectCast(IE_2_2_doc.all.item("btn"), mshtml.IHTMLElement)


btn_Button_onclick = btn_Button.onclick '元の function オブジェクト

btn_Button.onclick = DBNull.Value

Event1 = DirectCast(DirectCast(IE_2_2_doc.all.item("btn"), mshtml.IHTMLElement), mshtml.HTMLInputTextElementEvents2_Event)

AddHandler Event1.onclick, AddressOf WebDisp_click

End Sub


Private Function WebDisp_click(ByVal e As mshtml.IHTMLEventObj) As Boolean

MsgBox("webDisp_onclick", MsgBoxStyle.SystemModal)

Return CBool(CallByName(btn_Button_onclick, "[DispId=0]", CallType.Method, e)) '元の onclick 処理をここで呼び出す


End Function

End Class



[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90547 ] / ▼[ 90557 ] ▼[ 90558 ]
■90556 / 11階層)  Re[11]: AddHandler Eventの別スレッドについて
□投稿者/ TanuTanu (18回)-(2019/03/20(Wed) 23:14:04)
魔界の仮面弁士 様

大変お世話になっております。

invokeが気になったので調べてみたら2008年に魔界の仮面弁士 様が回答している件
がまさに私が悩んでる案件かも知れません。

http://hanatyan.sakura.ne.jp/patio/read.cgi?no=192

結果が出ましたらまたご連絡致します。

[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90556 ] / 返信無し
■90557 / 12階層)  Re[12]: AddHandler Eventの別スレッドについて
□投稿者/ PANG2 (272回)-(2019/03/21(Thu) 07:17:12)
2019/03/21(Thu) 07:37:35 編集(投稿者)

Private Sub IE_1_DownloadComplete() Handles IE_1.DownloadComplete
DoSomething()
End Sub

で、何が問題あるのでしょうか?

また、NewWindowイベントなら第一引数で別窓をつかめるはずです。
[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90556 ] / ▼[ 90583 ]
■90558 / 12階層)  Re[12]: AddHandler Eventの別スレッドについて
□投稿者/ 魔界の仮面弁士 (2118回)-(2019/03/21(Thu) 10:39:08)
No90556 (TanuTanu さん) に返信
> invokeが気になったので調べてみたら2008年に魔界の仮面弁士 様が回答している件
> がまさに私が悩んでる案件かも知れません。

そもそも何故、UI スレッドとワーカースレッドの間でのやり取りを必要としているのでしょうか。
わざわざスレッドを立ち上げずとも、イベントドリブンな非同期実装にするだけで良いと思うのですが。

もしもスレッドを分けるとしても、複数のスレッドでやりとりしようとせず、
取得から操作までを同一のスレッドで行うべきかと。



それと、IE 側から切断されたまま使おうとすると、COMException や InvalidComObjectException に
陥る可能性がありますので、ShellWindows を列挙した後、そのウィンドウが閉じられた場合に備えて、
OnQuit イベントを捕らえておくことをお奨めします。



No90557 (PANG2 さん) に返信
> NewWindowイベントなら第一引数で別窓をつかめるはずです。

COM 版の NewWindow イベント だとしたら、第一引数は URL のはず。
 ' DWebBrowserEvents::NewWindow
 ' void NewWindow(BSTR URL, long Flags, BSTR TargetFrameName, VARIANT* PostData, BSTR Headers, [in, out] VARIANT_BOOL* Processed);
 Sub NewWindow(URL As String, Flags As Integer, TargetFrameName As String, ByRef PostData As Object, Headers As String, ByRef Processed As Boolean)


使うとすれば、NewWindow2 イベントか
 ' DWebBrowserEvents2::NewWindow2
 ' void NewWindow2([in, out] IDispatch** ppDisp, [in, out] VARIANT_BOOL* Cancel);
 Sub NewWindow2(ByRef ppDisp As Object, ByRef Cancel As Boolean)


もしくは NewWindow3 イベントが良さそうです。
 ' DWebBrowserEvents2::NewWindow3
 ' void NewWindow3([in, out] IDispatch **ppDisp, [in, out] VARIANT_BOOL *Cancel, /* NWMF */ DWORD dwFlags, BSTR bstrUrlContext, BSTR bstrUrl);
 Sub NewWindow3(ByRef ppDisp As Object, ByRef Cancel As Boolean, dwFlags As UInteger, bstrUrlContext As String, bstrUrl As String)
[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90558 ] / ▼[ 90588 ] ▼[ 90589 ]
■90583 / 13階層)  Re[13]: AddHandler Eventの別スレッド
□投稿者/ TanuTanu (19回)-(2019/03/22(Fri) 12:36:15)
2019/03/22(Fri) 12:40:09 編集(投稿者)

魔界の仮面弁士 様
PANG2 様

お世話になっております。
恐れ入りますが、ご教授頂きたく存じます。

■90547の件 INVOKEを使いたいのですが小生の知識では上手く動作させる事が出来ませんでした;;
どのように記述すれば良いのでしょうか?

Private Function WebDisp_click(ByVal e As mshtml.IHTMLEventObj) As Boolean
MsgBox("webDisp_onclick", MsgBoxStyle.SystemModal)
Return CBool(Invoke(CallByName(btnYoinTehai_Button_onclick, "[DispId=0]", CallType.Method, e))) 
End Function

エラー内容
System.InvalidCastException
Message=型 'System.__ComObject' の COM オブジェクトをクラス型 'System.Delegate' にキャストできません。
COM コンポーネントを表す型のインターフェイスを COM コンポーネントを表さない型にキャストすることはできません。
ただし、基になる COM コンポーネントがインターフェイスの IID の QueryInterface 呼び出しをサポートする場合は、
インターフェイスにキャストすることができます。

■90558の件 スレッドを分ける理由について

ビギナーですので出来ればイベントドリブンな非同期実装や同一スレッドで組みたいのですが方法が解りません。

WEBページのボタンを手動クリック⇒DownloadCompleteを捕まえて重い処理させるとWEBページダイアログが重い処理終了しないと表示されない為、
DownloadCompleteで別スレッドにしようと考えました。


■90557の件 下記を試しましたが、GetIEDocument(hWnd_IES)にてハンドル取得出来ませんでした。

Private Sub IE_1_DownloadComplete() Handles IE_1.DownloadComplete
DoSomething()
End Sub

宜しくお願いいたします。





[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90583 ] / 返信無し
■90588 / 14階層)  Re[14]: AddHandler Eventの別スレッド
□投稿者/ PANG2 (274回)-(2019/03/22(Fri) 13:20:41)
No90583 (TanuTanu さん) に返信

> ■90558の件 スレッドを分ける理由について
>
> ビギナーですので出来ればイベントドリブンな非同期実装や同一スレッドで組みたいのですが方法が解りません。
>
> WEBページのボタンを手動クリック⇒DownloadCompleteを捕まえて重い処理させるとWEBページダイアログが重い処理終了しないと表示されない為、
> DownloadCompleteで別スレッドにしようと考えました。

DocumentCompletedを使うとか。
さらに問題があれば、Windows.Forms.Timer を使うとか。


[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90583 ] / ▼[ 90590 ]
■90589 / 14階層)  Re[14]: AddHandler Eventの別スレッド
□投稿者/ 魔界の仮面弁士 (2124回)-(2019/03/22(Fri) 15:03:37)
No90588 (PANG2 さん) に返信
> DocumentCompletedを使うとか。

DocumentComplete イベントですね。名前は似ていますが、
DocumentCompleted はマネージ版 WebBrowser のイベントです。


No90583 (TanuTanu さん) に返信
> ■90547の件 INVOKEを使いたいのですが小生の知識では上手く動作させる事が出来ませんでした;;
使う方法はありますが、そもそも今回の要件では、
無理にスレッドを分けるべきではないように思います。


> Message=型 'System.__ComObject' の COM オブジェクトをクラス型 'System.Delegate' にキャストできません。
Invoke の引数にはデリゲートインスタンスを渡す必要があります。ラムダ式でも良いですが。
手っ取り早いのは、そのメソッド自身を AddressOf で呼びなおすとか。
https://www.atmarkit.co.jp/ait/articles/0506/17/news111.html


> ■90558の件 スレッドを分ける理由について
> ビギナーですので出来ればイベントドリブンな非同期実装や同一スレッドで組みたいのですが方法が解りません。
ビギナーなら尚の事、イベント駆動型の開発スタイルで組むことをお奨めします。
現状の理解度でスレッドセーフな設計を組むのは難易度が高すぎるかと。


> WEBページのボタンを手動クリック⇒DownloadCompleteを捕まえて重い処理させるとWEBページダイアログが重い処理終了しないと表示されない為、
> DownloadCompleteで別スレッドにしようと考えました。

DownloadComplete は Document の取得とは無関係ですよね。
DocumentComplete では駄目でしょうか?
https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa752084%28v=vs.85%29#events

DocumentComplete では期待する結果が得られない場合(Refresh 時など)は、
PANG2 さんも指摘されていたように、Timer を併用することも検討してみてください。



> ■90557の件 下記を試しましたが、GetIEDocument(hWnd_IES)にてハンドル取得出来ませんでした。
取得できないというのは、具体的にはどういう状況でしょうか。

その処理を呼び出す前の、hWnd_IES を取得する処理に問題が生じているのか、
hWnd_IES は得ているが、それが指し示すウィンドウが失われている状態なのか、
SendMessageTimeout がタイムアウトしてゼロを返してくるのか、
SendMessageTimeout は成功しているけれど ObjectFromLresult が失敗しているのか、
ObjectFromLresult まで成功したけれど、想定外していたオブジェクトではないのか…。

あるいはそもそも、GetIEDocument を呼び出すところまで辿りつけていない状態なのか。


なお GetIEDocument では、hWnd_IES 配下に複数の "Internet Explorer_Server" が
存在していた場合を考慮した実装になっていないように見えます。最初に見つかったものが
目的のウィンドウであるかどうかを確認するための機構も用意されていないようですし。

ビギナーであるというのなら、無闇に API に頼ることはおすすめできません。

以前にも指摘していますが、New SHDocVw.ShellWindows() あるいは
CreateObject("Shell.Application").Windows を For Each して InternetExplorer を列挙し、
そのイベントやプロパティを通じて操作することをお奨めします。
[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90589 ] / ▼[ 90591 ]
■90590 / 15階層)  Re[15]: AddHandler Eventの別スレッド
□投稿者/ TanuTanu (20回)-(2019/03/22(Fri) 16:21:22)
魔界の仮面弁士 様
PANG2 様

大変お世話になっております。

■下記転記文

>無理にスレッドを分けるべきではないように思います。

>現状の理解度でスレッドセーフな設計を組むのは難易度が高すぎるかと。

>以前にも指摘していますが、New SHDocVw.ShellWindows() あるいは
>CreateObject("Shell.Application").Windows を For Each して InternetExplorer を列挙し、
>そのイベントやプロパティを通じて操作することをお奨めします。

>PANG2 さんも指摘されていたように、Timer を併用することも検討してみてください。

*****************************

上記、仰るとおりビギナーにはとても難易度高いです。この機能を実装するのはもう暫く先にしようと思います。

ただ今回、ご教授頂いた事で何とか下記まで辿り付く事が出来ました。
これを何とか動くようにする方法をお教え頂くことは出来ますでしょうか。
宜しくお願いいたします。


No90583 の件

Private Function WebDisp_click(ByVal e As mshtml.IHTMLEventObj) As Boolean

MsgBox("webDisp_onclick", MsgBoxStyle.SystemModal)

Return CBool(Invoke(New TESTAAADelegate(AddressOf TESTAAA)))

End Function

Delegate Function TESTAAADelegate() As Boolean

Sub TESTAAA(ByVal e As mshtml.IHTMLEventObj)
CallByName(btn_Button_onclick, "[DispId=0]", CallType.Method, e)
End Sub

エラー BC31143
メソッド 'Public Sub TESTAAA(e As IHTMLEventObj)' に、デリゲート 'Delegate Function Form1.TESTDelegate() As Boolean'
と互換性があるシグネチャがありません。

[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90590 ] / ▼[ 90592 ]
■90591 / 16階層)  Re[16]: AddHandler Eventの別スレッド
□投稿者/ 魔界の仮面弁士 (2125回)-(2019/03/22(Fri) 17:17:04)
No90590 (TanuTanu さん) に返信
> Delegate Function TESTAAADelegate() As Boolean
このデリゲートのシグネチャは、
 引数:0個
 戻り値:Boolean
となっています。


> Sub TESTAAA(ByVal e As mshtml.IHTMLEventObj)
一方、このメソッドのシグネチャは、
 引数:1個(IHTMLEventObj)
 戻り値:なし
ですよね。


そのため、
> New TESTAAADelegate(AddressOf TESTAAA)
と書かれた部分で、
> メソッド 'Public Sub TESTAAA(e As IHTMLEventObj)' に、デリゲート 'Delegate Function Form1.TESTDelegate() As Boolean'
> と互換性があるシグネチャがありません。
というエラーが生じているというわけです。


本来必要なのは WebDisp_click と同じシグネチャなので、
ひとまずコンパイルを通すだけで良いなら、たとえばこんな感じ。


' Func(Of mshtml.IHTMLEventObj, Boolean) デリゲートでも可
Private Delegate Function ExampleDelegate(ByVal e As mshtml.IHTMLEventObj) As Boolean

Private Function Example(ByVal e As mshtml.IHTMLEventObj) As Boolean
 Return CBool(CallByName(〜〜))
End Function

Private Function WebDisp_click(ByVal e As mshtml.IHTMLEventObj) As Boolean
 Return CBool(Invoke(New ExampleDelegate(AddressOf Example), e))
End Function


> これを何とか動くようにする方法をお教え頂くことは出来ますでしょうか。
このパターンでワーカースレッドを立てるのは、パフォーマンス面でも管理面でもデメリットになるかも。
[ 親 90434 / □ Tree ] 返信 編集キー/

▲[ 90591 ] / 返信無し
■90592 / 17階層)  Re[17]: AddHandler Eventの別スレッド
□投稿者/ TanuTanu (21回)-(2019/03/22(Fri) 20:17:57)
魔界の仮面弁士 様
PANG2 様

何とかコンパイル出来ましたが、Invoke、Delegateしても基になる RCW から分割された COM オブジェクトを使うことはできません。が出てしまいました;;

今回、大分引っ張ってしまいましたが素人が手を付ける案件では無い事を身をもって体験致しました。

このような素人に親切にして頂いた事、誠に感謝申し上げます。

この質問掲示板の益々の発展と皆様のご健勝を祈願致しましてお礼とさせて頂きます。
ありがとうございました。



解決済み
[ 親 90434 / □ Tree ] 返信 編集キー/


管理者用

- Child Tree -