首页 > 代码库 > Duilib嵌入CEF禁止浏览器响应拖拽事件

Duilib嵌入CEF禁止浏览器响应拖拽事件

在开发中有一个需求,拖拽外部文件到客户端,然后客户端响应WM_DROPFILES消息,在拖拽消息里处理一下业务,最后把处理结果显示到客户区html中,但实际中发现当拖拽文件到客户区,浏览器首先处理了拖拽事件,外层的Win32窗口无法捕捉到拖拽消息,因此要想实现此操作,刚开始我想了一个本办法,在客户区最外层罩了一个透明的Win32原生窗口,这样拖拽文件时,在最外层透明窗口的WM_DROPFILES消息中处理具体业务,最后用C++调用js函数,在页面显示处理结果。

 

技术分享

 

方法一:

透明窗口

LayeredWindow.h

 1 #ifndef _LAYEREDWINDOW_H_
 2 #define _LAYEREDWINDOW_H_
 3 
 4 class CLayeredWindow :public WindowImplBase
 5 {
 6 public:
 7     CLayeredWindow();
 8     ~CLayeredWindow();
 9 
10 public:
11     LPCTSTR GetWindowClassName() const;    
12 
13     virtual void OnFinalMessage(HWND hWnd);
14 
15     virtual LRESULT ResponseDefaultKeyEvent(WPARAM wParam);
16 
17     virtual UILIB_RESOURCETYPE GetResourceType() const;
18 
19     virtual CDuiString GetSkinFile();
20 
21     virtual CDuiString GetSkinFolder();
22 
23     virtual CControlUI* CreateControl(LPCTSTR pstrClass);
24 
25     virtual void InitWindow();
26 
27     virtual void Notify(TNotifyUI& msg);
28 
29     virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
30 
31     virtual void OnClick(TNotifyUI& msg);
32 
33     void OnPrepare();
34 };
35 #endif//_LAYEREDWINDOW_H_

LayeredWindow.cpp

  1 #include "stdafx.h"
  2 #include "LayeredWindow.h" 
  3 
  4 CLayeredWindow::CLayeredWindow()
  5 {
  6 
  7 }
  8 
  9 CLayeredWindow::~CLayeredWindow()
 10 {
 11 
 12 }
 13 
 14 LPCTSTR CLayeredWindow::GetWindowClassName() const
 15 {
 16     return _T("LayeredWindow");
 17 }
 18 
 19 void CLayeredWindow::OnFinalMessage(HWND hWnd)
 20 {
 21     CWindowWnd::OnFinalMessage(hWnd);
 22 }
 23 
 24 LRESULT CLayeredWindow::ResponseDefaultKeyEvent(WPARAM wParam)
 25 {
 26     if (wParam == VK_RETURN)
 27     {
 28         return FALSE;
 29     }
 30     else if (wParam == VK_ESCAPE)
 31     {
 32         return TRUE;
 33     }
 34     return FALSE;
 35 }
 36 
 37 DuiLib::UILIB_RESOURCETYPE CLayeredWindow::GetResourceType() const
 38 {
 39     return UILIB_FILE;
 40 }
 41 
 42 DuiLib::CDuiString CLayeredWindow::GetSkinFile()
 43 {
 44     return _T("LayeredDlg.xml");
 45 }
 46 
 47 DuiLib::CDuiString CLayeredWindow::GetSkinFolder()
 48 {
 49     return _T("");
 50 }
 51 
 52 CControlUI* CLayeredWindow::CreateControl(LPCTSTR pstrClass)
 53 {
 54     return NULL;
 55 }
 56 
 57 void CLayeredWindow::InitWindow()
 58 {
 59     
 60     //加入WS_EX_LAYERED扩展属性
 61     SetWindowLong(this->GetHWND(),GWL_EXSTYLE,
 62         GetWindowLong(this->GetHWND(),GWL_EXSTYLE)^0x80000);
 63     HINSTANCE hInst = LoadLibrary(L"User32.DLL"); 
 64     if(hInst) 
 65     { 
 66         typedef BOOL (WINAPI *MYFUNC)(HWND,COLORREF,BYTE,DWORD); 
 67         MYFUNC fun = NULL;
 68         //取得SetLayeredWindowAttributes函数指针 
 69         fun=(MYFUNC)GetProcAddress(hInst, "SetLayeredWindowAttributes");
 70         if(fun)fun(this->GetHWND(),0,1,2); 
 71         FreeLibrary(hInst); 
 72     }
 73 }
 74 
 75 
 76 void CLayeredWindow::OnPrepare()
 77 {
 78 
 79 }
 80 
 81 void CLayeredWindow::Notify(TNotifyUI& msg)
 82 {
 83     if( msg.sType == _T("windowinit") ) OnPrepare();
 84 
 85     if(msg.sType == _T("click"))
 86     {
 87     }
 88 
 89     WindowImplBase::Notify(msg);
 90 }
 91 
 92 void CLayeredWindow::OnClick(TNotifyUI& msg)
 93 {
 94     __super::OnClick(msg);
 95 }
 96 
 97 //禁用双击标题栏窗口最大化
 98 LRESULT CLayeredWindow::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
 99 {
100     LRESULT lRes = 0;
101     BOOL bHandled = TRUE;
102     switch( uMsg)
103     {
104     case WM_NCLBUTTONDBLCLK:
105         {
106             return 0;
107         }
108         break;
109     default:
110         bHandled = FALSE;
111     }
112     return WindowImplBase::HandleMessage(uMsg,wParam,lParam);
113 }

1.在主窗口InitWindow函数里面创建透明窗口

2.在主窗口的WM_SIZE 和 WM_MOVE消息中移动这个透明窗口,让其跟随主窗口移动

方法二:

 最好的办法是取消CEF浏览器对拖拽事件的处理,这样让外层Win32窗口处理拖拽事件

研究了一下CEF源码,发现有一个类CefDragHandler,是浏览器拖拽事件,可以让你自己的CLientHandler继承这个类,然后重写它里面的虚函数

virtual bool OnDragEnter(CefRefPtr<CefBrowser>browser,CefRefPtr<CefDragData> dragData,CefDragHandler::DragOperationsMask mask)
{

    CEF_REQUIRE_UI_THREAD();

    // Forbid dragging of link URLs.
    if (mask & DRAG_OPERATION_LINK)
    return true;

   return false;

}

让其返回true,取消拖拽响应,刚开始只重写了这个虚函数,但在拖拽时还是无法禁止,最后发现少写一个获取拖拽事件处理器

// CefClient 事件处理器,如果没有对应处理器则默认使用内部处理器

virtual CefRefPtr<CefDragHandler> GetDragHandler()  {
        return this;
    }

加上这个函数后,才能真正禁止拖拽事件

Duilib嵌入CEF禁止浏览器响应拖拽事件