CWebBrowser 中处理回车相应的问题

来源:互联网 发布:054a 知乎 编辑:程序博客网 时间:2024/05/17 07:17
Q:我做了一个mfc程序,其中视图是继承自 CFormView,在 CFormView上呢放置了一个WebBrowser控件,用来显示一个html文件,我在视图的成员函数OnInitialUpdate()中写了如下代码:其中CWebBrowser2 m_htmlShow;
 
运行程序的时候,出现了上述网页,
我想问的是,
本来这个网页里有一个编辑框,供用户输入数据使用,没有集成在我的程序的时候,可以输入换行。可在我的程序里浏览这个网页时候,输入数据却无法换行,不知道是什么原因。
 
A:因为回车键消息被你的窗口拦截了,没给控件处理机会。
Q:请问如何传递回车消息给CWebBrowser2控件??现在是页面里面不响应回车
A:如果是回车的话不调用CDialog::PretranslateMessage,调用CWnd::
 

This   article   may   contain   URLs   that   were   valid   when   originally   published,   but   now   link   to   sites   or   pages   that   no   longer   exist.   To   maintain   the   flow   of   the   article,   we've   left   these   URLs   in   the   text,   but   disabled   the   links.    
  --------------------------------------------------------------------------------   
WebBrowser   Keystroke   Problems    
     
  lot   of   people   have   noticed   that   when   they're   hosting   the   WebBrowser   control   in   MFC,   ATL,   or   standard   C++   applications,   they   sometimes   run   into   trouble   with   certain   keys.   These   keystroke   problems   usually   occur   when   typing   into   intrinsic   controls   such   as   text   boxes   that   reside   on   Web   pages   loaded   by   the   WebBrowser   control.   Usually   these   keys   are   accelerator   keys   such   as   Backspace,   Delete,   and   Tab.   The   problem   is   that   the   intrinsic   controls   on   a   Web   page   do   not   automatically   receive   these   accelerator   keys.   When   the   WebBrowser   control   receives   an   accelerator   key   message,   it   does   not   automatically   pass   it   to   child   controls   on   a   Web   page.   Therefore,   you   must   somehow   let   the   WebBrowser   control   know   that   it   should   pass   these   messages   to   controls   on   your   Web   page.           The   solution   is   always   the   same   whether   you   are   hosting   the   control   in   MFC,   ATL,   or   standard   C++:   call   the   TranslateAcclerator   method   of   the   IOleInPlaceActiveObject   interface   that   is   implemented   by   the   WebBrowser   control.   But   where   and   how   you   should   do   this   is   often   unclear.   Let's   see   how   to   work   around   keystroke   problems   in   MFC,   ATL,   and   standard   C++   applications   that   are   hosting   the   WebBrowser   control.  
   
   
  MFC   Dialogs    
   
          You   can   create   three   types   of   applications   in   MFC:   dialog-based,   single-document   interface   (SDI),   and   multiple-document   interface   (MDI).   Each   type   requires   a   different   solution   to   the   keystroke   problems.  
   
          When   hosting   the   WebBrowser   control   in   an   MFC   dialog-based   application,   the   TranslateAccelerator   method   is   automatically   called   for   you,   so   you   don't   run   into   these   problems   with   keystrokes.   But   understanding   how   MFC   works   when   you   are   hosting   the   WebBrowser   control   in   a   dialog-based   application   will   help   you   diagnose   and   solve   problems   with   keystrokes   in   other   situations.  
   
          In   an   MFC   application,   the   Windows®   message   pump   is   managed   for   you.   In   a   dialog-based   application,   a   method   called   IsDialogMessage   is   invoked   each   time   a   message   enters   the   loop.   Among   other   things,   this   function   will   call   TranslateAccelerator   for   any   controls   in   the   dialog.   IsDialogMessage   will   pass   the   MSG   structure   that   was   received   from   a   call   to   the   GetMessage   function   in   the   message   pump   to   the   TranslateAccelerator   method.   MFC   does   this   by   creating   an   instance   of   a   class   called   COccManager   that   manages   all   the   OLE   controls   on   your   dialog.   The   IsDialogMessage   method   is   a   member   of   the   COccManager   class.    
   
          The   IsDialogMessage   method   first   gets   a   handle   to   the   window   that   has   the   focus.   If   this   window   is   a   control,   the   TranslateAccelerator   method   is   called   on   that   control   to   give   it   a   chance   to   process   the   message.   If   the   window   that   has   the   focus   is   not   a   control,   IsDialogMessage   keeps   calling   the   GetParent   method   until   it   finds   an   ActiveX®   control.   If   it   finds   a   control,   it   calls   TranslateAccelerator   on   it.    
   
   
  MFC   SDI/MDI   Applications    
   
          MFC   SDI/MDI   applications   typically   run   into   problems   with   keystrokes.   Unlike   dialog-based   applications,   IsDialogMessage   is   not   automatically   called   for   you   in   SDI/MDI   applications.   Therefore,   the   way   to   fix   these   keystroke   problems   is   to   call   IsDialogMessage   yourself.   But   where   do   you   call   it?   Each   time   through   the   message   pump,   MFC   gives   your   application   a   chance   to   process   a   message   before   the   message   is   processed   by   the   default   window   procedure.   To   give   you   a   chance   to   process   a   message,   MFC   calls   the   PreTranslateMessage   method,   which   is   a   virtual   method   of   the   CWnd   class.   If   you   implement   this   method   in   any   of   your   CWnd-derived   classes,   it   will   be   called   automatically   by   MFC.    
   
          CWinApp   also   has   a   PreTranslateMessage,   which   means   that   you   can   override   this   in   the   CWinApp-derived   class   for   your   application   as   well.  
   
          An   MFC   SDI/MDI   application   typically   has   a   view   class   that   derives   from   CView.   CView   in   turn   derives   from   CWnd.   Therefore,   if   you   implement   PreTranslateMessage   in   your   view   class,   through   the   wonders   of   polymorphism   your   implementation   of   PreTranslateMessage   will   be   called   by   MFC.   So   to   solve   the   keystroke   problems   in   an   MFC   SDI/MDI   application,   all   you   have   to   do   is   call   IsDialogMessage   from   within   PreTranslateMessage   like   this:    
     
   
   
  BOOL   CMyView::PreTranslateMessage(MSG*   pMsg)  
    {  
            if   (IsDialogMessage(pMsg))  
                    return   TRUE;  
            else  
                    return   CWnd::PreTranslateMessage(pMsg);  
    }  
   
  Knowledge   Base   article   Q165074   (http://support.microsoft.com/support/kb/articles/q165/0/74.asp)   explains   this   in   detail.    
   
          But   sometimes   it   does   not   work.   For   instance,   if   the   user   presses   Tab,   you   would   expect   the   focus   to   be   shifted   between   all   controls   in   your   application   as   well   as   controls   in   the   WebBrowser   window.   Say   that   you   have   an   application   with   an   edit   box   in   which   you   can   enter   a   URL.   If   focus   is   set   to   that   edit   box,   each   time   you   press   Tab   the   focus   will   be   shifted   around   in   your   application   window,   but   focus   will   never   move   to   controls   on   the   Web   page   inside   of   the   WebBrowser   control   window.    
   
          To   make   this   work,   it   may   be   necessary   to   pass   the   Tab   key   directly   to   the   WebBrowser   control.   Call   TranslateAccelerator   in   the   PreTranslateMessage   method   for   your   CMainFrame   class   (see   Figure   1).   ID_URL_NAME   is   the   resource   ID   of   an   edit   control   in   the   application   that   is   used   to   enter   a   URL.  
   
          If   you   are   hosting   the   WebBrowser   control   in   a   DLL,   calling   TranslateAccelerator   is   a   bit   more   involved.   Please   see   Knowledge   Base   article   (Q175502)   for   more   information.  
   
   
  ATL   and   Standard   C++    
   
          When   hosting   the   WebBrowser   control   in   either   an   ATL   application   or   one   written   in   standard   C++,   the   solution   is   sometimes   rather   simple.   All   you   have   to   do   is   query   the   WebBrowser   control   for   the   IOleInPlaceActiveObject   interface   and   call   its   TranslateAccelerator   method.   Typically,   you   call   this   method   in   your   handler   function   for   the   WM_KEYDOWN   message.   Figure   2   contains   ATL   and   standard   C++   code   that   shows   how   to   call   the   TranslateAccelerator   method   to   fix   the   keystroke   problem.  
   
          Sometimes   your   application   will   not   automatically   be   sent   WM_KEYDOWN   messages   for   accelerator   keys.   In   this   case,   you   must   manually   send   this   message   to   your   window.   Here   is   a   sample   message   pump   that   sends   all   keyboard   messages   to   the   window   of   your   application:    
   
  while   (GetMessage(&msg,   NULL,   0,   0))  
    {  
          TranslateMessage(&msg);  
     
          //   Send   all   keyboard   messages   to   the   window   of   your  
          //   application.     hwndApp   is   the   window   handle   of  
          //   your   application.  
          //  
          if   (msg.message   >=   WM_KEYFIRST   &&   msg.message   <=   WM_KEYLAST)  
                ::SendMessage(hwndApp,   msg.message,   msg.wParam,   msg.lParam);  
                       
          DispatchMessage(&msg);  
    }  
   
  Win32   SDK   Modal   Dialogs    
   
          The   Win32&reg;   dialog   box   functions   (DialogBox,   DialogBoxIndirect,   DialogBoxIndirectParam,   and   DialogBoxParam)   are   very   helpful   when   creating   modal   dialog   boxes.   They   take   care   of   handling   the   message   pump   for   your   application.   However,   this   creates   a   problem   when   you   are   trying   to   fix   these   keystroke   problems.   Where   do   you   put   the   call   to   TranslateAccelerator?    
   
          Unfortunately,   if   you   need   to   host   the   WebBrowser   control   in   a   dialog,   it   is   not   a   good   idea   to   use   these   functions   to   create   the   modal   dialog.   The   reason   for   this   is   simple.   When   focus   is   set   to   a   control   on   a   dialog,   the   control   is   sent   the   WB_GETDLGCODE   message.   Controls   typically   respond   to   this   message   by   returning   DLGC_WANTALLKEYS.   Then   the   control   is   given   a   chance   to   handle   all   keys   entered   by   the   user.    
   
          The   WebBrowser   control   returns   DLGC_WANTARROWS|   DLGC_WANTCHARS   in   response   to   the   WM_GETDLGCODE   message.   This   means   that   it   will   not   handle   certain   keys   such   as   Tab   and   Delete.   Therefore,   to   work   around   these   keystroke   problems,   you   need   to   have   control   of   the   message   pump   so   that   you   can   call   TranslateAccelerator.    
   
  For   these   reasons,   I   recommend   that   you   do   not   use   the   Win32   dialog   box   functions   to   create   your   modal   dialog   box.   Create   the   dialog   window   yourself   so   you   have   control   of   the   message   pump.   You   can   use   MFC   or   ATL   to   create   this   dialog.   In   addition,   if   you   just   need   a   modal   dialog   that   displays   a   Web   page,   you   can   use   the   DHTML   showModalDialog   function   provided   by   Microsoft   Internet   Explorer.  
   
          There   is   one   other   option   you   can   use   to   fix   these   problems,   instead   of   creating   the   dialog   window   manually.   You   can   use   a   Windows   hook.   This   will   enable   you   to   retrieve   all   keyboard   messages   for   the   current   thread   and   then   call   TranslateAccelerator   so   that   accelerator   keys   will   be   processed.   There   is   one   problem   with   this   approach,   however.   When   the   focus   is   on   the   WebBrowser   control   and   you   attempt   to   change   focus   between   controls   on   the   Web   page   by   pressing   tab,   the   focus   will   never   leave   the   WebBrowser   window.   This   means   that   you   can   Tab   between   controls   on   the   Web   page   or   between   controls   in   your   application,   but   not   both.    
   
  There   are   four   steps   required   to   set   up   a   Windows   hook   to   work   around   the   keystroke   problems   in   a   Win32   SDK   dialog.   First,   declare   your   hook   procedure   in   your   header   file.    
   
  static   LRESULT   CALLBACK   GetMsgHookProc(int   nCode,   WPARAM   wParam,   LPARAM   lParam);  
   
  Next,   set   your   hook   procedure   during   initialization   by   calling   SetWindowsHookEx.   Also,   make   sure   to   save   the   returned   hook   handle   so   that   you   can   unhook   the   procedure   when   you   are   shutting   down   or   when   it   is   no   longer   needed.     

  //   Declare   this   global   handle   in   one   of   your   project   files.   
    HHOOK   g_hook;  
     
    //   Place   this   code   inside   an   initialization    
    //   method   in   your   implementation   file   (.cpp)  
    g_hook   =   SetWindowsHookEx(WH_GETMESSAGE,   GetMsgHookProc,  
                                                        NULL,   GetCurrentThreadId());  
   
  After   that,   implement   your   hook   procedure   and   call   TranslateAccelerator.    
   
    LRESULT   CALLBACK   CYourClass::GetMsgHookProc(int   nCode,   WPARAM   wParam,  
                                                                                            LPARAM   lParam)  
    {  
          LPCKFSEARCH   pThis   =   (LPCKFSEARCH)GetWindowLong(hwndMain,   DWL_USER);  
     
          if   (pThis   &&   nCode   >=   0)  
          {  
                MSG*   pMsg   =   (MSG*)lParam;  
     
                //   m_pOleInPlaceActObj   is   an   IOleInPlaceActiveObject  
                //   data   member   of   the   view   class   that   is   initialized  
                //   after   the   WebBrowser   control   is   loaded.  
     
                if   (pThis->m_pOleInPlaceActObj)  
                      pThis->m_pOleInPlaceActObj->TranslateAccelerator(pMsg);  
     
                //   This   causes   the   tab   to   work   in   the   WebBrowser   window.   If   you   do   not   do  
                //   this,   tabbing   will   happen   in   the   dialog   only.     You   have   the   choice   of  
                //   tabbing   in   the   dialog   or   the   WebBrowser   window,   not   both.  
     
                if   (pMsg->wParam   ==   VK_TAB)  
                      ZeroMemory(pMsg,   sizeof(MSG));  
          }  
     
          return   CallNextHookEx(g_hook,   nCode,   wParam,   lParam);  
    }  
   
  Finally,   when   your   application   is   shutting   down   or   when   you   no   longer   need   the   hook,   unhook   the   procedure.    
  UnhookWindowsHookEx(g_hook);  
   
  Explorer   Bars    
   
          When   hosting   the   WebBrowser   control   in   Explorer   bars   (Explorer   bands,   comm   bands,   or   desk   bands),   you   need   to   do   a   little   more   to   fix   keystroke   problems.   You   still   have   to   call   TranslateAccelerator,   but   there   are   also   issues   regarding   focus.   The   WebBrowser   control   has   to   know   that   your   browser   band   currently   has   the   focus   or   the   accelerator   keys   will   not   be   processed.    
   
          It   is   very   common   for   people   to   forget   that   they   have   to   implement   IOleControlSite   when   hosting   a   control.   This   is   true   when   hosting   the   WebBrowser   control   in   a   standard   application   or   when   hosting   it   in   an   Explorer   bar.   You   must   implement   this   interface   because   its   OnFocus   method   is   called   when   focus   is   set   to   the   WebBrowser   control.   When   this   method   is   called,   you   must   query   the   WebBrowser   control   for   the   IInputObjectSite   interface   and   call   its   OnFocusChangeIS   method.   This   tells   the   WebBrowser   control   that   your   Explorer   bar   now   has   the   focus.    
   
  Here   is   some   ATL-based   code   that   demonstrates   how   to   call   the   OnFocusChangeIS   method:    
   
  STDMETHODIMP   CWBExplorerBar::OnFocus(BOOL   fGotFocus)  
    {  
          if   (m_pSite)  
                m_pSite->OnFocusChangeIS(static_cast<IInputObject*>(this),   fGotFocus);  
                return   S_OK;  
    }  
   
          Note   that   m_pSite   is   a   data   member   of   type   IInputObjectSite   that   was   retrieved   from   the   WebBrowser   control   in   the   Explorer   bar's   IObjectWithSite::SetSite   method.   Also,   note   that   the   Explorer   bar   has   to   implement   the   IInputObject   interface.  
   
          Now,   whenever   a   key   is   pressed,   three   things   occur.   First,   the   Explorer   bar's   IInputObject::HasFocusIO   method   is   called   to   see   if   the   Explorer   bar   currently   has   the   focus.   The   Explorer   bar's   implementation   of   this   method   should   determine   if   the   WebBrowser   control   that   the   Explorer   bar   is   hosting   has   the   focus   or   if   any   of   the   WebBrowser   control's   children   have   the   focus.   The   HasFocusIO   method   should   return   S_OK   if   the   WebBrowser   control   or   one   of   its   children   has   the   focus;   otherwise   it   should   return   S_FALSE.   Here   is   the   code   for   this   method.    
   
  STDMETHODIMP   CWBExplorerBar::HasFocusIO(void)  
    {  
          HWND   hwnd   =   GetFocus();  
          HWND   hwndTmp   =   m_hwndWB;     //   HWND   of   the   WebBrowser   control  
     
          //   See   if   the   focus   has   been   set   to   any   of   the   children  
          while   (hwnd   &&   hwndTmp)  
          {  
                if   (hwnd   ==   hwndTmp)   return   S_OK;  
                hwndTmp   =   ::GetWindow(hwndTmp,   GW_CHILD);  
          }  
     
          return   S_FALSE;  
    }  
   
          The   Explorer   bar's   IInputObject::UIActivateIO   method   is   called   next   to   tell   the   Explorer   bar   that   it   is   being   activated.   The   Explorer   bar's   implementation   of   this   method   either   UI   activates   or   in-place   activates   the   WebBrowser   control   depending   on   one   of   the   input   values   to   this   method.   In   Figure   3,   m_pIOleObject   is   a   pointer   to   an   instance   of   IOleObject   that   was   retrieved   from   the   WebBrowser   control   in   the   SetSite   method   of   this   Explorer   bar.    
   
          Finally,   the   Explorer   bar's   IInputObject::TranslateAcceleratorIO   method   is   called.   Here   the   Explorer   bar   passes   the   keystroke   to   the   hosted   WebBrowser   control   by   calling   IOleInPlaceActiveObject::TranslateAccelerator.   This   causes   accelerators   such   as   the   Backspace   and   the   Delete   keys   to   be   processed   by   the   WebBrowser   control   (see   Figure   4).    
   
          The   steps   and   associated   code   that   I   just   showed   you   may   be   a   little   confusing   at   first.   To   better   understand   how   browser   bands   work   and   how   to   deal   with   keystroke   problems   of   this   sort,   pick   up   a   copy   of   my   book,   Programming   Microsoft   Internet   Explorer   5.0   (Microsoft   Press,   1999).   This   book   should   be   in   stores   very   soon.  
   
   
  Conclusion    
   
          Keystroke   problems   that   occur   when   hosting   the   WebBrowser   control   are   one   of   the   hardest   problems   to   resolve.   The   solution   is   always   to   call   the   TranslateAccelerator   method   of   IOleInPlaceActiveObject.   But   since   every   application   is   different   and   written   with   different   development   libraries,   the   method   used   to   fix   keystroke   problems   is   going   to   differ.   If   you   follow   the   steps   in   this   article,   you   should   be   able   to   solve   most   keystroke   problems   when   hosting   the   WebBrowser   control.  
   
   
  This   article   is   adapted   from   the   upcoming   book   Programming   Microsoft   Internet   Explorer   5.0   by   Scott   Roberts   (Microsoft   Press,   Spring   1999).  
   
   
  From   the   April   1999   issue   of   Microsoft   Internet   Developer.  
   
  --------------------------------------------------------------------------------   

原创粉丝点击