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

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

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

AddHandler Eventの別スレッドについて [1]

[トピック内 36 記事 (21 - 36 表示)]  << 0 | 1 >>

■90492 / inTopicNo.21)  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();
			}
		}
	}
}

引用返信 編集キー/
■90508 / inTopicNo.22)  Re[6]: AddHandler Eventの別スレッドについて
□投稿者/ TanuTanu (14回)-(2019/03/15(Fri) 10:28:12)
魔界の仮面弁士 様
Azulean 様
PANG2 様

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

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

今回、ビギナーの私にとても親切にして頂いた事、感謝申し上げます。
ありがとうございました。
解決済み
引用返信 編集キー/
■90511 / inTopicNo.23)  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 なのかそれ以外なのかもはっきりしないままです。
解決済み
引用返信 編集キー/
■90531 / inTopicNo.24)  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


引用返信 編集キー/
■90533 / inTopicNo.25)  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
引用返信 編集キー/
■90543 / inTopicNo.26)  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



引用返信 編集キー/
■90547 / inTopicNo.27)  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



引用返信 編集キー/
■90556 / inTopicNo.28)  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

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

引用返信 編集キー/
■90557 / inTopicNo.29)  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イベントなら第一引数で別窓をつかめるはずです。
引用返信 編集キー/
■90558 / inTopicNo.30)  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)
引用返信 編集キー/
■90583 / inTopicNo.31)  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

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





引用返信 編集キー/
■90588 / inTopicNo.32)  Re[14]: AddHandler Eventの別スレッド
□投稿者/ PANG2 (274回)-(2019/03/22(Fri) 13:20:41)
No90583 (TanuTanu さん) に返信

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

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


引用返信 編集キー/
■90589 / inTopicNo.33)  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 を列挙し、
そのイベントやプロパティを通じて操作することをお奨めします。
引用返信 編集キー/
■90590 / inTopicNo.34)  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'
と互換性があるシグネチャがありません。

引用返信 編集キー/
■90591 / inTopicNo.35)  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


> これを何とか動くようにする方法をお教え頂くことは出来ますでしょうか。
このパターンでワーカースレッドを立てるのは、パフォーマンス面でも管理面でもデメリットになるかも。
引用返信 編集キー/
■90592 / inTopicNo.36)  Re[17]: AddHandler Eventの別スレッド
□投稿者/ TanuTanu (21回)-(2019/03/22(Fri) 20:17:57)
魔界の仮面弁士 様
PANG2 様

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

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

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

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



解決済み
引用返信 編集キー/

このトピックをツリーで一括表示

<前の20件
トピック内ページ移動 / << 0 | 1 >>

このトピックに書きこむ