Como renderizar WebBrowser para o contexto do dispositivo?

Eu quero renderizar uma página web (ou seja,TWebBrowser) para um contexto de dispositivo. Eu quero usar o mecanismo de layout do Internet Explorer para renderizar conteúdo em um contexto de dispositivo (por exemplo, metarquivo, metarquivo pdf).

Começando com o Internet Explorer 9, oIHTMLElementRender interface não é maissuportado:

Interface IHTMLElementRender

Use essa interface para desenhar o conteúdo de um elemento em um contexto de dispositivo especificado, normalmente uma impressora.

Membros
oIHTMLElementRender interface herda doIUnknown interface, mas não tem membros adicionais.

Para o ponto que eles já não mencionam que oMétodo DrawToDC existe mesmo:

Método IHTMLElementRender :: DrawToDC

Descontinuada. Desenha o conteúdo do elemento para o contexto do dispositivo especificado.

Sintaxe

HRESULT DrawToDC(
     HDC hDC
);

Parâmetros

hDC
[no] umHDC especificando o dispositivo a ser desenhado, tipicamente uma impressora.

Valor de retorno

Retorna S_OK se for bem-sucedido ou um valor de erro.

Observações

A partir do Windows Internet Explorer 9, esse método é obsoleto e não deve ser usado.

Com algumas impressoras, executandoIHTMLElementRender :: DrawToDC pode causar problemas. Você pode garantir queIHTMLElementRender :: DrawToDC funciona corretamente em todas as impressoras executandoIHTMLElementRender :: SetDocumentPrinter primeiro método e, em seguida, passando o contexto do dispositivo modificado paraIHTMLElementRender :: DrawToDC.

Nota: Estou citando toda a documentação para que ela ainda possa ser encontrada quando a Microsoft finalmente a remover do MSDN. Junto com a declaração da interface:

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

Eu tentei converter para usar oIViewObject (por exemplo.Como renderizar elemento HTML sem usar o navegador da web?):

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;

O problema com este código é que ele só renderizavisível área do navegador (ou seja, sem conteúdo rolado):

eu preciso renderizar ointeira página da web (por exemplo, para impressão).

Eu tentei mudar odesenhar aspecto deDVASPECT_CONTENT (Comoeste exemplo faz), paraDVASPECT_DOCPRINT:

DVASPECT_DOCPRINT
Fornece uma representação do objeto na tela como se ele fosse impresso em uma impressora usando o comando Imprimir no menu Arquivo. Os dados descritos podem representar uma seqüência de páginas.

Com o mesmo resultado; em vez de renderizar a página, somente a parte visível é renderizada:

Como posso pedir ao mecanismo de renderização do IE9 para renderizar?

Eu também tentei usar diferentesíndices junto comDVASPECT_DOCPRINT. ApesarIViewObject não está documentado, talvez seja assim que você imprime diferente"Páginas":

view.Draw(DVASPECT_DOCPRINT, 1, ...);
view.Draw(DVASPECT_DOCPRINT, 2, ...);
view.Draw(DVASPECT_DOCPRINT, 3, ...);
...
view.Draw(DVASPECT_DOCPRINT, n, ...);

Mas o WebBrowser não se importa com o que o índice é; apenas renderizando a correnteView (o que eu acho que faz sentido ao usarIViewObject).

Como faço para renderizar um navegador para um contexto de dispositivo?

Nota: A questão é marcada comdelphi, mas não há nada nesta questão que sejadelphi específico.

Atualizar: eu também tentei outras combinações deaspecto eíndice:

view.Draw(DVASPECT_CONTENT, -1, ...);
view.Draw(DVASPECT_DOCPRINT, -1, ...);
view.Draw(DVASPECT_CONTENT, 0, ...);
view.Draw(DVASPECT_DOCPRINT, 0, ...);

questionAnswers(1)

yourAnswerToTheQuestion