扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
IDocHostUIHandler::GetDropTarget Method——Called by MSHTML when it is used as a drop target. This method enables the host to supply an alternative IDropTarget interface.
STDMETHODIMP CHtmlControlSite::XDocHostUIHandler::GetDropTarget(LPDROPTARGET pDropTarget, LPDROPTARGET* ppDropTarget){METHOD_PROLOGUE_EX_(CHtmlControlSite, DocHostUIHandler)*ppDropTarget = g_pDropTarget;//将自定义的实现告知MSHTML引擎return S_OK;}
IHTMLDataTransfer MembersclearData——Removes one or more data formats from the clipboard through dataTransfer or clipboardData object.dropEffect——Sets or retrieves the type of drag-and-drop operation and the type of cursor to display.effectAllowed——Sets or retrieves, on the source element, which data transfer operations are allowed for the object.getData——Retrieves the data in the specified format from the clipboard through the dataTransfer or clipboardData objects.setData——Assigns data in a specified format to the dataTransfer or clipboardData object.
HRESULT CHtmlDocument2::OnInvoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,DISPPARAMS * pdispparams, VARIANT * pvarResult,EXCEPINFO * pexcepinfo,UINT * puArgErr){......//如果只是要设置鼠标拖拽效果的话,这个事件可以不处理case DISPID_HTMLELEMENTEVENTS_ONDRAGSTART :{OnDragStart();break;}//重点在这里case DISPID_HTMLELEMENTEVENTS_ONDRAGOVER :{OnDragOver();break;}case DISPID_HTMLELEMENTEVENTS_ONDROP :{OnDrop();break;}......}void CHtmlDocument2::OnDragOver(void){SetDragEffect(); //设置鼠标拖拽效果}void CHtmlDocument2::SetDragEffect(void){CComQIPtr<IHTMLWindow2> pWindow;CComQIPtr<IHTMLEventObj> pEventObj;CComQIPtr<IHTMLEventObj2> pEventObj2;CComQIPtr<IHTMLElement> pElement;HRESULT hr = m_spHtmlObj->get_parentWindow( &pWindow );hr = pWindow->get_event( &pEventObj );//ondragover发生时IE的默认行为是“没有鼠标拖拽效果”。//将IHTMLEventObj的返回值设为false即可取消该事件的默认行为,所以执行完下面这句话,拖拽效果就出现了。AllowDisplayDragCursor(pEventObj, FALSE);CComBSTR bstrTagName;pEventObj->get_srcElement(&pElement); //获得当前HTML ElementpElement->get_tagName(&bstrTagName);if ( IsEditArea(bstrTagName) ) //根据Tag Name判断是否鼠标位于输入框,以便设置焦点使得光标随鼠标移动{CComQIPtr<IHTMLElement2> pElement2;if ( SUCCEEDED(pElement->QueryInterface(IID_IHTMLElement2, (void **) &pElement2 ))&& pElement2 ){pElement2->focus();}//默认情况下,当拖拽文档到输入框时,鼠标会变成拖拽的光标,所以这里使用IE的默认行为。AllowDisplayDragCursor(pEventObj, TRUE);}}BOOL CHtmlDocument2::IsEditArea(CComBSTR bstrTagName){return bstrTagName == "INPUT" || bstrTagName == "TEXTAREA";}void CHtmlDocument2::AllowDisplayDragCursor(CComQIPtr<IHTMLEventObj> pEventObj, BOOL bAllow){VARIANT v;v.vt = VT_BOOL;v.boolVal = !bAllow ? VARIANT_FALSE : VARIANT_TRUE;pEventObj->put_returnValue(v);}void CHtmlDocument2::OnDrop(void){CComQIPtr<IHTMLWindow2> pWindow;CComQIPtr<IHTMLEventObj> pEventObj;CComQIPtr<IHTMLEventObj2> pEventObj2;CComQIPtr<IHTMLElement> pElement;CComQIPtr<IHTMLDataTransfer> pdt; //此处演示如何使用IHTMLDataTransferHRESULT hr = m_spHtmlObj->get_parentWindow( &pWindow );hr = pWindow->get_event( &pEventObj );hr = pEventObj->QueryInterface(IID_IHTMLEventObj2, (void **) &pEventObj2 );hr = pEventObj2->get_dataTransfer(&pdt);CComBSTR bstrFormat = "URL"; //首先尝试获取URLVARIANT Data;hr = pdt->getData(bstrFormat, &Data);if ( Data.vt != VT_NULL ){ //获取成功,拖放的对象是UrlDoOpenUrl(CString(Data.bstrVal));}else{ //否则尝试获取选中的文本bstrFormat = "Text";hr = pdt->getData(bstrFormat, &Data);if ( Data.vt != VT_NULL ){ //获取成功,拖放的内容是文本CComBSTR bstrTagName;pEventObj->get_srcElement(&pElement);pElement->get_tagName(&bstrTagName);if ( IsEditArea(bstrTagName) ){//Drop target是输入框,不做任何操作,由IE进行默认处理return;}else{ //否则我们自己处理文本,或保存,或检测是否链接后打开,等等DoProcessText(CString(Data.bstrVal));//Process the text}}else{ //既不是链接,也不是文本,可认为是来自外部(如Windows Shell)的文件拖放DoOnDropFiles(pdt);}}}//演示如何从IHTMLDataTransfer得到IDataObjectvoid CHtmlDocument2::DoOnDropFiles(CComQIPtr<IHTMLDataTransfer> pDataTransfer)
{CComQIPtr<IServiceProvider> psp;CComQIPtr<IDataObject> pdo;if ( FAILED(pDataTransfer->QueryInterface(IID_IServiceProvider, (void **) &psp)) ){return;}if ( FAILED(psp->QueryService(IID_IDataObject, IID_IDataObject, (void **) &pdo)) ){return;}COleDataObject DataObject;DataObject.Attach(pdo);......}
HRESULT GetDropTarget( IDropTarget *pDropTarget, IDropTarget **ppDropTarget);
参数说明
pDropTarget
[in] Pointer to an IDropTarget interface for the current drop target object supplied by MSHTML.
ppDropTarget
[out] Address of a pointer variable that receives an IDropTarget interface pointer for the alternative drop target object supplied by the host.
想到了吗?解决问题的关键就在于第一个参数pDropTarget。相信很多浏览器在处理的时候都忽略掉了第一个参数而只是将自己的实现通过第二个参数告知MSHTML,因而丢失了IE缺省的行为。既然如此,将缺省的IDropTarget接口的指针保存下来,在适当的时候调用,不就能够保留IE的原始拖放行为了吗?
//构造函数,传入参数即是从GetDropTarget得到的那个pDropTarget,它是MSHTML的缺省实现CBrowserDropTarget::CBrowserDropTarget(IDropTarget *pOrginalDropTarget): m_bDragTextToInputBox(FALSE)//这个布尔变量用来判断是否正在向InputBox拖拽文字, m_pOrginalDropTarget(pOrginalDropTarget)//m_pOrginalDropTarget用来保存MSHTML的缺省实现{}STDMETHODIMP CBrowserDropTarget::DragEnter(/* [unique][in] */IDataObject __RPC_FAR *pDataObj,/* [in] */ DWORD grfKeyState,/* [in] */ POINTL pt,/* [out][in] */ DWORD __RPC_FAR *pdwEffect){//调用缺省的行为return m_pOrginalDropTarget->DragEnter(pDataObj, grfKeyState, pt, pdwEffect);}STDMETHODIMP CBrowserDropTarget::DragOver(/* [in] */ DWORD grfKeyState,/* [in] */ POINTL pt,/* [out][in] */ DWORD __RPC_FAR *pdwEffect){//在网页内拖拽文字时这个值是DROPEFFECT_COPY(拖拽的文字不属于输入框中)//或DROPEFFECT_COPY | DROPEFFECT_MOVE(拖拽的文字是输入框中的文字)DWORD dwTempEffect = *pdwEffect;//接下来调用IE的缺省行为HRESULT hr = m_pOrginalDropTarget->DragOver(grfKeyState, pt, pdwEffect);//判断是否是往输入框拖拽文字m_bDragTextToInputBox = IsDragTextToInputBox(dwOldEffect, *pdwEffect);if ( !m_bDragTextToInputBox ){//不是往输入框拖拽文字,则使用原始的拖拽效果。否则和IE的缺省效果一样——也就是没有效果*pdwEffect = dwTempEffect;}return S_OK;}//根据调用缺省行为前后的Effect值判断是否是往输入框拖拽文字BOOL CBrowserDropTarget::IsDragTextToInputBox(DWORD dwOldEffect, DWORD dwNewEffect){//如果是把非输入框中文字往输入框拖动,则dwOldEffect与dwNewEffect相等,都是DROPEFFECT_COPYBOOL bTextSelectionToInputBox = ( dwOldEffect == DROPEFFECT_COPY )&& ( dwOldEffect == dwNewEffect );//如果是把文字从一个输入框拖到另一个输入框,则dwOldEffect为DROPEFFECT_COPY | DROPEFFECT_MOVE,//而dwNewEffect的值可能为DROPEFFECT_MOVE(默认情况),也可能为DROPEFFECT_COPY(按下Ctrl键时)BOOL bInputBoxToInputBox = ( dwOldEffect == (DROPEFFECT_COPY | DROPEFFECT_MOVE) )&& ( dwNewEffect == DROPEFFECT_MOVE || dwNewEffect == DROPEFFECT_COPY );//来自Microsoft Word的拖拽特殊一些,dwOldEffect是所有效果的组合值BOOL bMSWordToInputBox =( dwOldEffect == (DROPEFFECT_COPY | DROPEFFECT_MOVE | DROPEFFECT_LINK) )&& ( dwNewEffect == DROPEFFECT_MOVE || dwNewEffect == DROPEFFECT_COPY );//来自Edit Plus的拖拽过也特殊一些,dwOldEffect是个负数(怀疑是Edit Plus的拖拽实现有问题)BOOL bEditPlusToInputBox = ( dwOldEffect < 0 )&& ( dwNewEffect == DROPEFFECT_MOVE || dwNewEffect == DROPEFFECT_COPY );//也许还有些例外,可再添加......return bTextSelectionToInputBox || bInputBoxToInputBox || bMSWordToInputBox || bEditPlusToInputBox;}STDMETHODIMP CBrowserDropTarget::DragLeave(){//调用缺省的行为return m_pOrginalDropTarget->DragLeave();}STDMETHODIMP CBrowserDropTarget::Drop(/* [unique][in] */ IDataObject __RPC_FAR *pDataObj,/* [in] */ DWORD grfKeyState,/* [in] */ POINTL pt,/* [out][in] */ DWORD __RPC_FAR *pdwEffect){if ( m_bDragTextToInputBox ){//是文字拖放,调用IE的缺省行为return m_pOrginalDropTarget->Drop(pDataObj, grfKeyState, pt, pdwEffect);}//否则是拖放链接、图片、文件等,按常规的IDataObject处理方式......return S_OK;}
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者