如何防止嵌入式浏览器提示将下载的文件保存到何处



如何在用程序点击下载按钮后下载文件,因此不需要知道下载文件的url。

文件下载后,会出现一个提示,询问您是否要保存文件,按"是"后,另一个提示会询问您要将文件保存在哪里。因此,文件首先被下载,可能会被下载到某个缓冲区中,在最初下载后,会出现提示。

那么,一旦点击按钮,如何在不出现弹出提示的情况下捕获下载流并将其保存为文件?

(任何点击按钮的方法都可以,以下方法也可以。)

procedure TForm1.Button1Click(Sender: TObject);
var
x: integer;
ovLinks: OleVariant;
begin
WebBrowser1.Navigate('The web page');
//wait for page to down load
ovLinks := WebBrowser1.OleObject.Document.all.tags('A');
if ovLinks.Length > 0 then
begin
for x := 0 to ovLinks.Length-1 do
begin
if Pos('id of button', ovLinks.Item(x).id) > 0 then
//or if Pos('href of button', ovLinks.Item(x).href) > 0 then
begin
ovLinks.Item(x).click;
Break;
end;
end;
end;
end;

这个问题的原因是:文件的url并不总是可以找到的。例如:在这个网站上,我无法通过程序找到网址,但在按下导出按钮后,使用IE,文件被下载到"临时Internet文件"文件夹中。在IE的"临时Internet文件"文件夹中,它有一列"Internet地址",显示url。但在Chrome中却不存在这样的数据。但是,在这个网站上,我可以用程序找到url,但当我下载文件时,按"此处",文件不会出现在IE的"临时Internet文件"文件夹中。对于其他网站,url可以在文件夹中找到,并通过程序找到,但在其他网站,无论哪种方式都找不到url。

IDownloadManager接口及其Download方法实现到web浏览器控件中,您可以简单地控制所需内容。每当您要下载文件时(仅当弹出另存为对话框时),就会调用Download方法。

1.嵌入式Web浏览器

您可以使用Embedded Web Browser控件,该控件已经实现了此接口,并激发与TWebBrowser中相同命名事件不同的OnFileDownload。例如,请参阅this thread了解如何使用它。

2.自己动手

另一种选择是,您可以自己将其实现到TWebBrowser。在下面的例子中,我使用插入类只是为了展示原理,但将其包装为组件非常容易(这就是我发布OnBeforeFileDownload的原因)。

2.1.OnBeforeFileDownload事件

在这个插入类中,TWebBrowser的唯一扩展是OnBeforeFileDownload事件,当文件要下载时(在弹出另存为对话框之前,但不是OnFileDownload事件,而不是在下载文档本身时),它会触发。如果不为其编写事件处理程序,则web浏览器控件的行为将与以前一样(显示另存为对话框)。如果编写事件处理程序并向其Allowed声明的参数返回False,则文件保存将被取消。如果将True返回到Allowed参数(默认情况下为True),则将显示另存为对话框。请注意,如果您通过将Allowed设置为False来取消下载,则需要自己下载该文件(就像我在本例中使用Indy同步下载的那样)。为此,有一个FileSource常量参数,它包含下载的文件URL。以下是事件参数概述:

  • 发件人(TObject)-事件发件人
  • FileSource(WideString)-源文件URL
  • Allowed(Boolean)-声明的布尔参数,用于决定是否允许下载文件(默认值为True)

2.2.IDownloadManager实现

unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
StdCtrls, OleServer, OleCtrls, Dialogs, ActiveX, MSHTML, UrlMon, SHDocVw,
IdHTTP;
const
IID_IDownloadManager: TGUID = '{988934A4-064B-11D3-BB80-00104B35E7F9}';
SID_SDownloadManager: TGUID = '{988934A4-064B-11D3-BB80-00104B35E7F9}';
type
IDownloadManager = interface(IUnknown)
['{988934A4-064B-11D3-BB80-00104B35E7F9}']
function Download(pmk: IMoniker; pbc: IBindCtx; dwBindVerb: DWORD;
grfBINDF: DWORD; pBindInfo: PBindInfo; pszHeaders: PWideChar;
pszRedir: PWideChar; uiCP: UINT): HRESULT; stdcall;
end;
TBeforeFileDownloadEvent = procedure(Sender: TObject; const FileSource: WideString;
var Allowed: Boolean) of object;
TWebBrowser = class(SHDocVw.TWebBrowser, IServiceProvider, IDownloadManager)
private
FFileSource: WideString;
FOnBeforeFileDownload: TBeforeFileDownloadEvent;
function QueryService(const rsid, iid: TGUID; out Obj): HRESULT; stdcall;
function Download(pmk: IMoniker; pbc: IBindCtx; dwBindVerb: DWORD;
grfBINDF: DWORD; pBindInfo: PBindInfo; pszHeaders: PWideChar;
pszRedir: PWideChar; uiCP: UINT): HRESULT; stdcall;
protected
procedure InvokeEvent(ADispID: TDispID; var AParams: TDispParams); override;
published
property OnBeforeFileDownload: TBeforeFileDownloadEvent read FOnBeforeFileDownload write FOnBeforeFileDownload;
end;
type
TForm1 = class(TForm)
Button1: TButton;
WebBrowser1: TWebBrowser;
FileSourceLabel: TLabel;
FileSourceEdit: TEdit;
ShowDialogCheckBox: TCheckBox;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
procedure BeforeFileDownload(Sender: TObject; const FileSource: WideString;
var Allowed: Boolean);
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TWebBrowser }
function TWebBrowser.Download(pmk: IMoniker; pbc: IBindCtx; dwBindVerb,
grfBINDF: DWORD; pBindInfo: PBindInfo; pszHeaders, pszRedir: PWideChar;
uiCP: UINT): HRESULT;
var
Allowed: Boolean;
begin
Result := E_NOTIMPL;
if Assigned(FOnBeforeFileDownload) then
begin
Allowed := True;
if pszRedir <> '' then
FFileSource := pszRedir;
FOnBeforeFileDownload(Self, FFileSource, Allowed);
if not Allowed then
Result := S_OK;
end;
end;
procedure TWebBrowser.InvokeEvent(ADispID: TDispID; var AParams: TDispParams);
begin
inherited;
// DispID 250 is the BeforeNavigate2 dispinterface and to the FFileSource here
// is stored the URL parameter (for cases, when the IDownloadManager::Download
// won't redirect the URL and pass empty string to the pszRedir)
if ADispID = 250 then
FFileSource := OleVariant(AParams.rgvarg^[5]);
end;
function TWebBrowser.QueryService(const rsid, iid: TGUID; out Obj): HRESULT;
begin
Result := E_NOINTERFACE;
Pointer(Obj) := nil;
if Assigned(FOnBeforeFileDownload) and IsEqualCLSID(rsid, SID_SDownloadManager) and
IsEqualIID(iid, IID_IDownloadManager) then
begin
if Succeeded(QueryInterface(IID_IDownloadManager, Obj)) and
Assigned(Pointer(Obj))
then
Result := S_OK;
end;
end;
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
var
HTMLWindow: IHTMLWindow2;
HTMLDocument: IHTMLDocument2;
begin
WebBrowser1.Navigate('http://financials.morningstar.com/income-statement/is.html?t=AAPL&ops=clear');
while WebBrowser1.ReadyState <> READYSTATE_COMPLETE do
Application.ProcessMessages;
HTMLDocument := WebBrowser1.Document as IHTMLDocument2;
if not Assigned(HTMLDocument) then
Exit;
HTMLWindow := HTMLDocument.parentWindow;
if Assigned(HTMLWindow) then
try
HTMLWindow.execScript('SRT_stocFund.Export()', 'JavaScript');
except
on E: Exception do
ShowMessage(E.Message);
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
ReportMemoryLeaksOnShutdown := True;
WebBrowser1.OnBeforeFileDownload := BeforeFileDownload;
end;
procedure TForm1.BeforeFileDownload(Sender: TObject; const FileSource: WideString;
var Allowed: Boolean);
var
IdHTTP: TIdHTTP;
FileTarget: string;
FileStream: TMemoryStream;
begin
FileSourceEdit.Text := FileSource;
Allowed := ShowDialogCheckBox.Checked;
if not Allowed then
try
IdHTTP := TIdHTTP.Create(nil);
try
FileStream := TMemoryStream.Create;
try
IdHTTP.HandleRedirects := True;
IdHTTP.Get(FileSource, FileStream);
FileTarget := IdHTTP.URL.Document;
if FileTarget = '' then
FileTarget := 'File';
FileTarget := ExtractFilePath(ParamStr(0)) + FileTarget;
FileStream.SaveToFile(FileTarget);
finally
FileStream.Free;
end;
finally
IdHTTP.Free;
end;
ShowMessage('Downloading finished! File has been saved as:' + sLineBreak +
FileTarget);
except
on E: Exception do
ShowMessage(E.Message);
end;
end;
end.

2.3.IDownloadManager项目

您可以下载上面的代码(用Delphi 2009编写)作为一个完整的项目from here

我不知道这是否能让你达到你需要的目的,但它似乎很有希望。使用我这里的TWebBrowser(从"Microsoft Internet Controls 1.1版"导出),您可以使用OnBeforeNavigate2事件监视web浏览器处理的所有URL。你的问题是确定你需要做什么,捕获URL,然后自己处理。下面是一个简短的例子,我在你展示的第一个网站上玩了五分钟的控件。

procedure TForm1.WebBrowser1BeforeNavigate2(Sender: TObject;
pDisp: IDispatch; var URL, Flags, TargetFrameName, PostData,
Headers: OleVariant; var Cancel: WordBool);
begin
Edit1.Text := String(URL);
if Pos('CSV', Edit1.Text) > 0 then
Cancel := true;
end;

正如你所看到的,有很多parm,你必须找到文档来了解它们的含义。但在我的简短示例中,我所做的是将导航的URL放在Edit1.Text中(如果你真的想看看发生了什么,可能最好是TMemo)。举个例子,实际上没有什么可以表明它是一个直接下载的文件,但使用上面的代码,我可以取消浏览器的操作(显示下载提示等),然后在Edit1框中设置URL以进行操作。如果要进一步挖掘,我相信你可以查看有问题的标题,并确定网站是否打算向你发送一个你应该下载的文件,因为URL本身并没有说"CSV文件"(http://financials.morningstar.com/ajax/ReportProcess4CSV.html?t=AAPL&region=usa&culture=us_EN&reportType=is&周期=12&dataType=A&order=asc&columnYear=5&舍入=3&视图=原始&productCode=美国&r=809199&denominatorView=原始&number=3进入网络浏览器将下载有问题的CSV文件)。

希望这对你来说是个好的开始。

最新更新