VBAからダウンロードボタンをクリックするということは、VBAを実行するコンテキストからIE内のコンテンツのボタンイベントを呼び出すということと等価です。
要するに、VBA内からMsgBoxで表示したダイアログに対して、自分自身でボタンを押せないのと同じことです。VBAではマルチスレッド動作は出来ませんから、どうしようもありません。
VBAでマルチスレッドは不可能ですが、擬似的にIE側でタイマを使ったスレッドもどきを起こすことで回避は可能です。
例えば、objIEがIEオブジェクトだとして、
objIE.document.getElementById("test_button").Click
というコードは、IE側のクリック処理(の先のwindow.alertなど)が処理されない限り、呼び出し元のVBAに制御が戻ってきません。
タイマを使って回避するには、
objIE.document.parentWindow.execScript "window.setTimeout(""document.getElementById('test_button').click();"",10);"
などのようにします。このコードは、10ミリ秒後に「document.getElementById('test_button').click();」を実行するようIE側に設定したあと、すぐVBAに制御が戻ってきます。10ミリ秒後にVBA側は何もしなくてもIE側が自動的にクリック処理を起動してくれるので、VBA側はその後の処理(window.alertの処理など)を継続することが出来ます。
URLはダミー
こんにちは。
・最近フットワークの軽くない 腰高ディフェンダーみたい( http://www.ken3.org/vba/backno/vba170.html )
・言い訳ばかり(できない予防線貼りまくり http://www.ken3.org/guchi/backno/guchi188.html )
の三流プログラマー ken3memoです
なんて挨拶は、おいといて、
動作しない原因
javascript prompt alert で VBAに処理が返らない(帰ってこない)
(自分でもテストしてみました
VBA IE操作 javascript の prompt alert で処理が止まってしまうダメパターン を 紹介する http://d.hatena.ne.jp/ken3memo/20100428/1272442497 )
解決案
javascript prompt alert で VBAに処理が返らないなら、prompt alertをつぶしたいので、一つの実験をしてみました。
実験内容は、単純に同じ名前の関数が存在したらどちらが優先されるか?
なんて、三流だから考えつく発想でテストしてみました。(一流のプログラマーは関数名が一致するなんてミスしたことないよね、私はだいぶまえにあったり)
javascriptの実験 同じ名前の関数 promptとalertを作るとどちらが有効か?※標準関数をつぶす実験
↑で、同じ名前だと 自分で作ったニセモノの方が優先されるみたいなので、
あとは応用するために、HTMLの文章を読み込んだあとにニセのprompt alertを挿入する方法を探ってみます。
VBA IE操作 ニセのpromptとalert() を 挿入する そんな実験
動的に JavaScriptを読み込む
http://zombiebook.seesaa.net/article/22810383.html
■ 外部スクリプトではなく生成したコードを突っ込む場合
var ele = document.createElement("script");
ele.type = "text/javascript";
ele.text = "突っ込むコード";
document.body.appendChild(ele);
を参考にして、
VBAから読み込んだページに
ニセのpromptとalert()をぶち込んでみます。
ページ読み込み後に、
'04/28 ページが読み込まれたので、ニセのjavascriptを挿入、毒を喰わせる? '>動的に JavaScriptを読み込む http://zombiebook.seesaa.net/article/22810383.html を参考にしました Dim ele As Object 'エレメント(script)を1つ作りたいので。 Set ele = objIE.document.createElement("SCRIPT") ele.Type = "text/javascript" Dim strJCODE As String '挿入するコード(文字列) strJCODE = "function prompt() { return ('123固定で返したい文字');}" strJCODE = strJCODE & vbCrLf & "function alert() { return ;}" ele.Text = strJCODE 'コードをセットする Call objIE.document.body.appendChild(ele) '上↑で作った要素・エレメントをドキュメントに挿入する '↑ここまでで、ニセjavascriptの関数作成終了、あとはいつものように処理すると
↑みたいな感じで、ニセのjavascriptを組み込む(毒を喰わせられるので)
これを応用すれば、
javascript prompt alert で VBAに処理が返らない(帰ってみない)
を回避できるのでは?
strJCODE = "function prompt() { return ('123固定で返したい文字');}"
ここの固定文字を入力したいコメントにすれば、目的の動作になると思います。
テストページと無駄に迷っているテスト動画は
http://www.youtube.com/watch?v=k6XIeMITqDg
VBA IE操作 ニセのpromptとalert() を 挿入する そんな実験
を見て笑ってください。
読み込み確認後とボタンを押す前に入れれば動くと思います。
ソース全体
Option Explicit Sub ie_Test_Button() 'ボタンを押した先で javascript の prompt/alert が 走ったら、止まる... Dim objIE As Object 'IEオブジェクト参照用 'IEを起動する Set objIE = CreateObject("InternetExplorer.application") 'IEのオブジェクトを作る objIE.Visible = True '見えるようにする(お約束) '.Navigate で 指定したURLを開く Dim strURL As String 'テストのHTML置き場 strURL = "http://ken3-info.blog.ocn.ne.jp/objie/2010/04/0428_javascript.html" 'テストページ objIE.Navigate strURL 'テストページを開く '↓デバック用で少し待つ(※これは通常いらないです) Application.Wait Time:=Now + TimeValue("00:00:02") '画面遷移がはやいので2秒間止める 'ページが表示される 完了を待つ While objIE.ReadyState <> 4 Or objIE.Busy = True 'READYSTATE_COMPLETE = 4 DoEvents '特に何もしないで.Busyの状態が変わるまで待つ Wend '04/28 ページが読み込まれたので、ニセのjavascriptを挿入、毒を喰わせる? '>動的に JavaScriptを読み込む http://zombiebook.seesaa.net/article/22810383.html を参考にしました Dim ele As Object 'エレメント(script)を1つ作りたいので。 Set ele = objIE.document.createElement("SCRIPT") ele.Type = "text/javascript" Dim strJCODE As String '挿入するコード(文字列) strJCODE = "function prompt() { return ('123固定で返したい文字');}" strJCODE = strJCODE & vbCrLf & "function alert() { return ;}" ele.Text = strJCODE 'コードをセットする Call objIE.document.body.appendChild(ele) '上↑で作った要素・エレメントをドキュメントに挿入する '↑ここまでで、ニセjavascriptの関数作成終了、あとはいつものように処理すると '↓デバック用で少し待つ(※これは通常いらないです) Application.Wait Time:=Now + TimeValue("00:00:02") '画面遷移がはやいので2秒間止める 'htmlドキュメント allのから .tagsでButtonタグを抜き '.InnerTEXT値(ボタンの名称) が VBA解説 の オブジェクト を クリック(.Click)する Dim objButton As Object 'Buttonタグ格納用 For Each objButton In objIE.document.all.tags("Button") 'Buttonのタグを.allから抜く If objButton.InnerTEXT = "ダウンロード" Then '.InnerTEXT値(ボタンの名称) で判断する objButton.Click '見つけたButtonオブジェクト(ボタン)を.Clickクリックする Exit For '用が済んだので(見つかったので)ループを抜ける End If Next '↑上でボタンが見つからなかった時のエラー処理が入っていない手抜きだけど、ご勘弁を Debug.Print Now & "に処理終了" End Sub
かなり 三流な逃げ手 ですが、応用して使えたらいいなぁと思いつつ、失礼します。
VBAからダウンロードボタンをクリックするということは、VBAを実行するコンテキストからIE内のコンテンツのボタンイベントを呼び出すということと等価です。
要するに、VBA内からMsgBoxで表示したダイアログに対して、自分自身でボタンを押せないのと同じことです。VBAではマルチスレッド動作は出来ませんから、どうしようもありません。
VBAでマルチスレッドは不可能ですが、擬似的にIE側でタイマを使ったスレッドもどきを起こすことで回避は可能です。
例えば、objIEがIEオブジェクトだとして、
objIE.document.getElementById("test_button").Click
というコードは、IE側のクリック処理(の先のwindow.alertなど)が処理されない限り、呼び出し元のVBAに制御が戻ってきません。
タイマを使って回避するには、
objIE.document.parentWindow.execScript "window.setTimeout(""document.getElementById('test_button').click();"",10);"
などのようにします。このコードは、10ミリ秒後に「document.getElementById('test_button').click();」を実行するようIE側に設定したあと、すぐVBAに制御が戻ってきます。10ミリ秒後にVBA側は何もしなくてもIE側が自動的にクリック処理を起動してくれるので、VBA側はその後の処理(window.alertの処理など)を継続することが出来ます。
URLはダミー
コメント(1件)
http://d.hatena.ne.jp/ken3memo/20100428/1272442497
確かに、
javascript の prompt alert で処理が止まって戻ってきませんね。
あまり関係ないのですが、起動のボタンって
<button onclick="submitF3('DDDD')">ダウンロード</button>
とか?
それとも
submit の ボタンに割り当ててあるのかなぁ?
submitF3のソースの中で、ダウンロード処理にどうやって飛ばしているのかわからなかったんで。
最後、コマンドを作っている? command += "#" + comment;
と openerForm.target="_parent"; の 開き方を変えているだけかなぁと思って。
あっ、あまり今回の問題(VBAに処理が戻らない)と関係ないので、スルーしてください。
何か うまい 逃げ手 でも、考えたらまた書き込みます。
(その前に、識者からの回答が付くことを願いつつ、失礼します。)