WebBrowser控件拖拽的实现
WebBrowser 作为群众喜闻乐见的插件, 一直以好用难写而臭名昭著.
其海量的接口忙的众多死程序员乐不思蜀.
前些天正好需要在WebBrowser中实现文件的拖拽, 遇到一些问题, 后来解决了, 希望和大家分享分享.
俺是菜鸟,大家包涵.
环境: 纯SDK ( 没有用MFC, 因为mfc太方便了,所以显得臃肿,有些问题反而复杂化了 ,所以用SDK模式讲解)
大家知道 WebBrowser 有一个有名的接口叫: IDocHostUIHandler
关于这个接口的详细教学可以参看下面的链接:
http://www.vckbase.com/document/viewdoc/?id=1486
唯一不足之处就是基于MFC, 不过这个接口很容易转换成SDK模式的,很简单.
在IDocHostUIHandler 中有一个函数, GetDropTarget( IDropTarget *pDropTarget,IDropTarget **ppDropTarget)
传说重载这个函数, 然后返回, 可以替换默认的拖拽处理( 默认的拖拽处理是下载这个被拖拽的文件)
在上面的接口教学的文章中, 作者似乎用mfc HTML 模块很容易就实现了这个功能.
可是,很快有人就反映了问题:
http://topic.csdn.net/u/20071130/10/c8fb0fe8-776a-42d3-b340-a5fce0568cda.html
该提问者直到最后,几乎解决问题, 但还是差了一点. 可惜已经结贴,无法再回答他的问题.
实际上对于拖拽的实现, 原理还是COM类的, 在mfc中提供了一个类 , COleDropTarget. 这个类被许多类,比如 CView 所继承.
通过这个类"实现"了拖拽. 我打上引号,是因为事实不竟然.
该类的实现文件在 X : /Program Files/Microsoft Visual Studio 9.0/VC/atlmfc/src/mfc/oledrop2.cpp
下面是一个使用他的教程: (你可以看,也可以直接掠过,因为作用和我们说的关系不大)
http://www.vckbase.com/document/viewdoc/?id=258
(我讨厌MFC的原因是,明明一个简单的事情, 他为了实现一点点的简洁,却使用了非常繁琐的技术,让我头大.)
根据那位同学的思路,其实可以有两种实现.
方法一:
使用 RegisterDragDrop(...) 告诉系统,定义某个窗口为拖拽窗口.
函数原型:
参数 hwnd 是要接受拖拽窗口的句柄.
参数 pDropTarget 是处理拖拽的IDropTarget的指针.
注意 pDropTarget 是要求用户自己实现的.
- WINOLEAPI RegisterDragDrop(
- HWND hwnd, //Handle to a window that can accept drops
- IDropTarget * pDropTarget
- //Pointer to object that is to be target of drop
- );
- HRESULT
- YourDocHostUIHandler::GetDropTarget( IDropTarget *pDropTarget, IDropTarget **ppDropTarget)
- {
- //使用用户定义的拖拽
- return S_OK;
- }
注意RegisterDragDrop参数hwnd是接受拖拽窗口的句柄, 必须是窗口自己,不能是子窗口,不能是父窗口.
许多人应当知道,也许不知道, MFC HTML 中给出的 m_hWnd 其实不是接受拖拽窗口的窗口,而是他的框架窗口.
请使用Sky++查看WebBrowser窗口的组成.
你会发现 m_hWnd 是最外层的窗口, 而实际窗口是一个有名的,类名如雷贯耳的: Internet Explorer_Server 的窗口, 正是这个窗口
才是真正应该接受拖拽的窗口.
前面那位同学尽管使用了 RegisterDragDrop ,但是仍然不能接受拖拽,问题正是他没有注册 Internet Explorer_Server 这个窗口为拖拽, 相反,注册了他的祖父辈窗口, 这样当然无法实现.
当然在MFC中问题被掩盖了, 但是有时候还是会冒出这种问题,当你没有"按照上帝的旨意"去使用mfc的时候.
方法二.
这种方法才是标准的方法, 也非常简单:
- HRESULT
- YourDocHostUIHandler::GetDropTarget( IDropTarget *pDropTarget, IDropTarget **ppDropTarget)
- {
- //使用用户定义的拖拽
- *ppDropTarget = &YourDropTarget;
- return S_OK;
- }
在这个方法中我们告诉WebBrowser,我们使用YourDropTarget代替默认的DropTarget.
欢迎拍砖和提问.
谢谢.
脱离MFC苦海, 返璞归真,回到纯SDK的怀抱吧~