Summary

The OLE Drag and Drop protocol is a streamlined technique for transfering data through direct mouse action rather than through the clipboard. The protocol itself is nothing more than a way to bring an IDataObject pointer from a source to a consumer, or target. Any distance can separate the source and the consumer: they can be the same document, different documents in the same application, or two different documents or sets of data in two completely different applications. The same code handles all cases, and because you can exchange any data through IDataObject, you can exchange any data through OLE Drag and Drop.

To facilitate the exchange of an IDataObject pointer, the source implements a second object called the drop source, which implements the IDropSource interface. The target, on the other side of the picture, implements an object called the drop target using the interface IDropTarget. The target must attach this object to a window with the OLE API function RegisterDragDrop.

When the source wants to start a drag-and-drop operation, it passes its IDataObject and IDropSource pointers to the OLE API DoDragDrop. This function then enters a modal loop that watches the mouse and the keyboard. Any mouse movement into a target window will call IDropTarget::DragEnter; movement within a target window calls IDropTarget::DragOver, and movement out of such a window calls IDropTarget::DragLeave. In the DragEnter and DragOver cases, the target checks the available data, displays any desired user feedback to indicate what will happen if a drop occurs, and returns an effect flag to OLE. The effect describes what should happen when a drop occurs: a move, a copy, or a link. The default effect is move, whereas holding down the Ctrl key during an operation changes the meaning to copy, and holding down Shift+Ctrl changes it to link.

This effect shows up in IDropSource::GiveFeedback, which changes the mouse cursor accordingly. Now, when the Esc key is pressed or there is a change in the state of any mouse button, DoDragDrop calls IDropSource::QueryContinueDrag, which decides whether to continue the operation, cancel the operation (which calls IDropTarget::DragLeave), or cause a drop. The latter calls the target's IDropTarget::Drop, at which point the target performs a Paste operation using what's available in the data object originally passed to DoDragDrop.

This chapter explores how to implement drag-and-drop features through the simple example of Cosmo and the more complex example of Patron. Specifically, Patron allows the user to scroll a target document by holding the mouse just inside the window border for a short period of time. Patron also demonstrates how to "debounce" the mouse when it is accidentally clicked in a region that would normally cause a drag and drop to commence.