如何给WebBrowser中的网页全身照相

发布时间:2009年09月01日      浏览次数:1315 次
最近在写程序的时候,突然觉得google chrome的网页缩略照片挺好玩 , 可是 chrome 是自己的内核, 自家的东西当然方便.WebBrowser 又怎么办?
首先想到的是最普通的屏幕复制, 也就是大家熟知的bitblt, 从WebBrowser的dc复制到bitmap的dc. 这种方法有很大的局限性: 1.要正确复制,必须保证WebBrowser在屏幕复制的时候必须处于窗口最前端( 就是没有遮蔽物 ), 否则复制出来的图像是有遮盖物. 2.即使没有遮盖物,复制出来的图像往往包含3D Border , Scroll , 这在标准的WebBrowser是必要的.但是对于网页缩略照片,这可就是恶心的东西了.
于是有人想到了ActiveX里面的一个接口 IViewObject2 , WebBrowser也实现了这个接口, 你只需要从WebBrowser对象中QueryInterface(...)就可以枚举出这个接口. IWebBrowser2* pWB2 = ...//获取WebBrowser接口, pWB2->QueryInterface( IID_IViewObject2 , (void**)&pViewObj2 ); 然后使用 IViewObject2 中的 Draw 这个方法,就可以绘画WebBrowser中网页的内容, 很好,即使窗口是隐藏的也可以画出, 可是,等等, 只要您尝试这个方法, 您就会发现,这个仍然不尽如人意. 因为你只能获取WebBrowser这个窗口大小的网页缩略图 , 而无法获取整个网页的缩略图. 同时, 3D Border, Scroll 仍然折磨着我们. 有人提出了如下代码 , 可以一定程度缓解, 让我们看看:

IHTMLBodyElement* pBody = 0;
IHTMLElement* pBodyElem;
HRTEST_E( GetHTMLDocument2()->get_body(&pBodyElem) );
HRTEST_E( pBodyElem->QueryInterface(IID_IHTMLBodyElement, (void**)&pBody) );
IHTMLStyle* pStyle;
HRTEST_E ( pBodyElem->get_style(&pStyle) );
HRTEST_E ( pStyle->put_borderStyle( bsBorderStyle = ::SysAllocString(L"none")) );
// hide scrollbars
HRTEST_E( pBody->put_scroll( bsScrollStyle = ::SysAllocString(L"no")) );
// resize the browser component to the size of the HTML content
IHTMLElement2* pBodyElement2;
HRTEST_E( pBody->QueryInterface(IID_IHTMLElement2, (void**)&pBodyElement2) );
long iScrollWidth = 0;
HRTEST_E( pBodyElement2->get_scrollWidth(&iScrollWidth) );
long iScrollHeight = 0;
HRTEST_E( pBodyElement2->get_scrollHeight(&iScrollHeight) );
RECT rc = { 0,0,iScrollWidth , iScrollHeight };
::SetWindowPos( GetHWND() , NULL , 0, 0, iScrollWidth , iScrollHeight , SWP_NOREDRAW );
SetWebRect(&rc);
忽略其中奇怪的宏,我们可以发现,这个思想就是使用 Body, 来关闭border, 关闭scroll, 在有些场合下是有用的,可是大部分情况,如果页面过大(比如超过屏幕大小), scroll还是会出现. border也不会消失,因为这和body元素没有关系.
真的没有办法解决吗? 当然有,否则我也不会写那么多东西了, 有一个很著名的好东西, 接口:IDocHostUIHandler , 他有一个方法: GetHostInfo(DOCHOSTUIINFO *pInfo); 可以改变WebBrowser的显示方式.完全不需要使用body来关闭border和scroll这种吃力不讨好的办法. 所以为了去除border, scroll我们只要这么写:

HRESULT
CShadowWebWindow::GetHostInfo(DOCHOSTUIINFO *pInfo)
{
pInfo->cbSize = sizeof(DOCHOSTUIINFO);
pInfo->dwFlags = DOCHOSTUIFLAG_DIALOG |
DOCHOSTUIFLAG_THEME |
DOCHOSTUIFLAG_NO3DBORDER |
DOCHOSTUIFLAG_SCROLL_NO;
return S_OK;
}
其中DOCHOSTUIFLAG_NO3DBORDER和DOCHOSTUIFLAG_SCROLL_NO正是我们需要的效果. 接下来我们要画出整个网页,只需要设置WebBrowser的容器大小为html的大小, 就可以完满的画出网页缩略图.
当然, 在下强烈推荐应当使用一个看不见的WebBrowser来实现化网页缩略图, 毕竟, 一个窗口忽大忽小,不是一个好的用户体验.
最后整理一下代码:
我使用一个叫CShadowWebWindow类实现WebBrowser, 这是一个不可见的窗口.
以下是关键代码, (请忽略奇怪的宏 )
void
CShadowWebWindow::DocumentComplete( IDispatch *pDisp,VARIANT *URL)
{
WebBrowserWindow::DocumentComplete( pDisp, URL );
PWSTR npwNewBmpFilePath = NULL;
IWebBrowser2* pWB2 = GetWebBrowser2();
IViewObject2* pViewObject2 = NULL;
HRTEST_E( pWB2->QueryInterface( IID_IViewObject2 , (void**)&pViewObject2 ) );
IHTMLElement* pBodyElem;
HRTEST_E( GetHTMLDocument2()->get_body(&pBodyElem) );
// resize the browser component to the size of the HTML content
IHTMLElement2* pBodyElement2;
HRTEST_E( pBodyElem->QueryInterface(IID_IHTMLElement2, (void**)&pBodyElement2) );
long iScrollWidth = 0;
HRTEST_E( pBodyElement2->get_scrollWidth(&iScrollWidth) );
long iScrollHeight = 0;
HRTEST_E( pBodyElement2->get_scrollHeight(&iScrollHeight) );
//调整WebBrowser大小和网页大小一致
RECT rc = { 0,0,iScrollWidth , iScrollHeight };
::SetWindowPos( GetHWND() , NULL , 0, 0, iScrollWidth , iScrollHeight , SWP_NOREDRAW );
SetWebRect(&rc);
HBITMAP hBitmap = ::CreateCompatibleBitmap( GetDC(GetHWND()), RECTWIDTH(rc), RECTHEIGHT(rc) );
HDC hBitmapDC = ::CreateCompatibleDC( GetDC(GetHWND()) );
::SelectObject( hBitmapDC , hBitmap );
RECTL rctl = { rc.left , rc.top , rc.right , rc.bottom };
//绘画WebBrowser中的网页内容
//GetHWND()返回WebBrowser容器窗口句柄
HRTEST_E( pViewObject2->Draw(DVASPECT_CONTENT, 1, NULL, NULL, ::GetDC(GetHWND()), hBitmapDC, &rctl, NULL , NULL, 0) );
//写bmp文件
BITMAP stBitmap;
PBYTE npData;
DWORD dwDataSize;
DWORD dwBmpDataSize;
HANDLE hBmpFile;
DWORD dwWritten;
NULLTEST_E( ::GetObjectW( hBitmap, sizeof(stBitmap), (PVOID)&stBitmap ));
NULLTEST_E( npData =
new BYTE[ dwDataSize = ( sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (dwBmpDataSize = ((stBitmap.bmWidth*8+31)/32)*4*stBitmap.bmHeight*3)) ] );
BITMAPFILEHEADER* pBmpFileHeader = (BITMAPFILEHEADER*)(npData);
pBmpFileHeader->bfTyp</span>
<p> <!--<A href="#">http://msnpiki.msnfanatic.com/index.php/Main_Page</A>--></p>
            <div id="ad_f4" class="ad_f4"><script src="/js/2009/ad/ad_f4.js"></script></div>
<div id="ad_f10" class="ad_f10"><script src="/js/2009/ad/ad_f10.js"></script></div><div id="ad_f11" class="ad_f11"><script src="/js/2009/ad_f11.js"></script></div>
       </div>
<div align="center" class="pager w635px"><span id="pagesSpan"> <span id="1">1</span> <a href="156108_2.html">2</a></span></div>
<div class="fh b14 w635px"> 如果图片或页面不能正常显示请<a onClick="#" onMouseOver="this.style.cursor='hand';" class= "redlink"><font color="#990000"><strong>点击这里</strong></font></a> 站内搜索:
<iframe id="baiduframe" marginwidth="0" marginheight="0" scrolling="no"
framespacing="0" vspace="0" hspace="0" frameborder="0" width="280" height="21"
src="http://unstat.baidu.com/bdun.bsc?tn=diybl_pg&cv=0&cid=1061623&csid=541&bgcr=ffffff&urlcr=0000ff&tbsz=180&sropls=2,99&insiteurl=diybl.com&defid=99&kwgp=0&ch=1">
</iframe>
</div>
<div class="toollinks hui"> 【<A href="javascript:window.external.addFavorite(window.location,'MSN协议分析-DIY部落');">收藏此页</a>】【<A
href="http://www.diybl.com/course/webjsh/osgl/5589fdssd.html" target="_blank">BBS社区</A>】【<A href="#comment">发表评论</A>】【<a href="#">返回顶部</a>】【<A
href="javascript:window.close()">关闭</A>】 </div>
<div class="p_bottom">

<a href="/course/3_program/c++/cppjs/20090221/156107.html">上一篇文章:读书笔记本09/02/20</a>
<br>
<a href="/course/3_program/c++/cppjs/20090221/156109.html">下一篇文章:How to use toolbar control on dialog using CToolBar class in VC++</a>
</div>
</div>
<!--content area end!-->
<div class="fc"></div>
<div class="left-contect mtop blue border">
<div class="b14 bold fh left-width">推荐文章</div>
</div>
<div class="left-contect white border recommend">
<div class="tj_l fh20 white">
<UL>

<LI> <a href="http://www.diybl.com/course/3_program/c++/cppjs/20090215/155654.html" target="_blank">关于“基于消息驱动的面向..</a></LI>
<LI> <a href="http://www.diybl.com/course/3_program/c++/cppjs/200836/102845.html" target="_blank">博彦科技软件测试工程师..</a></LI>
<LI> <a href="http://www.diybl.com/course/3_program/c++/cppjs/2008710/132648.html" target="_blank">一个典型网络引擎的设计..</a></LI>
<LI> <a href="http://www.diybl.com/course/3_program/c++/cppjs/2008923/144996.html" target="_blank">__stdcall,__cdecl,_cdecl..</a></LI>
<LI> <a href="http://www.diybl.com/course/3_program/c++/cppjs/20090403/163811.html" target="_blank">删除字符串中所有的空格sp..</a></LI>
<LI> <a href="http://www.diybl.com/course/3_program/c++/cppjs/20090403/163813.html" target="_blank">[dp问题] Girl Love Value..</a></LI>
<LI> <a href="http://www.diybl.com/course/3_program/c++/cppjs/20090303/157261.html" target="_blank">条件编译</a></LI>
<LI> <a href="http://www.diybl.com/course/3_program/c++/cppjs/200867/123367.html" target="_blank">初试指针---原来指针可以..</a></LI>
</UL></div>
<div class="tj_r fh20 white">
<ul>
<li><a href="http://www.diybl.com/course/3_program/c++/cppjs/20090414/165011.html" target="_blank">symbian中使用使用数学函数</a></li>
<li><a href="http://www.diybl.com/course/3_program/c++/cppjs/20071024/79796.html" target="_blank">指向函数的指针的使用</a></li>
<li><a href="http://www.diybl.com/course/3_program/c++/cppjs/20090403/164102.html" target="_blank">VC中越文或其他外文软件..</a></li>
<li><a href="http://www.diybl.com/course/3_program/c++/cppjs/20090201/154709.html" target="_blank">ACE_Reactor中的handle_ou..</a></li>
<li><a href="http://www.diybl.com/course/3_program/c++/cppjs/20090429/166017.html" target="_blank">自定义简单的工具栏类(真..</a></li>
<li><a href="http://www.diybl.com/course/3_program/c++/cppjs/20081117/151503.html" target="_blank"> /proc/目录写</a></li>
<li><a href="http://www.diybl.com/course/3_program/c++/cppjs/2007114/83890.html" target="_blank">职工管理系统</a></li>
<li><a href="http://www.diybl.com/course/3_program/c++/cppjs/2008723/133833.html" target="_blank">关于堆的困惑</a></li>
</ul>
</div>
</div>
<div class="fc"></div>
<div class="left-contect mtop gray border-hui">
<div class="b14 bold fh left-width"><a name="comment"></a>文章评论</div>
</div>
<div class="left-contect border-hui">
       <div id="divComment" class="left-width fh"></div>
</div>
<div class="fc"></div>
<div class="comment_1 mtop border w_l">
<div class="blue fh b14 bold pleft">请您留言</div>
<div class="cleanblock fh22">
昵称:
<input name="tbName" id="tbName" class="input input_comment" type="text" size="15" value="" onclick="this.focus();this.select()"maxlength="20"/>
<br />
            <span style="float:left;">验证码:<input name="tbCode" id="tbCode" class="input input_comment" type="text" size="6" /></span><span id="spanCode" style=" float:left; clear:right; "><img id="Img2" onclick="this.src=this.src" style="display:none;"/></span>
<a href="http://user.diybl.com/register.aspx" target="_blank"><font color=red><br />
注册会员</font></a> <a href="http://user.diybl.com/login.aspx" target="_blank">会员登陆</a> <br />
<textarea name="tbContent" id="tbContent" rows="6" class=" input" style="VERTICAL-ALIGN: text-top; WIDTH:290px; HEIGHT: 7em">
免责声明:本站相关技术文章信息部分来自网络,目的主要是传播更多信息,如果您认为本站的某些信息侵犯了您的版权,请与我们联系,我们会即时妥善的处理,谢谢合作!