Using MFC to customize and extend the browser (JavaScript interacts with C + +)

Source: Internet
Author: User
Tags microsoft c

Original address: http://www.vckbase.com/document/viewdoc/?id=1486

customization and extension of the browser
Li Hanpeng

Download source code
This article is divided into the following chapters:

    • Objective
    • Using the browser in MFC
    • How to expand or customize your browser
    • Customizing the right mouse button popup menu
    • Implementing script extensions (very important external interfaces)
    • How to invoke a function in a Web page script in C + + code
    • Customizing the title of a message box
    • How to customize and modify the HTTP request headers that the browser sends to the Web server
    • How to modify the browser ID
    • Get rid of annoying exception warnings
    • How to handle drag and drop in the browser
    • How to prohibit the selection of page elements
    • Other

Preface
Because I often in the development of the program to embed the browser, in order to meet their own needs often to expand and customize the browser, to solve these problems need to find information on the Internet and learning process, I think many developers may encounter the same problem, close-up this article, for your reference.
using the browser in MFC
In MFC, Microsoft has provided us with the CHtmlView, CDHtmlDialog class to make our program easy to embed browser and browser development two times, which is more convenient than the direct use of WebBrowser control, So the browser issues discussed in this article are all about CHtmlView. The article will refer to a class Clhphtmlview, which is a derived class of CHtmlView, and the extensions or customizations mentioned in the article will be implemented on the Clhphtmlview class (or derived class).
how to expand or customize your browser
The browser defines some extension interfaces (such as IDocHostUIHandler can customize the behavior of the browser interface) for developers to customize and extend. When needed, the browser will query these interfaces to his control site, and the corresponding interfaces in the control site can be extended accordingly. In the MFC7.01 class library, the control site used by CHtmlView is CHtmlControlSite, only the interface IDocHostUIHandler is implemented in the CHtmlControlSite class, and more expansion interfaces are implemented. You must replace CHtmlControlSite with a custom control station class, and the class Cdochostsite mentioned below is a custom control station class.
For an introduction to the interface, please refer to:

How do I get a custom control site to replace the default control site? In MFC7.0, you simply overload the CHtmlView virtual function Createcontrolsite:

BOOL clhphtmlview::createcontrolsite (COleControlContainer * Pcontainer,  

VC6.0 to replace the control station is more complex, this is not discussed here, if you need 6.0 version of the Please send me an email to [email protected].
Customizing the right mouse button popup menu
To customize the browser's right-click popup menu, you must implement the IDocHostUIHandler2 interface in your custom control site class, and IE version is 5.5 or higher. Invoking the Onshowcontextmenu virtual function of the browser class in the ShowContextMenu method of the interface IDocHostUIHandler2, we overload this virtual function with the derived class of the browser class to enable the customization of the right-click menu, see Code

HRESULT Cdochostsite::xdochostuihandler::showcontextmenu (DWORD DwID,                                                          Point * ppt, IUnknown * pcmdtreserved, IDispatch * pdispreserved) {method_prologue (cdochostsite, Dochostuihandler); return PT His->m_pview->onshowcontextmenu (DwID, PPT, pcmdtreserved,pdispreserved);                                         } HRESULT Clhphtmlview::onshowcontextmenu (DWORD DwID, lppoint ppt, Lpunknown pcmdtreserved, Lpdispatch pdispreserved) {H  result = S_FALSE; Switch (m_contextmenumode) {case nocontextmenu://no menu result=s_ok, break, case defaultmenu://default menu break, Case textselecti ononly://only the text selection menu if (! ( DwID = = Context_menu_textselect | | DwID = = Context_menu_control)) Result=s_ok; Break Case custommenu://the custom menu if (dwid!=context_menu_textselect) Result=onshowcustomcontextmenu (ppt,pcmdtreserved,pdispreserved); Break } return result; }

Enumeration types defined in Clhphtmlview context_menu_mode four types of custom right-click popup menus

The type of the right-click menu is set by Clhphtmlview's function Setcontextmenumode. If the right-click popup menu is a "custom menu" type, we can simply overload the Onshowcustomcontextmenu virtual function in a derived class of Clhphtmlview, where the following code Cdemoview is a derived class of Clhphtmlview

HRESULT Cdemoview::onshowcustomcontextmenu (lppoint ppt, Lpunknown pcmdtreserved,lpdispatch pdispreserved) {if (ppt== NULL) | | (pcmdtreserved==null) | | (Pcmdtreserved==null))  return S_OK; HRESULT hr=0;     Iolewindow *olewnd=null; Hr=pcmdtreserved->queryinterface (Iid_iolewindow, (void**) &olewnd); if ((hr! = S_OK) | | (Olewnd = = NULL))  return S_OK; HWND Hwnd=null; Hr=olewnd->getwindow (&hwnd); if ((HR!=S_OK) | | | (Hwnd==null))  {olewnd->release (); return S_OK;} Ihtmlelementptrpelem=null; hr = Pdispreserved->queryinterface (iid_ihtmlelement, (void**) &pelem);  if (hr! = S_OK) {olewnd->release (); return S_OK;}  Ihtmlelementptrpparentelem=null; _bstr_ttagid;  BOOL go=true;  PELEM->GET_ID (&tagid.getbstr ()); while (Go && tagid.length () ==0) {hr=pelem->get_parentelement (&pparentelem); if (Hr==s_ok && Pparentelem!=null) {pelem->release (); pelem=pparentelem; pelem->get_id (&tagid.getbstr ());} else Go=FALSE; }; if (Tagid.length () ==0) tagid= "no ID "; CMenu Menu,submenu;  Menu.createpopupmenu ();  CString Strtagid = Tostr (TagID); if (Strtagid = = "Red") Menu.appendmenu (Mf_byposition, id_red, "you click on the Red"); else if (Strtagid = = "Green") Menu.appendmenu (Mf_byposition, Id_green, "You are clicking on the Greens"); else if (Strtagid = = "Blue") Menu.appendmenu (Mf_byposition, Id_blue, "you clicked Blue");  else Menu.appendmenu (mf_byposition, Id_none, "You have ordered the white point, please click on the designated place"); int Menuid=menu.trackpopupmenu (tpm_returncmd| tpm_leftalign| Tpm_rightbutton,ppt->x, Ppt->y, this); Switch (MenuID) {case Id_red:messagebox ("Red"), break, Case Id_green:messagebox ("Red"), break, Case Id_blue:messagebox ("Red Color "); Break Case Id_none:messagebox ("haha"); Break } olewnd->release ();  Pelem->release (); return S_OK; }

Implementing Script extensions (a very important external interface)
in the project where you embed your browser, it would be nice to have a script extension if you could invoke C + + code in a Web page's script. Implementing a script extension is to implement a IDispatch interface in your program that returns this interface pointer through the ongetexternal virtual function of the CHtmlView class, so that you can pass the Window.external.XXX in the script (the keyword window can be omitted) To refer to methods or properties exposed by the interface (XXX is a method or property name). Classes derived from CCmdTarget in MFC can be automated without the need to introduce complex ATL into the MFC project.   Do not forget to call the Enableautomation function in the constructor when implementing an Automation interface from a CCmdTarget derived class. To make virtual function ongetexternal work, you must implement IDocHostUIHandler in the   custom control site class, invoking the browser class in the GetExternal method of the interface IDocHostUIHandler. Ongetexternal virtual functions, we overload the ongetexternal virtual function in a derived class of the browser class, returning a IDispatch pointer through the parameter lppdispatch, This is referred to as the returned interface when referencing window.external in the script, see Code

HRESULT cdochostsite::xdochostuihandler::getexternal (IDispatch * * ppdispatch) {method_prologue (Cdochostsite, Dochostuihandler); Return pthis->m_pview->ongetexternal (Ppdispatch); }  Clhphtmlview::clhphtmlview (BOOL isview) {... Enableautomation ();//Allow automation}  HRESULT clhphtmlview::ongetexternal (lpdispatch *lppdispatch) {*lppdispatch = GetIDispatch (TRUE);//returns S_OK for the IDispatch interface itself; }      

Note that in the above code, the ongetexternal returned is its own IDispatch interface, so it is no more than a new class derived from CCmdTarget for script extensions, and Clhphtmlview itself is derived from CCmdTarget, Implementing the interface directly above is.
Below is a concrete example of how to implement a script extension
Example clicking a button on a webpage causes the entire window to shake.
Derive a class Cdemoview from Clhphtmlview, implement IDispatch in the class, and IDispatch exposure method Wobblewnd

---------------------------------------------------------------------------file DemoView.h------------------ ---------------------------------------------------------....... class cdemoview:public Clhphtmlview {...  Declare_dispatch_map ()//Build DISPATCH mapping table to expose methods or properties ... void Wobblewnd ();//Jitter window}; ---------------------------------------------------------------------------Files DemoView.cpp--------------------- ------------------------------------------------------......//The member function is mapped to the DISPATCH mapping table, exposing the method to the script Begin_dispatch_map (  Cdemoview, Clhphtmlview) disp_function (Cdemoview, "Wobblewnd", Wobblewnd, Vt_empty, Vts_none) END_DISPATCH_MAP ()  ... void Cdemoview::wobblewnd () {//To implement Jitter window here ...} ---------------------------------------------------------------------------Files demo.htm------------------------- --------------------------------------------------...... onclick= "external. Wobblewnd () "... 

Here I would like to introduce the Disp_function macro, its role is to map a function to the dispatch mapping table, we see

Disp_function (Cdemoview, "Wobblewnd", Wobblewnd, Vt_empty, Vts_none)

Cdemoview is the host class name, "Wobblewnd" is the name that is exposed to the outside (the name used when the script is called), Vt_empty is the return value of the type is empty, Vts_none shows that this method has no parameters, if the function to be mapped has return values and the parameters are mapped, By the following examples,

Disp_function (Ccalendarview, "TestFunc", Testfunc,vt_bool,vts_bstr vts_i4 vts_i4)  BOOL TestFunc (LPCSTR param1, int param2, int param3) {...}

The

parameter table Vts_bstr vts_i4  VTS_I4 is separated by a space, their type mapping please refer to MSDN, this should be reminded that vts_bstr and CString should not correspond, but should be corresponding to LPCSTR. How
in C + + code calls a function in a Web page script
The Ihtmldocument2::scripts property represents all the script objects in the HTML document. Using the GetIDsOfNames method of the IDispatch interface of the script object can get the DispID of the script function, after dispid, the corresponding script function can be called using the IDispatch invoke function. Clhphtmlview provides a handy function for invoking JavaScript, please refer to the code in Clhphtmlview that has the keyword "JScript".
Customizing the caption of a message box
When we invoke the alert pop-up message box in a script, the title of the message box is Microsoft's predefined Microsoft Internet Explorer, such as:

in the custom control The Idochostshowui interface is implemented in the site class, and the onshowmessage of the browser is called in the ShowMessage method of the interface, we overload the Onshowmessage virtual function to customize the message box title, the implementation code is as follows:

Window title "Microsoft Internet Explorer" Resource identification #define IDS_MESSAGE_BOX_TITLE 2213 HRESULT clhphtmlview::onshowmessage (HWND                                     hwnd, LPOLESTR Lpstrtext, Lpolestr lpstrcaption,                                     DWORD dwtype, Lpolestr lpstrhelpfile, DWORD Dwhelpcontext, LRESULT * plresult) {//Load Shdoclc.dll and IE message box caption string hinstance HINSTSHDOCLC = LoadLibrary (TEXT ("SHDOCLC.     DLL "));  if (HINSTSHDOCLC = = NULL) return S_FALSE; CString strbuf,strcaption (lpstrcaption);      Strbuf.loadstring (HINSTSHDOCLC, ids_message_box_title);      Compare IE message box caption string and lpstrcaption//if same, replace if (strbuf==lpstrcaption) strcaption = M_defaultmsgboxtitle with custom caption;      Create your own message box and show *plresult = MessageBox (CString (Lpstrtext), strcaption, dwtype);     Unload Shdoclc.dll and return FreeLibrary (HINSTSHDOCLC); return S_OK; }

You can see from the code that you change the caption of the message width by setting the value of M_defaultmsgboxtitle, and modifying this value is the same as Setdefaultmsgboxtitle.

How to customize and modify the HTTP request headers that the browser sends to the Web server
In an app that integrates the WebBrowser control, the Web server may sometimes want the client (browser) to send an HTTP request with some additional information or a custom HTTP header field, which must control the HTTP request sent to the Web server in the browser. The following is a common HTTP request header that is sent by the browser:

Get/text7.htm http/1.0 accept:image/gif, Image/x-xbitmap, Image/jpeg, Image/pjpeg, Application/x-shockwave-flash,/ Application/vnd.ms-excel, Application/vnd.ms-powerpoint, Application/msword, */* referer:http://localhost Accept-language:en-us user-agent:mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Poco 0.31; LHP Browser 1.01; /. NET CLR 1.1.4322) host:localhost connection:keep-alive  chtmlview  void Navigate2 (    lpctstr Lpszurl,    DWORD dwFlags = 0,    LPCTSTR lpsztargetframename = null,    LPCTSTR lpszheaders = null,    lpvoid lpvpostdata = null,    DWORD Dwpostdatalen = 0  

The function parameter lpszheaders can specify an HTTP request header, as in the following example:

The HTTP headers we captured are as follows:


How to modify the browser identity

The User-agent field in the HTTP request header indicates the version of the browser and the version of the operating system. Web servers often need to know whether a user is requesting a page from IE or from an WebBrowser control in their own client,  for separate processing, while the WebBrowser control sends a browser identity to the Web server (user-agent field) It is the same as using IE, how to distinguish between their own browser and IE?   Microsoft does not provide a ready-made method to solve its own ideas. The custom HTTP request headers discussed earlier are prepared for this section. The idea is that:  in their own browser to deal with each U page request, the request header user-agent change to what you want.   in CHtmlView's OnBeforeNavigate2 virtual function to modify the HTTP request is no better than, 

#define WM_NVTO (wm_user+1000) class Nvtoparam {public:cstring URL; DWORD Flags; CString Targetframename; CByteArray Posteddata; CString Headers;   };                                    void Cdemoview::onbeforenavigate2 (LPCTSTR lpszurl, DWORD nflags,                                    LPCTSTR Lpsztargetframename, cbytearray& Baposteddata, LPCTSTR lpszheaders, bool* pbcancel) {CString strheaders (lpszheade RS); if (Strheaders.find ("User-agent:lhpbrowser 1.0") < 0)//Check header there is no custom user-agent string {*pbcancel = true;//No, cancel this navigation if (!str Headers.isempty ()) Strheaders + = "/r/n"; Strheaders + = "User-agent:lhpbrowser 1.0";//Add custom user-agent string nvtoparam* pnvto = new Nvtoparam; Pnvto->url = Lpszurl; Pnvto->flags = nflags; Pnvto->targetframename = Lpsztargetframename; Baposteddata.copy (Pnvto->posteddata);  Pnvto->headers = strheaders; Send a custom navigation message and send the parameters past PostMessage (WM_NVTO, (WPARAM) pnvto); Return } chtmlview::onbeforenavigate2 (Lpszurl, nflags, Lpsztargetfra                               Mename, Baposteddata, Lpszheaders, Pbcancel); } LRESULT cdemoview::onnvto (WPARAM WPARAM, LPARAM LPARAM) {nvtoparam* pnvto = (nvtoparam*) WPARAM; Navigate2 (LPCTSTR) Pnvto->url, Pnvto->flags, Pnvto->posteddata, (LPCTSTR) PNVT O->targetframename, (LPCTSTR) pnvto->headers); Delete pnvto; return 1;  }

In OnBeforeNavigate2 if there is no custom user-agent string, add this string, and cancel the navigation, and then post a message (be sure to post, let OnBeforeNavigate2 jump out of the future to navigate), Navigating again in the message, the request header already has its own identity when navigating again, so it can navigate normally.
Get rid of annoying exception warnings
After using CHtmlView in the program, we often see an exception warning from the Output window when resizing the window: the most likely exception in 0x77e53887 in ReusingBrowser.exe: Microsoft C + + exception: COleException @ 0x0012e348.

This is due to a small problem with CHtmlView handling the wm_size message, and it is not a warning to handle wm_size messages with the following code

 void Clhphtmlview::onsize (UINT nType, int cx, int cy) {cformview::onsize (NType, CX, CY);  if (:: IsWindow (M_wndbrowser.m_hwnd)) {CRect rect;  GetClientRect (rect); The difference between this sentence and CHtmlView:: Adjustwindowrectex (Rect, GetStyle (), FALSE, Ws_ex_clientedge);                            M_wndbrowser.setwindowpos (NULL, Rect.left, Rect.top, Rect. Width (), Rect. Height (), Swp_noactivate |  Swp_nozorder); }  } 

How to handle drag and drop in the browser
Sometimes there may be such a requirement, we want to be in the resource Manager to support a file to the browser to do the appropriate processing, or even drag the file to a page element to do the appropriate processing, and the browser default processing drag and drop file operation is to open the file,  But the WebBrowser control gives us a chance to handle the drag and drop ourselves. That is to implement IDocHostUIHandler in the custom control site class and invoke the Ongetdroptarget virtual function of the browser class in the GetDropTarget method of the interface IDocHostUIHandler. To handle drag-and-drop within a Web page, it is necessary to return a IDropTarget interface pointer in the Ongetdroptarget function, so we write a class cmyoledroptarget derive from the COleDropTarget class. And in implementing the IDropTarget interface, this class of code is not listed here, please download the demo program, refer to Files MyOleDropTarget.h and MyOleDropTarget.cpp. We look at the Ongetdroptarget code in Clhphtmlview.

HRESULT Clhphtmlview::ongetdroptarget (Lpdroptarget pdroptarget, lpdroptarget* ppdroptarget) {m_ Droptarget.setiedroptarget (pdroptarget);  Lpdroptarget Pmydroptarget; Pmydroptarget = (lpdroptarget) m_droptarget.getinterface (&iid_idroptarget); if (pmydroptarget) {*ppdroptarget = Pmydroptarget; Pmydroptarget->addref (); return S_OK;}  

M_droptarget is the custom processing object for the drag-and-drop. This allows you to handle drag-and-drop by overloading OnDragEnter, OnDragOver, OnDrop, and OnDragLeave virtual functions in classes derived from Clhphtmlview.  Here, incidentally, how the view handles drag-and-drop.  To drag and drop the view processing, first add a coledroptarget (or derived class) member variable to the view, such as "Cmyoledroptarget m_droptarget;" In Clhphtmlview, and then When the view is created, it invokes the Register of the COleDropTarget object, which associates the view with the COleDropTarget object, such as "M_droptarget.register (this) in Clhphtmlview", and then the drag-and-drop The event that is triggered is handled appropriately, ondragenter the object that is dragged into the view when the object is not the object that the view wants to accept, and the return "Dropeffect_move" means that the object is accepted, as

OnDragOver the object to be dragged on the view, the same as OnDragEnter detects the dragged object, and returns "Dropeffect_move" if you want to accept the object. OnDrop drag the object on the view to release the mouse, here to drag into the object to make processing; OnDragLeave drag the object to leave the view. C + + code is written, but things are not over, but also in the Web page with a script to the drag-and-drop event processing, that is, which element of the page to accept drag-and-drop object which element to deal with OnDragEnter, OnDragOver, OnDrop, the code is actually very simple, let the return value of the event is False, so that C + + code has the opportunity to handle drag-and-drop events, the code is as follows:

If you want the entire view to accept drag-and-drop, the three events are handled in the BODY element. Note: Don't forget to let the engineering support for OLE call AfxOleInit () when the application is initialized.
How to prohibit the selection of page elements
In most cases when using Web page interface, you do not want the elements on the page to be able to be selected by the mouse, to make the page elements can not be selected is: to the browser "host information tag" plus dochostuiflag_dialog tag.
The host information token uses n tag bits to control many properties of the browser, such as:

    • Disable the 3D edge of the browser;
    • prohibit scroll bar;
    • disabling scripts;
    • Define the mode of double-click processing;
    • Disable the auto-complete function of the browser;

...... Please refer to MSDN Dochostuiflag Help for more details.
How do I change the "host information token"?
Implement IDocHostUIHandler in Cdochostsite, invoke the browser's Ongethostinfo virtual function in the GetHostInfo method, and specify the "host information token" in the virtual function ongethostinfo, such as:

HRESULT clhphtmlview::ongethostinfo (Dochostuiinfo * pInfo) {pinfo->cbsize = sizeof (dochostuiinfo); pinfo-> DwFlags = Dochostuiflag_dialog |                      Dochostuiflag_theme  |                      Dochostuiflag_no3dborder |                      Dochostuiflag_scroll_no; Pinfo->dwdoubleclick = Dochostuidblclk_default;  

Scripting is also possible: Add a script to the head:

Or

other
Several functions are also available in Clhphtmlview to modify the contents of a page element:

Take the value of the form element:

Set the value of the form element:

To set the focus on a FORM element:

void Elementsetfocus (CString elename);

Using MFC to customize and extend the browser (JavaScript interacts with C + +)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.