4

I am writing a Browser Helper Object in Visual C++ that needs to take a full-length screenshot of the rendered web-page. Currently, I am trapping the DocumentComplete event in my BHO. I get the hWnd of the Browser, and can take a screenshot of that, but it's not what I really need. I really need the Window that the page is rendered in (not the frame with the scroll bar).

Also, I'm currently experiencing a race condition where the browser may not have rendered the page yet when I take the screenshot. I've added a call to UpdateWindow but even after that returns true, sometimes the window hasn't been rendered yet.

So, summing up:

1) How do I get the hWnd of the rendered HTML window 2) What is the appropriate event available to a BHO to take the screenshot?

EDIT:

Based on the answer below, I've created this code:

        MSHTML::IHTMLRectPtr pRect2 = pBody2->getBoundingClientRect();

        long width = pRect2->right;
        long height = pRect2->bottom;

        RECTL imageRect = { 0, 0, width, height };

        IViewObject *pViewObject = NULL;
        pHtmlDocument2->QueryInterface(IID_IViewObject, (void**)&pViewObject);

        HDC hdcScreen = GetDC(NULL);
        HDC hCompDc = CreateCompatibleDC(hdcScreen);

        pViewObject->Draw(DVASPECT_CONTENT, -1, NULL, NULL, NULL, hCompDc, NULL, &imageRect, NULL, 0);

        HBITMAP hbmp = CreateCompatibleBitmap(hCompDc, imageRect.right - imageRect.left, imageRect.bottom - imageRect.top);
        SelectObject(hCompDc, hbmp);

        Bitmap *image = new Bitmap(hbmp, NULL);

        long bitLength = (imageRect.right - imageRect.left) * (imageRect.bottom - imageRect.top) * 4;
        byte *bits = (byte*)malloc(bitLength);
        memset(bits, 0, bitLength);

        BITMAPINFO *info = new BITMAPINFO();

        GetDIBits(hCompDc, hbmp, 0, imageRect.bottom - imageRect.top, bits, info, DIB_RGB_COLORS);

        FILE* file = fopen("d:\\screenshot.bmp", "wb");
        fwrite(bits, 1, bitLength, file);
        fclose(file);

Unfortunately, the output is not a valid bitmap. I don't know what I'm doing wrong. Please help.

Payton Byrd
  • 956
  • 1
  • 12
  • 27

1 Answers1

2

I assume that you have IWebBrowser2 interface, right?

Then I would get an interface to the HTML Document:

HRESULT IWebBrowser2::get_Document(IDispatch **ppDisp);

and then to the view (as suggested here), to draw the content on the supplied DC:

//hCompDc is a CompatibleDC which select a CompatibleBitmap.
RECTL imageRect = {0, 0, nWidth, nHeight};
pHtmlDocument2->QueryInterface(IID_IViewObject, (void **)&pViewObject);
pViewObject->Draw(DVASPECT_CONTENT, -1, NULL, NULL, NULL, 
                  hCompDc, NULL, &imageRect, NULL, 0);
Community
  • 1
  • 1
Vlad Feinstein
  • 10,960
  • 1
  • 12
  • 27
  • Thank you so much for your answer. What is hCompDc initialized with? – Payton Byrd Apr 25 '16 at 15:27
  • Judging by the comment that I linked: `//hCompDc is a CompatibleDC which select a CompatibleBitmap.` it was created via `CreateCompatibleDC()`, and then a bitmap, created by `CreateCompatibleBitmap()` was selected into it... – Vlad Feinstein Apr 25 '16 at 20:26
  • I believe your problem is here: `HBITMAP hbmp = CreateCompatibleBitmap(hCompDc, ...`; the newly created DC has a 1x1 monochrome bitmap selected into it. You need to create bitmap, compatible to the screen DC. Also, you are just writing down bits, that is NOT a valid bitmap format. – Vlad Feinstein Apr 26 '16 at 14:52