Keywords: Super drag-and-drop, getdroptarget, ondragover, ihtmldatatransfer 1. Overview The Ghost window browser provides a type of browser called "Super drag-and-drop" (or "Super drag-and-drop" or "drag-and-drop,. As an extension for IE drag-and-drop behavior, "Super drag-and-drop" provides some very practical functions:
- Drag and Drop webpage links: usually open in a new window
- Drag and Drop selected text: Save the text, search for the network as a keyword, and open it as a URL.
- Drag-and-drop image: it is usually used to save the image to a specified folder.
- Of course, there is also a key point: when you drag an object, the mouse pointer gives different drag effects
As mentioned in Internet Explorer programming briefing (10) responding to Event Notifications from HTML elements-several useful classes, although many browsers provide the super drag-and-drop function, however, compared with the default Implementation of IE, in addition to dragging the mouse pointer, no browser can implement the following:
- Interactive drag-and-drop between text on the page and input box (this is the most important)
- Interactive drag-and-drop between external text and webpage input boxes
- Scroll the page when dragging (this is ignored)
The purpose of this article is to introduce two methods for implementing super drag-and-drop, and to explain how to achieve "perfect" drag-and-drop, that is, to extend the Internet Explorer drag-and-drop behavior, retain the default IE Drag behavior. The third is to provide the most direct and concise implementation. As for dragging and dropping different objects to implement different functions, it is not in the scope discussed in this article. 2. Standard implementation methods: the standard method is implemented through the getdroptarget member function of the idochostuihandler. It is mentioned in msdn as follows:
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.
That is, when appropriate, the mshtml engine will call the getdroptarget method of idochostuihandler to provide an opportunity for the application to replace the default droptarget Implementation of mshtml. We can use this custom droptarget to complete the above "Super Drag and Drop" function. The method example is as follows. For the omitted part, see the source code of chtmlcontrolsite and chtmlview in MFC:
Stdmethodimp chtmlcontrolsite: Role: getdroptarget (inclupdroptarget, role * handle) {role _ (chtmlcontrolsite, dochostuihandler) * handle = role; // notify the mshtml engine of the custom implementation
ReturnS_ OK ;}
G_pdroptarget points to the implementation of a global idroptarget interface, which is assumed to be ciedroptarget. ciedroptarget implements several member functions of idroptarget: dragenter, dragover, dragleave, and drop. In dragenter, you can decide whether to accept a drop and what type of mouse drag feedback should be provided if you accept this drop. You can also set the mouse drag feedback in the continuously triggered dragover, in this way, different drag-and-drop visual effects can be provided when different objects (such as texts, links, and images) are dragged and dropped. The implementation is quite simple and will not be described here. However, the above implementation has some problems. First, the drag and drop between the selected text and the input box on the page is gone. This is natural. Since we replaced the default IE implementation with the custom droptarget, we should implement this interactive drag-and-drop by ourselves. The difficulty is not that it cannot be implemented, but that it is difficult to implement it-it is enough to get the HTML element under the mouse; when there is text in the input box, the cursor should also move as the mouse moves-so there seems to be no browser for this effort-Consuming Feature. Second, as a derivative of the text drag and drop in the input box, the drag and drop scroll is gone. When you drag the mouse to a certain direction, the webpage should scroll out with invisible parts, such as an input box, giving us the opportunity to drag the text. The implementation of this feature is not difficult, but it is ignored (not many people are noticed to drag and drop the scroll). Secondly, the main feature is not implemented, and this scrolling is of little significance. 3. Enter the mshtml internal. Since it is difficult to obtain interactive drag-and-drop with the input box from the external implementation provided by getdroptarget, let's consider the problem from another angle and let us break into the mshtml internal. The starting point is the ihtmldocumentx interface-a magic weapon for manipulating the DOM of IE. We noticed that ihtmldocument2 has an ondragstart event, and then we thought that there should also be events such as ondragenter, ondragover, ondrop (and so on). If we respond to these events, interactive drag-and-drop processing of the same input box should be able to solve. Because these drag and drop occur in the default droptarget Implementation of mshtml, when you drag the mouse to an input box, it will certainly trigger an ondragover event, with the help of ihtmleventobj, we can easily get the relevant HTML element, and other operations will be easy. After careful consideration, we also found that the ihtmleventobj2 interface has a datatransfer Attribute-you can get an ihtmldatatransfer pointer, the ihtmldatatransfer interface is one of the important methods used in the browser for data exchange (it will be useful if you look at its properties ):
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. when tallowed -- 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.
Furthermore, the idataobject interface can be accessed from the ihtmldatatransfer interface. During OLE drag and drop, data is transmitted through the idataobject interface. The usage will be discussed later. 4. Break into the mshtml. The idea of providing mouse feedback is similar to implementing the getdroptarget method. With the ihtmldatatransfer interface, you can set the drag-and-drop effect through the dropeffect attribute when the ondragstart and ondragover events are triggered (you can set the drag-and-drop effect as needed, and use the default effect if not set ). Furthermore, "drag" and "put" occur in the default Implementation of mshtml. We can know from the srcelement of ihtmleventobj whether the HTML element at the mouse position is an input box. 5. Enter the mshtml internal-to receive events such as ondragstart, you can use Internet Explorer programming description (10) respond to the chtmlobj class and chtmlelements class mentioned in the event notification from HTML element-several useful classes, and connect to the document class where appropriate. The sample code is as follows:
Hresult chtmldocument2: oninvoke (dispidmember, refiid riid, lcid, word wflags, dispparams * pdispparams, variant * pvarresult, interval info * p1_info, uint * puargerr) {...... // if you only want to set the mouse drag effect, this event can not be handled
CaseDispid_htmlelementevents_ondragstart: {ondragstart ();
Break;} // The focus is here
CaseDispid_htmlelementevents_ondragover: {ondragover ();
Break;}
CaseDispid_htmlelementevents_ondrop: {ondrop ();
Break;}......}
VoidChtmldocument2: ondragover (
Void) {Setdrageffect (); // sets the mouse drag effect}
VoidChtmldocument2: setdrageffect (
Void) {Response <ihtmlwindow2> pwindow; ccomqiptr <response> peventobj; ccomqiptr <response> peventobj2; ccomqiptr <ihtmlelement> pelement; hresult hR = response-> get_parentwindow (& pwindow ); hR = pwindow-> get_event (& peventobj); // when ondragover occurs, the default behavior of IE is "no mouse drag effect ". // Set the return value of ihtmleventobj to false to cancel the default action of the event. Therefore, after executing the following sentence, the drag-and-drop effect is displayed. Allowdisplaydragcursor (peventobj, false); ccombstr bstrtagname; peventobj-> get_srcelement (& pelement); // obtain the current HTML elementpelement-> get_tagname (& bstrtagname );
If(Iseditarea (bstrtagname) // determines whether the mouse is in the input box based on the tag name to set the focus so that the cursor moves with the mouse {ccomqiptr <ihtmlelement2> pelement2;
If(Succeeded (pelement-> QueryInterface (iid_ihtmlelement2, (void **) & pelement2) & pelement2) {pelement2-> focus () ;}// by default, when you drag a document to the input box, the mouse turns into a drag cursor, so the default IE behavior is used here. Allowdisplaydragcursor (peventobj, true) ;}} bool chtmldocument2: iseditarea (ccombstr bstrtagname ){
ReturnBstrtagname = "input" | bstrtagname = "textarea ";}
VoidChtmldocument2: allowdisplaydragcursor (ccomqiptr <ihtmleventobj> peventobj, bool ballow) {variant V; V. Vt = vt_bool; V. boolval =! Ballow? Variant_false: variant_true; peventobj-> put_returnvalue (V );}
VoidChtmldocument2: ondrop (
Void) {Ccomqiptr <ihtmlwindow2> pwindow; ccomqiptr <strong> peventobj; ccomqiptr <strong> peventobj2; ccomqiptr <ihtmlelement> pelement; ccomqiptr <strong> PDT; // demonstrate how to use ihtmldatatransfer hresult hR = m_sphtmlobj-> get_parentwindow (& pwindow); HR = pwindow-> get_event (& peventobj); HR = peventobj-> QueryInterface (response, (void **) & peventobj2); HR = peventobj2-> get_datatransfer (& PDT); ccombstr bstrformat = "url"; // first try to get urlvariant data; hR = PDT-> getdata (bstrformat, & data );
If(Data. VT! = Vt_null) {// get successful. The drag-and-drop object is urldoopenurl (cstring (data. bstrval);} else {// otherwise, try to get the selected text bstrformat = "text"; HR = PDT-> getdata (bstrformat, & data );
If(Data. VT! = Vt_null) {// The result is obtained successfully. The drag-and-drop content is the text ccombstr bstrtagname; peventobj-> get_srcelement (& pelement); pelement-> get_tagname (& bstrtagname );
If(Iseditarea (bstrtagname) {// drop target is the input box without any operation. ie performs default processing.
Return;}
Else{// Otherwise, we can process the text, save it, or check whether the link is opened, etc. doprocesstext (cstring (data. bstrval); // process the text }}
Else{// Neither a link nor a text, it can be considered as a file from an external (such as Windows Shell) drag and drop doondropfiles (PDT) ;}}// demonstrate how to get idataobject from ihtmldatatransfer
VoidChtmldocument2: 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 );......}
6. Return to the standard method again. The above method of responding to webpage drag through event sink can work well. It can be said that it is "perfect", but there are still two "small" problems: first, you must establish a connection with the document before you can work, but the time for establishing a connection is not easy to grasp (documentcomplete is recommended in msdn, but it is also available in navigatecomplete, or when the readystate of webbrowser changes to readystate_interactive ). Second, the implementation method is still slightly complicated. Is there a simpler way? I decided to conduct a "survey" on getdroptarget again ". The so-called "shoes without finding anything, it takes no effort to get it". After a glance at the declaration of the getdroptarget method, I suddenly thought of a solution. Facts have proved that this is a perfect solution. Let's take a look at the Declaration of getdroptarget. The first parameter points to the default droptarget implementation provided by mshtml, and the second parameter is used to return the custom droptarget Implementation of the application, if s_ OK is returned in getdroptarget, mshtml replaces the default droptarget implementation with the custom droptarget provided by the application.
Hresult getdroptarget (idroptarget * pdroptarget, idroptarget ** ppdroptarget );
Parameter description
Pdroptarget
[In] pointer to an idroptarget interface for the current drop target object supplied by mshtml.
Ppdroptarget
[Out] address of a pointer variable that represents es an idroptarget interface pointer for the alternative drop target object supplied by the host.
Did you think of it? The key to solving the problem lies in the first parameter pdroptarget. I believe that many browsers ignore the first parameter while processing it, but only inform mshtml of their implementation through the second parameter, thus losing the default IE behavior. In this case, the pointer of the default idroptarget interface is saved and called as appropriate. Can the original drag-and-drop behavior of IE be retained?
7. Perfect implementation
The complete code is no longer provided. We only list the key parts as an example. Suppose the class we use to implement the idroptarget interface is called cbrowserdroptarget:
// Constructor. The input parameter is the pdroptarget obtained from getdroptarget. It is the default Implementation of mshtml, cbrowserdroptarget: cbrowserdroptarget (idroptarget * porginaldroptarget): false) // This Boolean variable is used to determine whether text is being dragged to inputbox, m_porginaldroptarget (porginaldroptarget) // m_porginaldroptarget is used to save the default Implementation of mshtml {} stdmethodimp cbrowserdroptarget :: dragenter (/* [unique] [in] */idataobject _ rpc_far * pdataobj,/* [in] */DWORD grfkeystate,/* [in] */pointl PT, /* [out] [in] */DWORD _ rpc_far * pdweffect) {// call the default behavior
ReturnM_porginaldroptarget-> dragenter (pdataobj, grfkeystate, PT, pdweffect);} stdmethodimp cbrowserdroptarget: dragover (/* [in] */DWORD grfkeystate, /* [in] */pointl PT,/* [out] [in] */DWORD _ rpc_far * pdweffect) {// when dragging text in a webpage, the value is dropeffect_copy (the drag text does not belong to the input box) // or dropeffect_copy | dropeffect_move (the drag text is the text in the input box) DWORD dwtempeffect = * pdweffect; // call the default hresult hR = m_porginaldroptarget-> dragover (grfkeystate, PT, pdweffect) of IE ); // determine whether to drag the text m_bdragtexttoinputbox = isdragtexttoinputbox (dwoldeffect, * pdweffect) to the input box );
If(! M_bdragtexttoinputbox) {// The original drag effect is used if the text is not dragged to the input box. Otherwise, the default effect is the same as that of IE-that is, no effect * pdweffect = dwtempeffect ;}
ReturnS_ OK;} // determine whether to drag the text bool cbrowserdroptarget: isdragtexttoinputbox (DWORD dwoldeffect, DWORD dwneweffect) to the input box based on the effect value before and after the default call behavior) {// if the text in the non-input box is dragged to the input box, dwoldeffect and dwneweffect are equal, all of them are parallel equal = (dwoldeffect ==dropeffect_copy) & (dwoldeffect = dwneweffect ); // if the text is dragged from one input box to another, dwoldeffect is dropeffect_copy | dropeffect_move, // while dwneweffect may be dropeffect_move (default ), it may also be running (Press CTRL) bool finished = (dwoldeffect = (dropeffect_copy | finished) & (dwneweffect = dropeffect_move | dwneweffect = dropeffect_copy ); // drag from Microsoft Word. dwoldeffect is the combination of all effects. bool bmswordtoinputbox = (dwoldeffect = (dropeffect_copy | dropeffect_move | dropeffect_link )) & (dwneweffect = dropeffect_move | dwneweffect = dropeffect_copy); // The drag and drop operations from edit plus are also special, dwoldeffect is a negative number (it is suspected that there is a problem with the drag and drop Implementation of Edit plus) bool Limit = (dwoldeffect <0) & (dwneweffect = dropeffect_move | dwneweffect = dropeffec ); // there may be some exceptions. You can add more ......
ReturnBtextselectiontoinputbox | binputboxtoinputbox | bmswordtoinputbox | beditplustoinputbox;} stdmethodimp cbrowserdroptarget: dragleave () {// call the default behavior
ReturnM_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) {// It is a text drag-and-drop. The default behavior of calling IE is return m_porginaldroptarget-> drop (pdataobj, grfkeystate, PT, pdweffect );} // otherwise, it is a drag-and-drop link, image, file, etc. The conventional idataobject processing method ......
ReturnS_ OK ;}
So far, we have a perfect basic framework of "Super Drag and Drop", which retains the default behavior of IE while extending:
- Text can be dragged and dragged between the page and the input box.
- Interactive drag-and-drop between external text and webpage input boxes
- Automatically scroll the page when dragging
Other functions, such as dragging in different directions to complete different tasks, right-clicking and dragging to execute different functions, and holding down ALT to save the text, can be implemented as needed and will not be discussed.
8. I have been chatting with Stanley Xu for a few hours today and have benefited a lot. According to Stanley's proposal, we do not need to judge whether to drag text to the input box, because all we need is to make it have the drag effect when IE's default behavior does not have the mouse drag effect, therefore, you only need to simply determine whether the effect value after calling the default IE behavior is 0, as shown in the following code: // determine whether to drag the text m_bdragtexttoinputbox = * pdweffect to the input box! = 0; simple and direct, of course, more importantly: available.
9. References: msdn: ihtmleventobj interfacemsdn: ihtmldatatransfer interface Internet Explorer programming Overview (10) responding to Event Notifications from HTML elements-several useful classes