IE7でダウンロードするファイルがあります。
手動では、「ファイルのダウンロード」ウィンドウ
->保存(&S)->「名前をつけて保存」->保存(&S)となりますが
これをプログラムにて自動化したいと考えています。
過去ログ、別サイトを見て大体の方法はわかったのですが、
どうしても「ファイルのダウンロード」ウィンドウの保存(&S)ボタンを押すことができません。
----以下「ファイルのダウンロード」ウィンドウが開いているとして
Const BM_CLICK = &HF5
Const WM_ACTIVATE = &H6
Dim strCaption As String
dim PWnd As Long, cWnd As Long
'親ウィンドウ取得
strCaption = "ファイルのダウンロード"
Pwnd = FindWindowEx(0, 0, vbNullString, strCaption)
'保存ボタンのハンドル
cWnd = FindWindowEx(pWnd, 0&, "Button", "保存(&S)")
'クリック
Call PostMessage(cWnd, WM_ACTIVATE, 1, 0)
Call PostMessage(cWnd, WM_BUTTON, 0, 0)
--------まで
保存ボタンにフォーカスがセットされるのですが、
どうも押しているように見えません。
念のためこの部分を手動で押して
次の「名前を付けて保存」では
strCaption = "名前を付けて保存"にして
以下同様で、保存ボタンを押すことができます。
どうやら、「ファイルのダウンロード」の保存ボタンは、
単純にWM_BUTTONでは動作しないらしいのですが
具体的な方法はないでしょうか。
URLDownloadToFile APIとか、XMLHTTPとADODB.Streamとか
使うのが定番だと思いますけど。
こんにちは。
正当な回答は熊谷隆史にお任せするとして
とりあえずの答えは下記のようで出来ます。
関数、定数は調べて下さいね。
lngR = PostMessage(PWnd, WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(cWnd), BN_CLICKED), ByVal cWnd)
Public Function MAKEWPARAM(LOWWORD As Long, HIWORD As Long) As Long
MAKEWPARAM = (LOWWORD And &HFFFF&) Or (HIWORD * &H10000)
End Function
失礼しました
>とりあえずの答えは下記のようで出来ます。
出来ませんでした。
YKさん、
> 正当な回答は熊谷隆史にお任せするとして
呼び捨てはご勘弁ください。
熊谷隆史さん
大変失礼しました。
YK様、熊谷様、レスありがとうございます。
YK様、こちらのソースでは反応しませんでした(フォーカスはセットされていますが、、)
熊谷様、
対象となるサイトは、ssl環境で、ログオンが必要です。
ログオンから、対象ページまでは、xmlHTTPで遷移しているのですが
そのままURLDownloadTOFile APIを使うことができるのでしょうか
少々用語が違うかもしれませんが、
xmlHTTPとURLDownloadFileは、同じセッション、クッキー遷移を使っているのでしょうか
> 対象となるサイトは、ssl環境で、ログオンが必要です。
> ログオンから、対象ページまでは、xmlHTTPで遷移しているのですが
> そのままURLDownloadTOFile APIを使うことができるのでしょうか
>
> 少々用語が違うかもしれませんが、
> xmlHTTPとURLDownloadFileは、同じセッション、クッキー遷移を使っているのでしょうか
成程。出来れば冒頭でご説明されたなら、
こちらも先刻のコメントは無かったかも知れません。
それで、ボタンのハンドルが取れてるなら
BM_CLICKでも、WM_LBUTTONDOWN(YKさんが載せられている様に
VB6にMAKELPARAMマクロなんて便利なモノは存在しないので、自力でビット演算します)でも、
あるいはボタンの親に対して、WM_COMMANDでも送信すればいいかと。
UrlDownloadToFile で Secure なサイトからダウンロードする場合は、
第5引数に、IBindStatusCallback、IAuthenticate、IHttpNegotiate(2) などを
正しく Implements したオブジェクトを渡す必要があります。
お世話になります。
とりあえず、
Call PostMessage(cWnd, WM_LBUTTONDOWN, 1, 0)
で、[保存(S)]ボタンが押されたような状態になり
Call PostMessage(cWnd, WM_LBUTTONUP, 1, 0)
で、[保存(S)]ボタンが浮き上がりましたが、ボタン効果はないです。
ビット演算は理解していますが、この場合、どのように使うのでしょうか。
また、親ウィンドウに対してですが、保存ボタンにフォーカスがある状態で
Call PostMessage(hWnd, WM_COMMAND, BM_CLICKED, 0)
Call PostMessage(hWnd, WM_COMMAND, BM_CLICKED, cwnd)
もだめでした。
お手数ですが、もう少しご指導をお願いします。
> また、親ウィンドウに対してですが、保存ボタンにフォーカスがある状態で
> Call PostMessage(hWnd, WM_COMMAND, BM_CLICKED, 0)
> Call PostMessage(hWnd, WM_COMMAND, BM_CLICKED, cwnd)
BM_CLICKEDは0なので、別に指定しなくともいいのですが、
肝心のボタンのコントロールIDは、どこへ行ったのでしょうか。
と言うより、YKさんがすでに載せられていますよね。
そちらをボタンの親に対して送信するだけだと思いますが。
それから、フォーカス云々は関係無いです。
> Call PostMessage(cWnd, WM_ACTIVATE, 1, 0)
> Call PostMessage(cWnd, WM_BUTTON, 0, 0)
なので、ランチャさんが載せられているこちらの部分も不要です。
また、WM_LBUTTONDOWNにするにしても、マジックナンバーにせずに
きちんと定数を宣言して使われた方が良いかと。
> Call PostMessage(cWnd, WM_LBUTTONDOWN, 1, 0)
LPARAMで、「y * &H10000 Or x」かなと。
> Call PostMessage(cWnd, WM_LBUTTONUP, 1, 0)
こちらは要りません。
それから、余裕があればK.J.K. さんのご提案されてる
真っ当な方法も、チャレンジされてはと思います。
YK様のソースは試してみましたが反応しませんでした。
spy++にて、「ファイルのダウンロード」の[保存(S)]ボタンを押したときの
挙動を見ると
hwnd S ...... WM_COMMAND xNotifyCode:BN_CLICKED wID:4427 hwndCtl:cwnd
だったのでプログラムではwparamを4427と直接指定し
Call PostMessage(hwnd, WM_COMMAND, 4427, cwnd)を実行したところ
spy++では
hwnd P WM_COMMAND wNotifyCode:BN_CLICKED wID:4427 hwndCtl:cwnd
でした
違いは、最初の[P]と[S] および [.......]ですが何か意味があるのでしょうか
K.j.K様の方法は、今回の件が解決したらトライしようかと思っています。
Vista/VBAの環境で確認しましたが、
セキュリティ上の制限を受けているのでしょうね。
別プルセスから送信しているから、ダメなのかも知れませんが。
(BM_CLICK、WM_COMMAND、WM_LBUTTONDOWNなど軒並み無理。
IAccessibleを実装しているにも関わらず、accDoDefaultActionでもクリック出来ない)
AppActivate "ファイルのダウンロード - セキュリティの警告"
Application.Wait Now + TimeSerial(0, 0, 2)
PostMessage hButton, WM_SYSCHAR, Asc("s"), 0
> 違いは、最初の[P]と[S] および [.......]ですが何か意味があるのでしょうか
SPY++ のヘルプに書いてある通り、
P … PostMessage による、メッセージ キューへの「ポスト」。
S … SendMessage による、メッセージの「送信」。
s … S と同義だが、戻り値へのアクセスが禁止されていた場合。
R … S に対するメッセージの戻り値。
であるかと。
S はメッセージ送信後、それが処理されるまで待機します。
P はメッセージを投げっぱなしにし、すぐに制御が返されます。
http://yokohama.cool.ne.jp/chokuto/advanced/sendmsg.html
どうやらウィンドウが最前面でないと反応しない様です。
(面倒な仕様です)
hDlg = FindWindow("#32770", "ファイルのダウンロード - セキュリティの警告")
If hDlg = 0 Then Exit Sub
SetForegroundWindow hDlg
Sleep 2000
PostMessage hDlg, WM_COMMAND, 4427, 0
こんにちは。
熊谷隆史さんの
>どうやらウィンドウが最前面でないと反応しない様です。
を参考に保存して完了までを作ってみました。
Sub FileDownLoad_Proc()
Dim strCaption As String
Dim PWnd As Long
Dim cWnd As Long
Dim hDlg1 As Long
Dim hDlg2 As Long
Dim lngR As Long
Dim hWnd1 As Long
Dim hWnd2 As Long
Dim hWnd3 As Long
Dim strBuf As String
Dim strA As String
Dim nLen As String
' 親ウィンドウ取得
strCaption = "ファイルのダウンロード"
PWnd = FindWindowEx(0, 0, "#32770", strCaption)
If PWnd = 0 Then Exit Sub
' 保存ボタンのハンドル
cWnd = FindWindowEx(PWnd, 0&, "Button", "保存(&S)")
' '保存ボタンを押す
Do
' WindowTopMost PWnd, 0
SetForegroundWindow PWnd
Sleep 500
lngR = SendNotifyMessage(PWnd, WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(cWnd), BN_CLICKED), ByVal cWnd)
If lngR = 0 Then Exit Do
Loop
Do
Sleep 1
hDlg1 = FindWindow("#32770", "名前を付けて保存")
If hDlg1 Then Exit Do
Loop
hWnd1 = GetDlgItem(hDlg1, 1148) 'ファイル名
If hWnd1 = 0 Then Exit Sub
hWnd2 = GetDlgItem(hDlg1, 1) '保存(&S)
If hWnd2 = 0 Then Exit Sub
nLen = SendMessage(hWnd1, WM_GETTEXTLENGTH, 0, ByVal 0&) + 1
strBuf = String$(nLen, 0)
lngR = SendMessage(hWnd1, WM_GETTEXT, nLen, ByVal strBuf)
strBuf = Left$(strBuf, InStr(strBuf, vbNullChar) - 1)
strA = "D:\" & strBuf 'Full Path 指定
lngR = SendMessage(hWnd1, WM_SETTEXT, 0, ByVal strA)
lngR = PostMessage(hDlg1, WM_COMMAND, MAKEWPARAM(1, BN_CLICKED), ByVal hWnd2)
Do
Sleep 1
hDlg2 = FindWindow("#32770", "ダウンロードの完了")
If hDlg2 Then Exit Do
Loop
hWnd3 = GetDlgItem(hDlg2, 2)
If hWnd3 = 0 Then Exit Sub
lngR = PostMessage(hDlg2, WM_COMMAND, MAKEWPARAM(2, BN_CLICKED), ByVal hWnd3)
End Sub
魔界の仮面弁士さん、フォロー頂きまして有難うございました。
YKさん、お疲れ様です。
K.J.K.さんの
> IHttpNegotiate(2) などを
IHttpNegotiate2のことなのでしょうけど。
IBindStatusCallbackの実装に付いては、チラホラある様ですが、
他のCOMインタフェースは、どうすればいいのやら。
かなりの茨の道ですね(私にはどうにも出来ない)。
http://technocraft.blog.so-net.ne.jp/2008-04-21
手抜き版ならば、昔作ってあります。
http://www.koalanet.ne.jp/~akiya/vbtaste/vbp/EasyDL3.lzh
但し、これだとIHttpNegotiate.OnResponseメソッドの戻り値を有効に
使っていません。そこも実情に合わせて適切な値を返すようにすべきでしょう。
# 追記。
かなり昔のサンプルが元になっているので、IHttpNegotiate であって
IHttpNegotiate2 は Implements していません。
熊谷様,K.J.J様,仮面弁士様、お世話になりました。
無事、ダウンロードができました。
こちらの誤解かも知れませんが、
vistaでは
' hWnd1 = GetDlgItem(hDlg1, 1148) 'ファイル名
ではhWnd1が取得できないようです。
xpは"edit"コントロールIDが1148ですが
vistaでは1001となっているので
' hWnd1 = GetDlgItem(hDlg1, 1001) 'ファイル名
でもダメでした
とりあえず
'ファイル名入力欄のハンドル取得
hWnd1 = FindWindowEx(hDlg1, 0&, "DUIViewWndClassName", vbNullString)
If hWnd1 > 0 Then 'DUI..が取得できた場合(Vista)
hWnd1 = FindWindowEx(hWnd1, 0&, "DirectUIHWND", vbNullString)
hWnd1 = FindWindowEx(hWnd1, 0&, "FloatNotifySink", vbNullString)
Else 'Xpの場合
hWnd1 = FindWindowEx(hDlg1, 0&, "ComboBoxEx32", vbNullString)
End If
'ComboBoxから共通
hWnd1 = FindWindowEx(hWnd1, 0&, "ComboBox", vbNullString)
hWnd1 = FindWindowEx(hWnd1, 0&, "edit", vbNullString)
としました。
K.J.K様のソースはこれから勉強します。
本当にありがとうございました。
ランチャさん、
> K.J.J様,
YKさんとK.J.K. さんのお名前が、ごっちゃになっている様な。
それから、APIでウィンドウ操作するなら、EnumChildWindowsを使った方がいい気も。
> vistaでは1001となっているので
> ' hWnd1 = GetDlgItem(hDlg1, 1001) 'ファイル名
> でもダメでした
'ファイル名入力欄のハンドル取得
hWnd1 = FindWindowEx(hDlg1, 0&, "DUIViewWndClassName", vbNullString)
--- 中略 ---
hWnd1 = FindWindowEx(hWnd1, 0&, "FloatNotifySink", vbNullString)
hWnd1 = GetDlgItem(hWnd1, 1001) 'ファイル名
としないと。
また、K.J.K. さんが
> 但し、これだとIHttpNegotiate.OnResponseメソッドの戻り値を有効に
> 使っていません。そこも実情に合わせて適切な値を返すようにすべきでしょう。
と書かれてましたが、そのままでも問題無く、こちらのVista/VBA環境で動作しました。
# K.J.K. さん、有難うございました。
With New FileDownloader
.hWndOwner = Application.Hwnd
.URL = "https://mail.google.com/mail/help/images/logo.gif"
.FileName = "C:\Temp\logo.gif"
.UserName = ""
.Password = ""
.Download
End With
ツイート | ![]() |