Delphi 如何将WebBrowser呈现到设备上下文?

Delphi 如何将WebBrowser呈现到设备上下文?,delphi,winapi,internet-explorer-9,rendering,delphi-5,Delphi,Winapi,Internet Explorer 9,Rendering,Delphi 5,我想将网页(即TWebBrowser)呈现到设备上下文。我想使用Internet Explorer的布局引擎将内容呈现到设备上下文(即图元文件、pdf图元文件) 从Internet Explorer 9开始,不再支持iHTMLelementTrender界面: IHTMLElementRender接口 使用此接口将元素的内容绘制到指定的设备上下文(通常是打印机) 成员 IHTMLelementTrender接口继承自接口,但没有其他成员 甚至到了他们不再提及这个问题的地步: 不赞成。将元素的内

我想将网页(即
TWebBrowser
)呈现到设备上下文。我想使用Internet Explorer的布局引擎将内容呈现到设备上下文(即图元文件、pdf图元文件)


从Internet Explorer 9开始,不再支持
iHTMLelementTrender
界面:

IHTMLElementRender接口 使用此接口将元素的内容绘制到指定的设备上下文(通常是打印机)

成员
IHTMLelementTrender接口继承自接口,但没有其他成员

甚至到了他们不再提及这个问题的地步:

不赞成。将元素的内容绘制到指定的设备上下文

语法

HRESULT DrawToDC(
     HDC hDC
);
参数

  • hDC
    [在]指定要绘制到的设备的HDC,通常为打印机
返回值

如果成功,则返回S_OK,否则返回错误值

备注

从Windows Internet Explorer 9开始,此方法已被弃用,不应使用

对于某些打印机,运行IHTMLElementRender::DrawToDC可能会导致问题。通过先运行方法,然后将修改后的设备上下文传递给IHTMLELELEMENTRENDER::DrawToDC,可以确保IHTMLElementRender::DrawToDC在所有打印机上正常工作

注意:我引用了所有文档,以便在Microsoft最终将其从MSDN中完全删除时仍能找到。与接口声明一起:

IHTMLElementRender = interface(IUnknown)
   ['{3050F669-98B5-11CF-BB82-00AA00BDCE0B}']
   function DrawToDC(hdc: HDC): HResult; stdcall;
   function SetDocumentPrinter(const bstrPrinterName: WideString; hdc: HDC): HResult; stdcall;
end;

使用
IViewObject
界面 我已尝试转换为使用
IViewObject
(例如):

此代码的问题在于,它仅呈现浏览器的可见区域(即没有滚动内容):

我需要呈现整个网页(例如用于打印)

我试着将从(按原样)更改为
DVASPECT\u DOCPRINT

DVASPECT\u DOCPRINT
在屏幕上提供对象的表示,就像使用“文件”菜单中的“打印”命令将对象打印到打印机一样。所描述的数据可以表示页面序列

结果相同;不呈现页面,只呈现可见部分:

如何要求IE9渲染引擎进行渲染


我还尝试使用不同的索引以及
DVASPECT\u DOCPRINT
。虽然未记录
IViewObject
,但可能这就是您打印不同“页面”的方式:

但是网络浏览者并不关心索引是什么;仅呈现当前的
视图
(我认为在使用
IViewObject
时这是有意义的)

如何将浏览器呈现到设备上下文

注意:该问题标有
delphi
,但该问题中没有delphi特定的内容


更新:我还尝试了aspect和index的其他组合:


使用IViewObject,可以创建当前视口的屏幕截图。我使用了一个技巧来创建网页(没有任何框架)或框架文档的屏幕截图

  • 使用scrollWidth/scrollHeight/scrollLeft/scrollTop计算完整文档大小(检查IHtmlDocument2和IHtmlDocument3接口)
  • 锁定窗口更新并将文档调整为计算的全尺寸
  • 使用IViewObject创建快照(上面的代码似乎还可以)
  • 将文档还原为其原始大小并解锁窗口更新

  • 请注意当文档非常大时,您应该小心操作。

    根据,您的做法是正确的,需要调整浏览器控件的大小(暂时)。未测试。TOndrej在这种情况下,浏览器(控件)与客户端窗体对齐/固定,客户端窗体的大小受限于用户显示器的大小。就像Internet Explorer本身一样。所以我想知道Internet Explorer是如何打印的。也许你可以创建一个临时的不可见的浏览器控件并将内容复制到它,或者重用你现有的控件并尝试WM_SETREDRAW、LockWindowUpdate等技巧以避免可见的效果。@TOndrej调整浏览器控件的大小在某些情况下可能会起作用,在其他情况下,它可能会给您带来意外的结果,即如果您调整浏览器控件本身的大小,HTML内容可能会更改其布局。@Ian,正如TOndrej所提到的,如果不调整浏览器的大小,您似乎无法获得完整的内容。顺便说一句,您可能希望在宽度和高度计算中包括正文的左、右、上、下边距。IViewObject.Draw(..)的第二个参数“index”似乎可以。恐怕您无法直接使用任何API创建完整大小的文档快照。
    procedure RenderWebBrowserToMetafile(Browser: TWebBrowser; Metafilename: string);
    var
        view: IViewObject;
        m: TMetafile;
        mc: TMetafileCanvas;
        w, h: Integer;
        r: TRect;
        dpix: Integer;
        dpiy: Integer;
        dc: HDC;
    begin
        w := WebBrowserScrollWidth(Browser);
        h := WebBrowserScrollHeightStrict(Browser);
    
        //96dpi screen to 300dpi metafile (destined for printer)
        dc := GetDC(0);
        try
            dpix := GetDeviceCaps(GetDC(0), LOGPIXELSX);
            dpiy := GetDeviceCaps(GetDC(0), LOGPIXELSY);
        finally
            ReleaseDC(0, dc);
        end;
        w := MulDiv(w, 300, dpix);
        h := MulDiv(h, 300, dpiy);
    
        view := Browser.Document as IViewObject;
    
        m := TMetafile.Create;
        try
            m.Width := w;
            m.Height := h;
            r := Rect(0, 0, w, h);
    
            mc := TMetafileCanvas.Create(m, 0);
            try
                view.Draw(
                        DVASPECT_CONTENT, //draw aspect
                        1, //index
                        nil, //pAspectInfo
                        nil, //pDVTargetDevice
                        0, //Target Device Context
                        mc.handle, //hdcDraw
                        @r, //target Bounds
                        @w, //window bounds (for metafiles)
                        nil, //continue function
                        0); //continue value
            finally
                mc.Free;
            end;
            m.SaveToFile(Metafilename);
        finally
            m.Free;
        end;
    end;
    
    view.Draw(DVASPECT_DOCPRINT, 1, ...);
    view.Draw(DVASPECT_DOCPRINT, 2, ...);
    view.Draw(DVASPECT_DOCPRINT, 3, ...);
    ...
    view.Draw(DVASPECT_DOCPRINT, n, ...);
    
    view.Draw(DVASPECT_CONTENT, -1, ...);
    view.Draw(DVASPECT_DOCPRINT, -1, ...);
    view.Draw(DVASPECT_CONTENT, 0, ...);
    view.Draw(DVASPECT_DOCPRINT, 0, ...);