c++ - 尝试使用 IViewObject::Draw() 将 Web 浏览器控件渲染到 HDC 中在 IE8 中失败,但在 IE11 中成功

标签 c++ internet-explorer mfc com internet-explorer-8

我有一个 MFC 对话框窗口,我在其中添加了 WebBrowser control (封装了 Internet Explorer 引擎。)

以下代码的目的是渲染上述 web browser control 的内容。成device context我以后可以用于打印:

//MFC code, error checks are omitted for brevity

//'m_browser' = is a web browser control of type `CExplorer1`
IDispatch* pHtmlDoc = m_browser.get_Document();

CComPtr<IHTMLDocument2> pHtmlDocument2;
pHtmlDoc->QueryInterface(IID_IHTMLDocument2, (void**)&pHtmlDocument2));

//Get IViewObject2 for the entire document that we will use to render into a DC
CComPtr<IViewObject2> pViewObject;
pHtmlDocument2->QueryInterface(IID_IViewObject2, (void **)&pViewObject));

CComPtr<IHTMLElement> pBody;
pHtmlDocument2->get_body(&pBody));

CComPtr<IHTMLElement2> pBody2;
pBody->QueryInterface(IID_IHTMLElement2, (void **)&pBody2));


//Get default printer DC
CPrintDialog pd(TRUE, PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_HIDEPRINTTOFILE | PD_NOSELECTION);
pd.m_pd.Flags |= PD_RETURNDC | PD_RETURNDEFAULT;
pd.DoModal();         //corrected later
HDC hPrintDC = pd.CreatePrinterDC();

//Calc bitmap width based on printer DC specs
//Note that this width will be larger than
//the width of the WebControl window itself due to
//printer's much higher DPI setting...
int n_bitmapWidth = ::GetDeviceCaps(hPrintDC, HORZRES);     //Use entire printable area


//Get full size of the document
long n_scrollWidth;
long n_scrollHeight;
pBody2->get_scrollWidth(&n_scrollWidth);
pBody2->get_scrollHeight(&n_scrollHeight);

//Calc proportional size of the bitmap in the DC to render
int nWidth = n_bitmapWidth;
int nHeight = n_bitmapWidth * n_scrollHeight / n_scrollWidth;

//Create memory DC to render into
HDC hDc = ::GetDC(hWnd);
HDC hCompDc = ::CreateCompatibleDC(hDC);

//I'm using a raw DIB section here as I'll need to access
//its bitmap bits directly later in my code...
BITMAPINFOHEADER infoHeader = {0};

infoHeader.biSize          = sizeof(infoHeader);
infoHeader.biWidth         = nWidth;
infoHeader.biHeight        = -nHeight;
infoHeader.biPlanes        = 1;
infoHeader.biBitCount      = 24;
infoHeader.biCompression   = BI_RGB;

BITMAPINFO info;
info.bmiHeader = infoHeader; 

//Create a bitmap as DIB section of size `nWidth` by `nHeight` pixels
BYTE* pMemory = 0;
HBITMAP hBitmap = ::CreateDIBSection(hDc, &info, DIB_RGB_COLORS, (void**)&pMemory, 0, 0);

HBITMAP hOldBmp = (HBITMAP)::SelectObject(hCompDc, hBitmap);

RECT rcAll = {0, 0, nWidth, nHeight};
::FillRect(hCompDc, &rcAll, (HBRUSH)::GetStockObject(WHITE_BRUSH));

RECTL rectPrnt = {0, 0, nWidth, nHeight};

//Do the upscaling & render -- note that IE8 fails to render it here!!!!
pViewObject->Draw(DVASPECT_CONTENT, //DVASPECT_DOCPRINT
        -1, NULL, NULL, NULL, hCompDc, 
        &rectPrnt,
        NULL,
        NULL, 0));

::SelectObject(hCompDc, hOldBmp);


//Now the bitmap in `hCompDc` contains the resulting pixels
//For debugging purposes, save it as .bmp file

BITMAPFILEHEADER fileHeader = {0};
fileHeader.bfType      = 0x4d42;
fileHeader.bfSize      = 0;
fileHeader.bfReserved1 = 0;
fileHeader.bfReserved2 = 0;
fileHeader.bfOffBits   = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

CFile file(
    L"path-to\\test.bmp",
    CFile::modeCreate | CFile::modeReadWrite | CFile::shareDenyNone);
file.Write((char*)&fileHeader, sizeof(fileHeader));
file.Write((char*)&infoHeader, sizeof(infoHeader));

int bytes = (((24 * nWidth + 31) & (~31)) / 8) * nHeight;
file.Write(pMemory, bytes);


//Clean up
::DeleteObject(hBitmap);
::DeleteDC(hCompDc);

::ReleaseDC(hWnd, hDc);

::DeleteDC(hPrintDC);

如果我有最新的 IE11,此代码工作正常安装在我的开发机器上。但是,例如,如果某人有 IE8安装在他们的 Windows 7 上,IViewObject::Draw方法将仅呈现文档的一小部分(等于 Web 浏览器控件本身的大小。)

描述它的最好方法是用例子来说明它:

通常使用 IE11 呈现的测试页面安装:

enter image description here

这就是 IE8 发生的事情安装:

enter image description here

有谁知道我在这里做错了什么IE8不喜欢?

编辑 1:IViewObject::Draw 进行了更多挖掘功能与 WinDbg然后找到了它的源代码。这是CServer::Draw()IViewObject::Draw ,然后 CDoc::Draw()CServer::Draw() 内部调用.

最佳答案

首先,感谢您提出有趣的问题。虽然不太实用 - 今天没有多少人使用 IE8 - 但解决起来并不是那么简单。我将描述问题所在,并提供您可以改进的简单但有效的解决方案。

在我进入 IE8 解决方案之前,有几点:

  • 如果您遇到大文档,调整窗口大小以适应滚动大小的解决方案不稳定。如果您不知道要期待什么,您还需要为以后的资源管理器重构解决方案,以避免依赖调整窗口大小来滚动大小。
  • 为什么要携带巨幅位图?元文件等可能更适合。在这种分辨率下,任何足够大的页面都会通过幼稚的 DIB 创建来破坏 PC 上的内存。提供的示例中的 Google 页面呈现为 100Mb 位图文件,而 emf(从中完成光栅化)需要不到 1Mb。
  • 虽然我不知道你的项目的确切要求和限制,但我 99% 肯定绘制到巨大的 DIB 不是最好的解决方案。即使是 EMF,虽然更好,但也不是最好的。例如,如果您需要添加签名然后打印,则有更好的方法来处理此问题。当然,这只是一个旁注,与问题本身无关。

  • IE8 渲染问题
    在 IE8 渲染器中有一个错误。 Draw() 将在实际显示区域的像素尺寸处进行裁剪(您看到的可见矩形是渲染上下文比例中的原始显示区域)。
    因此,如果您的缩放目标大于实际大小,则在缩放时,无论如何都会将其裁剪为缩放像素的大小(因此它的内容比原始矩形少得多)。
    如果它在真正的 IE8 上没有为某人剪辑,那么系统中还有后期 IE 的剩余部分,或者有其他非划痕设置、系统更新等。
    解决方法的可能性
    好消息可以解决,坏消息解决方法有点讨厌。
    首先,仍然可以使用 IViewObject 来解决。但是,因为涉及任意缩放并且可访问的源矩形非常小,所以这个解决方案有一些复杂性,我认为这是一个 SO 答案。所以我不会潜入这条道路。
    相反,我们可以通过另一个现已过时的 API 进行渲染:IHTMLElementRender .它允许使用 DrawToDC 将页面渲染到任意上下文中。不幸的是,它并不像看起来那么简单,而且不仅仅是提供设备上下文。
    首先,有类似的剪辑错误。它可以更容易地处理,因为剪裁发生在超出屏幕尺寸的大值处。其次,当使用设备上下文转换时,它要么不起作用,要么会弄乱呈现的 html,因此您实际上不能依赖缩放或翻译。这两个问题都需要相对不平凡的处理并且使彼此复杂化。
    解决方案
    我将描述并提供非最佳但适用于最简单页面解决方案的示例代码。一般而言,可以实现完美且更有效的解决方案,但这又超出了答案的范围。显然,它只是 IE8,因此您需要检查浏览器版本并为 IE8 和 IE9 或更高版本执行不同的处理程序,但您也可以采取一些想法来改进其他浏览器的渲染。
    这里有两个相互关联的解决方法。
    升级
    首先,如果我们不能转换,我们如何将 vector 内容升级到打印机质量?此处的解决方法是渲染到与打印机 dc 兼容的上下文。将会发生的是内容将在打印机 DPI 上呈现。请注意,它不会完全适合打印机宽度,它会缩放到 printerDPI/screenDPI。
    后来,在光栅化时,我们缩小以适应打印机宽度。我们最初渲染为 EMF,因此没有太大的质量损失(无论如何都会发生在打印机本身上)。如果您需要更高的质量(我对此表示怀疑),有两种可能性 - 修改解决方案以呈现目标宽度(这不是微不足道的)或使用生成的电动势而不是位图并让打印机进行缩小适合。
    另一个注意事项是您目前仅使用打印机宽度,但可能存在不可打印的页边距,您需要从打印机查询并说明它们。因此,即使您提供精确的打印机尺寸的位图,它也可能被打印机重新缩放。但同样,我怀疑这种分辨率差异会对您的项目产生任何影响。
    剪裁
    第二个要克服的是剪裁。为了克服这个限制,我们以小块的形式渲染内容,这样它们就不会被渲染器剪掉。渲染一个块后,我们改变文档的滚动位置并将下一个块渲染到目标 DC 中的适当位置。这可以优化以使用更大的块,例如最接近 1024 的 DPI 倍数(使用窗口调整大小),但我没有实现(这只是速度优化)。如果您不进行此优化,请确保最小浏览器窗口大小不会太小。
    请注意,在任意分数尺度上进行此滚动将是一个近似值,并且在一般情况下实现起来并不那么简单。但是使用普通的打印机和屏幕,我们可以在 DPI 的乘积中进行整数块步骤,例如如果屏幕是 96 DPI,打印机是 600DPI,我们在每个上下文中以 96 和 600 的相同倍数执行步骤,一切都简单得多。但是,处理完所有整个块后从顶部或底部开始的余数将不会以 DPI 乘法计算,因此我们无法轻松滚动。
    一般来说,我们可以在打印机空间中近似滚动位置,并希望最终块之间不会出现错配。我所做的是在页面的右下角附加一个绝对定位的具有块大小的 div。
    请注意,这可能会干扰某些页面并更改布局(可能不是简单报告的情况)。如果这是一个问题,您需要在循环后添加余数处理而不是添加元素。在这种情况下,最简单的解决方案仍然是用 div 填充而不是用完整的块大小填充,而只是使内容宽度成为屏幕 DPI 的倍数。
    更简单的想法,正如我后来意识到的,只是将窗口大小调整为最接近 DPI 的倍数,并将此窗口大小作为块大小。您可以尝试使用它代替 div,这将简化代码并修复可能干扰注入(inject) div 的页面。
    编码
    这只是一个示例。
  • 没有错误处理。您需要为每个 COM 和 API 调用等添加检查。
  • 没有代码风格,只是快速而肮脏。
  • 不确定所有获得的资源都根据需要释放,请检查
  • 必须禁用浏览器控件上的页面边框以使此示例工作(如果您需要浏览器周围的边框,只需单独呈现它们,无论如何内置是不一致的)。在 IE8 上,这不是那么简单,但这里或网上有很多答案。无论如何,我将在示例解决方案项目中包含此补丁。您也可以使用边框进行渲染并排除它们,但这对于具有简单解决方案的问题来说将是不必要的复杂化。
  • 完整的解决方案项目可以在 this link 中找到。 ,我会在这里只发布相关的代码。

  • 下面的代码呈现页面并保存在 c:\temp\test.emf + c:\temp\test.bmp
    void convertEmfToBitmap(const RECT& fitRect, HDC hTargetDC, HENHMETAFILE hMetafile, LPCTSTR fileName);
    CComPtr<IHTMLDOMNode> appendPadElement(IHTMLDocument2* pDoc, IHTMLElement* pBody, long left, long top, long width, long height);
    void removeElement(IHTMLElement* pParent, IHTMLDOMNode* pChild);
    
    void CMFCApplication1Dlg::OnBnClickedButton2()
    {
        COleVariant varNull;
        COleVariant varUrl = L"http://www.google.com/search?q=ie+8+must+die";
        m_browser.Navigate2(varUrl, varNull, varNull, varNull, varNull);
    }
    
    
    void CMFCApplication1Dlg::OnBnClickedButton1()
    {
        //get html interfaces
        IDispatch* pHtmlDoc = m_browser.get_Document();
        CComPtr<IHTMLDocument2> pHtmlDocument2;
        pHtmlDoc->QueryInterface(IID_IHTMLDocument2, (void**)&pHtmlDocument2);
    
        CComPtr<IHTMLElement> pBody;
        pHtmlDocument2->get_body(&pBody);
    
        CComPtr<IHTMLElement2> pBody2;
        pBody->QueryInterface(IID_IHTMLElement2, (void**)&pBody2);
    
        CComPtr<IHTMLBodyElement> pBodyElement;
        pBody->QueryInterface(IID_IHTMLBodyElement, (void**)&pBodyElement);
    
        CComPtr<IHTMLElement> pHtml;
        pBody->get_parentElement(&pHtml);
    
        CComPtr<IHTMLElement2> pHtml2;
        pHtml->QueryInterface(IID_IHTMLElement2, (void**)&pHtml2);
    
        CComPtr<IHTMLStyle> pHtmlStyle;
        pHtml->get_style(&pHtmlStyle);
        CComPtr<IHTMLStyle> pBodyStyle;
        pBody->get_style(&pBodyStyle);
    
        //get screen info
        HDC hWndDc = ::GetDC(m_hWnd);
        const int wndLogPx = GetDeviceCaps(hWndDc, LOGPIXELSX);
        const int wndLogPy = GetDeviceCaps(hWndDc, LOGPIXELSY);
    
    
        //keep current values
        SIZE keptBrowserSize = { m_browser.get_Width(), m_browser.get_Height() };
        SIZE keptScrollPos;
        //set reasonable viewport size 
        //m_browser.put_Width(docSize.cx);
        //m_browser.put_Height(docSize.cy*2);
        pHtml2->get_scrollLeft(&keptScrollPos.cx);
        pHtml2->get_scrollTop(&keptScrollPos.cy);
        COleVariant keptOverflow;
        pBodyStyle->get_overflow(&keptOverflow.bstrVal);
    
        //setup style and hide scroll bars
        pHtmlStyle->put_border(L"0px;");
        pHtmlStyle->put_overflow(L"hidden");
        pBodyStyle->put_border(L"0px;");
        pBodyStyle->put_overflow(L"hidden");
    
        //get document size and visible area in screen pixels
        SIZE docSize;
        pBody2->get_scrollWidth(&docSize.cx);
        pBody2->get_scrollHeight(&docSize.cy);
        RECT clientRect = { 0 };
        pHtml2->get_clientWidth(&clientRect.right);
        pHtml2->get_clientHeight(&clientRect.bottom);
    
        //derive chunk size
        const SIZE clientChunkSize = { 
            clientRect.right - clientRect.right % wndLogPx, 
            clientRect.bottom - clientRect.bottom % wndLogPy };
    
        //pad with absolutely positioned element to have enough scroll area for all chunks
        //alternatively, browser can be resized to chunk multiplies (simplest), to DPI multiplies (more work). 
        //This pad also can be made smaller, to modulus DPI, but then need more work in the loops below
        CComPtr<IHTMLDOMNode> pPadNode = 
            appendPadElement(pHtmlDocument2, pBody, docSize.cx, docSize.cy, clientChunkSize.cx, clientChunkSize.cy);
    
        //get printer info
        CPrintDialog pd(TRUE, PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_HIDEPRINTTOFILE | PD_NOSELECTION);
        pd.m_pd.Flags |= PD_RETURNDC | PD_RETURNDEFAULT;
        pd.DoModal(); 
        HDC hPrintDC = pd.CreatePrinterDC();
        const int printLogPx = GetDeviceCaps(hPrintDC, LOGPIXELSX);
        const int printLogPy = GetDeviceCaps(hPrintDC, LOGPIXELSY);
        const int printHorRes = ::GetDeviceCaps(hPrintDC, HORZRES);
        const SIZE printChunkSize = { printLogPx * clientChunkSize.cx / wndLogPx, printLogPy * clientChunkSize.cy / wndLogPy };
    
        //browser total unscaled print area in printer pixel space
        const RECT printRectPx = { 0, 0, docSize.cx* printLogPx / wndLogPx, docSize.cy*printLogPy / wndLogPy };
        //unscaled target EMF size in 0.01 mm with printer resolution
        const RECT outRect001Mm = { 0, 0, 2540 * docSize.cx / wndLogPx, 2540 * docSize.cy / wndLogPy };
        HDC hMetaDC = CreateEnhMetaFile(hPrintDC, L"c:\\temp\\test.emf", &outRect001Mm, NULL);
        ::FillRect(hMetaDC, &printRectPx, (HBRUSH)::GetStockObject(BLACK_BRUSH));
    
        //unscaled chunk EMF size in pixels with printer resolution
        const RECT chunkRectPx = { 0, 0, printChunkSize.cx, printChunkSize.cy };
        //unscaled chunk EMF size in 0.01 mm with printer resolution
        const RECT chunkRect001Mm = { 0, 0, 2540 * clientChunkSize.cx / wndLogPx, 2540 * clientChunkSize.cy / wndLogPy };
    
        ////////
        //render page content to metafile by small chunks
    
        //get renderer interface
        CComPtr<IHTMLElementRender> pRender;
        pHtml->QueryInterface(IID_IHTMLElementRender, (void**)&pRender);
        COleVariant printName = L"EMF";
        pRender->SetDocumentPrinter(printName.bstrVal, hMetaDC);
    
    
        //current positions and target area
        RECT chunkDestRectPx = { 0, 0, printChunkSize.cx, printChunkSize.cy };
        POINT clientPos = { 0, 0 };
        POINT printPos = { 0, 0 };
    
        //loop over chunks left to right top to bottom until scroll area is completely covered
        const SIZE lastScroll = { docSize.cx, docSize.cy};
        while (clientPos.y < lastScroll.cy)
        {
            while (clientPos.x < lastScroll.cx)
            {
                //update horizontal scroll position and set target area
                pHtml2->put_scrollLeft(clientPos.x);
                chunkDestRectPx.left = printPos.x;
                chunkDestRectPx.right = printPos.x + printChunkSize.cx;
    
                //render to new emf, can be optimized to avoid recreation
                HDC hChunkDC = CreateEnhMetaFile(hPrintDC, NULL, &chunkRect001Mm, NULL);
                ::FillRect(hChunkDC, &chunkRectPx, (HBRUSH)::GetStockObject(WHITE_BRUSH));
                pRender->DrawToDC(hChunkDC);
                HENHMETAFILE hChunkMetafile = CloseEnhMetaFile(hChunkDC);
    
                //copy chunk to the main metafile
                PlayEnhMetaFile(hMetaDC, hChunkMetafile, &chunkDestRectPx);
                DeleteEnhMetaFile(hChunkMetafile);
    
                //update horizontal positions
                clientPos.x += clientChunkSize.cx;
                printPos.x += printChunkSize.cx;
            }
    
            //reset horizontal positions
            clientPos.x = 0;
            printPos.x = 0;
            //update vertical positions
            clientPos.y += clientChunkSize.cy;
            printPos.y += printChunkSize.cy;
            pHtml2->put_scrollTop(clientPos.y);
            chunkDestRectPx.top = printPos.y;
            chunkDestRectPx.bottom = printPos.y + printChunkSize.cy;
        }
    
        //restore changed values on browser
        //if for large pages on slow PC you get content scrolling during rendering and it is a problem,
        //you can either hide the browser and show "working" or place on top first chunk content
        pBodyStyle->put_overflow(keptOverflow.bstrVal);
        pHtml2->put_scrollLeft(keptScrollPos.cx);
        pHtml2->put_scrollTop(keptScrollPos.cy);
        m_browser.put_Width(keptBrowserSize.cx);
        m_browser.put_Height(keptBrowserSize.cy);
        removeElement(pBody, pPadNode);
    
        //draw to bitmap and close metafile
        HENHMETAFILE hMetafile = CloseEnhMetaFile(hMetaDC);
        RECT fitRect = { 0, 0, printHorRes, docSize.cy * printHorRes / docSize.cx };
        convertEmfToBitmap(fitRect, hWndDc, hMetafile, L"c:\\temp\\test.bmp");
        DeleteEnhMetaFile(hMetafile);
    
        //cleanup - probably more here
        ::ReleaseDC(m_hWnd, hWndDc);
        ::DeleteDC(hPrintDC);
    
        //{
        //  std::stringstream ss;
        //  ss << "====" << docSize.cx << "x" << docSize.cy << " -> " << fitRect.right << "x" << fitRect.bottom << "" << "\n";
        //  OutputDebugStringA(ss.str().c_str());
        //}
    
    }
    
    
    
    ///////////////
    ////some util 
    
    void convertEmfToBitmap(const RECT& fitRect, HDC hTargetDC, HENHMETAFILE hMetafile, LPCTSTR fileName)
    {
        //Create memory DC to render into
        HDC hCompDc = ::CreateCompatibleDC(hTargetDC);
        //NOTE this 
        BITMAPINFOHEADER infoHeader = { 0 };
        infoHeader.biSize = sizeof(infoHeader);
        infoHeader.biWidth = fitRect.right;
        infoHeader.biHeight = -fitRect.bottom;
        infoHeader.biPlanes = 1;
        infoHeader.biBitCount = 24;
        infoHeader.biCompression = BI_RGB;
    
        BITMAPINFO info;
        info.bmiHeader = infoHeader;
    
        //create bitmap
        BYTE* pMemory = 0;
        HBITMAP hBitmap = ::CreateDIBSection(hCompDc, &info, DIB_RGB_COLORS, (void**)&pMemory, 0, 0);
        HBITMAP hOldBmp = (HBITMAP)::SelectObject(hCompDc, hBitmap);
    
    
        PlayEnhMetaFile(hCompDc, hMetafile, &fitRect);
    
        BITMAPFILEHEADER fileHeader = { 0 };
        fileHeader.bfType = 0x4d42;
        fileHeader.bfSize = 0;
        fileHeader.bfReserved1 = 0;
        fileHeader.bfReserved2 = 0;
        fileHeader.bfOffBits = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
    
        CFile file(
            fileName,
            CFile::modeCreate | CFile::modeReadWrite | CFile::shareDenyNone);
        file.Write((char*)&fileHeader, sizeof(fileHeader));
        file.Write((char*)&infoHeader, sizeof(infoHeader));
    
        int bytes = (((24 * infoHeader.biWidth + 31) & (~31)) / 8) * abs(infoHeader.biHeight);
        file.Write(pMemory, bytes);
    
        ::SelectObject(hCompDc, hOldBmp);
    
        //Clean up
        if (hBitmap)
            ::DeleteObject(hBitmap);
        ::DeleteDC(hCompDc);
    }
    
    
    CComPtr<IHTMLDOMNode> appendPadElement(IHTMLDocument2* pDoc, IHTMLElement* pBody, long left, long top, long width, long height)
    {
        CComPtr<IHTMLElement> pPadElement;
        pDoc->createElement(L"DIV", &pPadElement);
        CComPtr<IHTMLStyle> pPadStyle;
        pPadElement->get_style(&pPadStyle);
        CComPtr<IHTMLStyle2> pPadStyle2;
        pPadStyle->QueryInterface(IID_IHTMLStyle2, (void**)&pPadStyle2);
        pPadStyle2->put_position(L"absolute");
        CComVariant value = width;
        pPadStyle->put_width(value);
        value = height;
        pPadStyle->put_height(value);
        pPadStyle->put_posLeft((float)left);
        pPadStyle->put_posTop((float)top);
        CComPtr<IHTMLDOMNode> pPadNode;
        pPadElement->QueryInterface(IID_IHTMLDOMNode, (void**)&pPadNode);
        CComPtr<IHTMLDOMNode> pBodyNode;
        pBody->QueryInterface(IID_IHTMLDOMNode, (void **)&pBodyNode);
        pBodyNode->appendChild(pPadNode, NULL);
        return pPadNode;
    }
    
    void removeElement(IHTMLElement* pParent, IHTMLDOMNode* pChild)
    {
        CComPtr<IHTMLDOMNode> pNode;
        pParent->QueryInterface(IID_IHTMLDOMNode, (void **)&pNode);
        pNode->removeChild(pChild, NULL);
    }
    
    示例页面输出 (4958x7656)
    Sample Output

    关于c++ - 尝试使用 IViewObject::Draw() 将 Web 浏览器控件渲染到 HDC 中在 IE8 中失败,但在 IE11 中成功,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41299973/

    相关文章:

    c++ - 使用 QtGui 显示 QImage

    c++ - 无法编译 64 位 Visual Studio 2010 项目

    javascript - 如何修复 IE9 的 f12 问题?

    c# - 无法使用 JRE 7u51 在 Internet Explorer 11 中运行 Java 小程序

    css - 在 Internet Explorer 中设置 INPUT 按钮的样式

    c++ - MFC IMPLEMENT_DYNCREATE 模板

    c++ - Boost BGL Dijkstra 最短路径

    c++,位图不会显示?

    c# - MFC 中的硬件加速

    c++ - 如何知道Windows XP 或7 中是否安装了MSSql Server?