IE7「ファイルのダウンロード」のクリック

解決


ランチャ  2009-01-06 12:59:37  No: 101447

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では動作しないらしいのですが
具体的な方法はないでしょうか。


熊谷隆史  2009-01-06 20:18:41  No: 101448

URLDownloadToFile APIとか、XMLHTTPとADODB.Streamとか
使うのが定番だと思いますけど。


YK  2009-01-06 20:26:25  No: 101449

こんにちは。
正当な回答は熊谷隆史にお任せするとして
とりあえずの答えは下記のようで出来ます。
関数、定数は調べて下さいね。

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  2009-01-06 20:32:32  No: 101450

失礼しました

>とりあえずの答えは下記のようで出来ます。
出来ませんでした。


熊谷隆史  2009-01-06 20:58:13  No: 101451

YKさん、
> 正当な回答は熊谷隆史にお任せするとして
呼び捨てはご勘弁ください。


YK  2009-01-06 22:13:25  No: 101452

熊谷隆史さん

大変失礼しました。


ランチャ  2009-01-07 03:26:19  No: 101453

YK様、熊谷様、レスありがとうございます。
YK様、こちらのソースでは反応しませんでした(フォーカスはセットされていますが、、)
熊谷様、
対象となるサイトは、ssl環境で、ログオンが必要です。
ログオンから、対象ページまでは、xmlHTTPで遷移しているのですが
そのままURLDownloadTOFile APIを使うことができるのでしょうか

少々用語が違うかもしれませんが、
xmlHTTPとURLDownloadFileは、同じセッション、クッキー遷移を使っているのでしょうか


熊谷隆史  2009-01-07 20:05:27  No: 101454

> 対象となるサイトは、ssl環境で、ログオンが必要です。
> ログオンから、対象ページまでは、xmlHTTPで遷移しているのですが
> そのままURLDownloadTOFile APIを使うことができるのでしょうか

> 少々用語が違うかもしれませんが、
> xmlHTTPとURLDownloadFileは、同じセッション、クッキー遷移を使っているのでしょうか

成程。出来れば冒頭でご説明されたなら、
こちらも先刻のコメントは無かったかも知れません。

それで、ボタンのハンドルが取れてるなら
BM_CLICKでも、WM_LBUTTONDOWN(YKさんが載せられている様に
VB6にMAKELPARAMマクロなんて便利なモノは存在しないので、自力でビット演算します)でも、
あるいはボタンの親に対して、WM_COMMANDでも送信すればいいかと。


K.J.K.  2009-01-07 22:31:29  No: 101455

UrlDownloadToFile で Secure なサイトからダウンロードする場合は、
第5引数に、IBindStatusCallback、IAuthenticate、IHttpNegotiate(2) などを
正しく Implements したオブジェクトを渡す必要があります。


らんちゃ  2009-01-08 03:45:31  No: 101456

お世話になります。
とりあえず、
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)
もだめでした。
お手数ですが、もう少しご指導をお願いします。


熊谷隆史  2009-01-08 19:23:30  No: 101457

> また、親ウィンドウに対してですが、保存ボタンにフォーカスがある状態で
> 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. さんのご提案されてる
真っ当な方法も、チャレンジされてはと思います。


ランチャ  2009-01-09 04:58:34  No: 101458

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様の方法は、今回の件が解決したらトライしようかと思っています。


熊谷隆史  2009-01-09 23:51:02  No: 101459

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


魔界の仮面弁士  2009-01-10 00:21:45  No: 101460

> 違いは、最初の[P]と[S] および [.......]ですが何か意味があるのでしょうか

SPY++ のヘルプに書いてある通り、
  P … PostMessage による、メッセージ キューへの「ポスト」。
  S … SendMessage による、メッセージの「送信」。
  s … S と同義だが、戻り値へのアクセスが禁止されていた場合。
  R … S に対するメッセージの戻り値。
であるかと。

S はメッセージ送信後、それが処理されるまで待機します。
P はメッセージを投げっぱなしにし、すぐに制御が返されます。

http://yokohama.cool.ne.jp/chokuto/advanced/sendmsg.html


熊谷隆史  2009-01-10 02:12:04  No: 101461

どうやらウィンドウが最前面でないと反応しない様です。
 (面倒な仕様です)

    hDlg = FindWindow("#32770", "ファイルのダウンロード - セキュリティの警告")
    If hDlg = 0 Then Exit Sub
    SetForegroundWindow hDlg
    Sleep 2000
    PostMessage hDlg, WM_COMMAND, 4427, 0


YK  2009-01-10 18:31:57  No: 101462

こんにちは。
熊谷隆史さんの
>どうやらウィンドウが最前面でないと反応しない様です。
を参考に保存して完了までを作ってみました。

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


熊谷隆史  2009-01-10 21:38:48  No: 101463

魔界の仮面弁士さん、フォロー頂きまして有難うございました。
YKさん、お疲れ様です。
K.J.K.さんの
> IHttpNegotiate(2) などを
IHttpNegotiate2のことなのでしょうけど。

IBindStatusCallbackの実装に付いては、チラホラある様ですが、
他のCOMインタフェースは、どうすればいいのやら。
かなりの茨の道ですね(私にはどうにも出来ない)。
http://technocraft.blog.so-net.ne.jp/2008-04-21


K.J.K.  2009-01-11 00:29:29  No: 101464

手抜き版ならば、昔作ってあります。
http://www.koalanet.ne.jp/~akiya/vbtaste/vbp/EasyDL3.lzh
但し、これだとIHttpNegotiate.OnResponseメソッドの戻り値を有効に
使っていません。そこも実情に合わせて適切な値を返すようにすべきでしょう。


K.J.K.  2009-01-11 00:31:04  No: 101465

# 追記。

かなり昔のサンプルが元になっているので、IHttpNegotiate であって
IHttpNegotiate2 は Implements していません。


ランチャ  2009-01-12 05:21:45  No: 101466

熊谷様,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様のソースはこれから勉強します。

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


熊谷隆史  2009-01-14 19:42:30  No: 101467

ランチャさん、
> 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


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加