title: Trying to render web browser control using IViewObject::Draw() into HDC fails with IE8 but succeeds with IE11
body: <p>I have an MFC dialog window where I added a <a href="https://msdn.microsoft.com/en-us/library/aa752046(v=vs.85).aspx" rel="nofollow noreferrer">WebBrowser control</a> (that encapsulates the <code>Internet Explorer</code> engine.)</p>
  
  <p>The goal of the following code is to render the contents of the said <code>web browser control</code> into a <code>device context</code> that I can later use for printing:</p>
  
  <pre><code>//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&lt;IHTMLDocument2&gt; pHtmlDocument2;
  pHtmlDoc-&gt;QueryInterface(IID_IHTMLDocument2, (void**)&amp;pHtmlDocument2));
  
  //Get IViewObject2 for the entire document that we will use to render into a DC
  CComPtr&lt;IViewObject2&gt; pViewObject;
  pHtmlDocument2-&gt;QueryInterface(IID_IViewObject2, (void **)&amp;pViewObject));
  
  CComPtr&lt;IHTMLElement&gt; pBody;
  pHtmlDocument2-&gt;get_body(&amp;pBody));
  
  CComPtr&lt;IHTMLElement2&gt; pBody2;
  pBody-&gt;QueryInterface(IID_IHTMLElement2, (void **)&amp;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-&gt;get_scrollWidth(&amp;n_scrollWidth);
  pBody2-&gt;get_scrollHeight(&amp;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, &amp;info, DIB_RGB_COLORS, (void**)&amp;pMemory, 0, 0);
  
  HBITMAP hOldBmp = (HBITMAP)::SelectObject(hCompDc, hBitmap);
  
  RECT rcAll = {0, 0, nWidth, nHeight};
  ::FillRect(hCompDc, &amp;rcAll, (HBRUSH)::GetStockObject(WHITE_BRUSH));
  
  RECTL rectPrnt = {0, 0, nWidth, nHeight};
  
  //Do the upscaling &amp; render -- note that IE8 fails to render it here!!!!
  pViewObject-&gt;Draw(DVASPECT_CONTENT, //DVASPECT_DOCPRINT
          -1, NULL, NULL, NULL, hCompDc, 
          &amp;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*)&amp;fileHeader, sizeof(fileHeader));
  file.Write((char*)&amp;infoHeader, sizeof(infoHeader));
  
  int bytes = (((24 * nWidth + 31) &amp; (~31)) / 8) * nHeight;
  file.Write(pMemory, bytes);
  
  
  //Clean up
  ::DeleteObject(hBitmap);
  ::DeleteDC(hCompDc);
  
  ::ReleaseDC(hWnd, hDc);
  
  ::DeleteDC(hPrintDC);
  </code></pre>
  
  <p>This code works fine if I have the latest <code>IE11</code> installed on my development machine. But if, for instance, someone has <code>IE8</code> installed on their Windows 7, the <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms688655(v=vs.85).aspx" rel="nofollow noreferrer">IViewObject::Draw</a> method will render only a small part of the document (equal to the size of the web browser control itself.)</p>
  
  <p>The best way to describe it is to illustrate it with the examples:</p>
  
  <p>Normally rendered test page with <code>IE11</code> installed:</p>
  
  <p><a href="https://i.stack.imgur.com/2xpCi.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/2xpCi.jpg" alt="enter image description here"></a></p>
  
  <p>and here's what happens with <code>IE8</code> installed:</p>
  
  <p><a href="https://i.stack.imgur.com/sibJl.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/sibJl.jpg" alt="enter image description here"></a></p>
  
  <p>Does anyone have any idea what am I doing wrong here that <code>IE8</code> doesn't like?</p>
  
  <p><strong>EDIT1:</strong> Did some more digging into the <code>IViewObject::Draw</code> function with <code>WinDbg</code> and then found the source code for it. Here's <a href="http://read.pudn.com/downloads3/sourcecode/windows/248345/win2k/private/inet/mshtml/src/core/cdbase/sdv.cxx__.htm" rel="nofollow noreferrer">CServer::Draw()</a> that is <code>IViewObject::Draw</code>, and then <a href="http://read.pudn.com/downloads3/sourcecode/windows/248345/win2k/private/inet/mshtml/src/site/base/paint.cxx__.htm" rel="nofollow noreferrer">CDoc::Draw()</a> that is called internally from <code>CServer::Draw()</code>.</p>