【问题标题】:Silently block cookies warning with IHTMLDocument2 in Delphi在 Delphi 中使用 IHTMLDocument2 静默阻止 cookie 警告
【发布时间】:2014-08-29 15:09:37
【问题描述】:

我正在使用 IHTMLDocument2 来抓取一组网站。我正在创建 IHTMLDocument2 实例,如下所示:

    var
      myDownload : TDownLoadURL;
      doc: OleVariant;
    (...)
      myDownload:= TDownLoadURL.Create(nil);
      with myDownload do
      begin
        URL:=myURL;
        Filename:= GetTempDirectory+'temp_download_url_complete2.txt';
        ExecuteTarget(nil);
      end;
(...)
      doc := coHTMLDocument.Create as IHTMLDocument2;
      doc.write(html);
      doc.close;
(...)

有一个特定的网站会弹出一条消息:

允许本网站为您提供个性化的信息, 你会允许它在你的电脑上放一个小文件(称为cookie)吗 电脑?

我已更改操作系统 (Windows 2008 SE) Internet 选项以在不提示的情况下阻止 cookie,但消息不断出现。如何在静默模式下创建 IHTMLDocument2?

【问题讨论】:

  • 你设置了静音标志对吗?
  • TDownloadURL 没有静默属性,对吧?
  • 我猜要么使用隐藏的 TWebBrowser,要么使用 IOleClientSite 和 SetClientSite。
  • @David 是对的。如果您想在没有 TWebBrowser 的情况下使用 IHTMLDocument2,则需要实现 IOleClientSite;IPropertyNotifySink;IDispatch。我建议你看看EmbeddedWB 来源。特别是IEParser.pasUI_Less.pas。您可能要考虑直接使用这些组件。它完全满足您的需求。

标签: delphi cookies delphi-xe


【解决方案1】:

如果您需要禁止 IHTMLDocument 用户界面或用户通知,您需要同时实现 IOleClientSite 和定义为 DISPID_AMBIENT_DLCONTROL 的环境属性。
来自文档"Download Control"

主机可以控制下载的某些方面——帧、图像、Java、 等等——通过实现 IOleClientSite 和环境属性 定义为 DISPID_AMBIENT_DLCONTROL。当主机的 IDispatch::Invoke 在 dispidMember 设置为 DISPID_AMBIENT_DLCONTROL 的情况下调用方法,它 应将零或以下值的组合放入 pvarResult。

在这种情况下,您需要的标志是 DLCTL_SILENT(也可能是 DLCTL_NO_SCRIPTS)。

如前所述,如果您希望从文档中获取事件通知(比如DISPID_READYSTATE)。

查看EmbeddedWB 来源,了解它是如何实现的。特别是IEParser.pasUI_Less.pas。它已经完全满足您的需求。


这是一个基于UI_Less的简化演示(未实现IPropertyNotifySink):

uses ..., ActiveX, MSHTML;

const
  DISPID_AMBIENT_DLCONTROL = (-5512);

type
  TUILess = class(TComponent, IUnknown, IDispatch, IOleClientSite)
    protected
    // IDispatch
    function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
      Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HRESULT; stdcall;
    // IOleClientSite
    function SaveObject: HRESULT; stdcall;
    function GetMoniker(dwAssign: Longint; dwWhichMoniker: Longint;
      out mk: IMoniker): HRESULT; stdcall;
    function GetContainer(out container: IOleContainer): HRESULT; stdcall;
    function ShowObject: HRESULT; stdcall;
    function OnShowWindow(fShow: BOOL): HRESULT; stdcall;
    function RequestNewObjectLayout: HRESULT; stdcall;
  end;

implementation

function TUILess.Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
  Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HRESULT;
const
  DLCTL_NO_SCRIPTS = $00000080;
  DLCTL_NO_JAVA = $00000100;
  DLCTL_NO_RUNACTIVEXCTLS = $00000200;
  DLCTL_NO_DLACTIVEXCTLS = $00000400;
  DLCTL_DOWNLOADONLY = $00000800;
  DLCTL_SILENT = $40000000;
var
  I: Integer;
begin
  if DISPID_AMBIENT_DLCONTROL = DispID then
  begin
    I := DLCTL_DOWNLOADONLY + DLCTL_NO_SCRIPTS +
      DLCTL_NO_JAVA + DLCTL_NO_DLACTIVEXCTLS +
      DLCTL_NO_RUNACTIVEXCTLS +
      DLCTL_SILENT;
    PVariant(VarResult)^ := I;
    Result := S_OK;
  end
  else
    Result := DISP_E_MEMBERNOTFOUND;
end;

function TUILess.SaveObject: HRESULT;
begin
  Result := E_NOTIMPL;
end;

function TUILess.GetMoniker(dwAssign: Longint; dwWhichMoniker: Longint;
  out mk: IMoniker): HRESULT;
begin
  Result := E_NOTIMPL;
end;

function TUILess.GetContainer(out container: IOleContainer): HRESULT;
begin
  Result := E_NOTIMPL;
end;

function TUILess.ShowObject: HRESULT;
begin
  Result := E_NOTIMPL;
end;

function TUILess.OnShowWindow(fShow: BOOL): HRESULT;
begin
  Result := E_NOTIMPL;
end;

function TUILess.RequestNewObjectLayout: HRESULT;
begin
  Result := E_NOTIMPL;
end;

procedure TForm1.Button1Click(Sender: TObject);
const
  cHTML: WideString = '<b>test</b><script>alert("boo")</script>';
var
  Doc: IHTMLDocument2;
  DocClientSite: TUILess;
begin
  DocClientSite := TUILess.Create(nil);
  try
    Doc := coHTMLDocument.Create as IHTMLDocument2;
    try
      (Doc as IOleObject).SetClientSite(DocClientSite);
      (Doc as IOleControl).OnAmbientPropertyChange(DISPID_AMBIENT_DLCONTROL); // Invoke
      OleVariant(Doc).write(cHTML);
      Doc.close;
      ShowMessage(Doc.body.innerHtml); // Test
    finally
      (Doc as IOleObject).SetClientSite(nil);
      Doc := nil;
    end;
  finally
    DocClientSite.Free;
  end;
end;

【讨论】:

  • 你是个英雄。非常感谢!
【解决方案2】:

恐怕您将无法轻松隐藏该消息。为什么?

首先,您需要了解该消息甚至显示在该特定网站上的原因。简短的回答是今年欧盟开始使用的关于处理 cookie 的新法律(不确定具体时间):

http://ico.org.uk/for_organisations/privacy_and_electronic_communications/the_guide/cookies?hidecookiesbanner=true

然后您需要意识到显示的消息不是任何类型的标准弹出消息,而是硬编码到网站中。更糟糕的是,每个网站所有者都使用自己的方法来执行此操作。

顺便说一句,在您的网络浏览器中禁用 cookie 不会阻止显示该消息。为什么?如果网站想查看是否允许使用 cookie,则必须将 cookie 发送到客户端计算机。但法律要求在将任何 cookie 发送到客户端计算机之前,向用户发出有关使用 cookie 的警告。

因此,只需单击一次我接受使用 cokies 可能会更容易,并且该消息可能不会再次显示。为什么?因为在这种情况下,网站会创建一个永久 cookie,其中存储您已经同意使用 cookie 的信息。

【讨论】:

  • 他没有浏览器控件,所以他看不到页面。似乎正在显示一个弹出对话框。
  • 警告作为“Windows 安全警告”通过操作系统发出。我已将所有安全策略减少到最低限度,但没有成功 (tiny.cc/fzedlx)
  • 真的吗?如果不是秘密,介意分享网页链接吗?我以前从未见过这样的行为。
  • @SilverWarior 我想知道为什么这个答案仍然以这种形式出现,因为你知道这是错误的
  • @SilverWarior 此操作系统行为记录在此:support.microsoft.com/kb/154360
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-02-15
  • 2015-03-14
  • 1970-01-01
  • 1970-01-01
  • 2018-10-20
  • 2019-12-22
  • 1970-01-01
相关资源
最近更新 更多