Hacker’s Guide to Visual FoxPro
An irreverent look at how Visual FoxPro really works. Tells you the inside scoop on every command, function, property, event and method of Visual FoxPro.
OLE Drag and Drop
When we first learned that VFP 6 would support OLE Drag and Drop
, we thought, “That’s nice. Now we’ll be able to drag between ActiveX controls and native controls.” Then we realized it applied to the development environment, too, and that we’d be able to drag from VFP to Word or drag files from Explorer into the Project Manager or the Command Window. Even better, but still nothing to write home about.
Then we started to actually play with the programmatic elements of OLE Drag and Drop
. The farther we went, the closer our jaws got to the floor. This is cool stuff!
OLE Drag and Drop
is, of course, not just a VFP thing. This is the model used throughout Windows to allow applications to share data through drag and drop. So what we use in VFP to move data from a calendar control to a text box is the same set of PEMs that the Windows programmers use to move files from one directory to another, or that Word and Excel use to drag data from one application to the other.
The design of OLE Drag and Drop
is truly elegant. It involves three objects, each with a job to do, and each with the appropriate tools to do it.
The first two objects are fairly obvious. First, there’s the drag source, the control or application from which the data is being dragged. Second, there’s the drop target, the control or application onto which the data might be dropped. So far, so good, but what’s the third? The third is a COM object called the data object. It contains the data from the drag source in various formats, and makes that data available to the drop target upon request.
In VFP’s native drag and drop, responsibilities are partitioned between the drag source and the drop target. The drag source starts things off and specifies the icon to be used; the drop target responds to the drag in a couple of events. But that’s all there is.
OLE Drag and Drop
is much more complex, but that complexity gives you much more control. With OLE Drag and Drop
, it’s possible that either the drag source or the drop target belongs to another application and thus isn’t accessible to you programmatically. For example, if you drag files into VFP from Explorer, VFP owns only the drop target, not the drag source.
To deal with this, both the drag source and the drop target have a chance to respond every step of the way. For example, whenever the drop target’s OLEDragOver event fires, indicating that data is passing over the object, it also fires the drag source’s OLEGiveFeedback event, so the drag source can decide whether or not it likes the drop target and behave accordingly. Even if the drop target is outside VFP, a VFP drag source’s OLEGiveFeedback event fires. Similarly, when the drag source comes from outside VFP, a VFP drop target’s events fire as expected. This table shows the order of events when both participants are VFP objects; when one of them is an outsider, you won’t see all the events fire. OLEDragOver and OLEGiveFeedback fire repeatedly. The form DragDropSample.SCX in the Developer Downloads available at www.hentzenwerke.com shows the firing sequence as you drag and drop data.
Event |
Object |
MouseDown |
Drag source |
OLEStartDrag |
Drag source |
OLEDragOver |
Drop target (which may be the drag source itself, if OLEDropMode is enabled) |
OLEGiveFeedback |
Drag source |
OLEDragDrop |
Drop target |
OLESetData |
Drag source |
OLECompleteDrag |
Drag source |
In addition to giving both participants a chance to react, the control over OLE Drag and Drop
is finer than for native drag and drop. The drag source and drop target both can indicate not just whether a drop is possible, but whether a drop of this source onto this target produces a copy or a move. The drop target can also respond differently based on the mouse buttons that are used and whether any of the keyboard modifiers (Ctrl, Alt, Shift) are down.
As if all that weren’t enough, OLE Drag and Drop
also provides fine control over the actual data that is dropped. The data object is automatically filled with appropriate data (based on the drag source and any highlighting), but its methods let you inquire about what’s there and, if you want, change it to meet your needs.
Data in the data object is stored in one or more of a set of formats. There are a number of built-in formats, but you can define your own as well, allowing you to store whatever data you want and process it as you desire when a drop occurs. With the built-in formats, you can replace the default data with your own data as well.
Debugging OLE drag and drop sequences is incredibly difficult. It's almost impossible to get to the debugger when an error occurs, and you can't set breakpoints successfully or use SUSPEND in the OLE drag and drop events. (If you try, you get the error "CANCEL or SUSPEND is not allowed" and, if that's not bad enough, the error dialog has Cancel, Suspend, Ignore and Help buttons.) In addition, you can put the data object in the Watch window, but you can't actually find out anything about it. We do understand what the problem is here. As soon as you're in the debugger, your drag and drop operation ends, so you're not in the relevant method anymore and the data object no longer exists. Rather than deal with that issue, you simply can't stop there. We've had some success using DEBUGOUT and WAIT WINDOW statements and the Event Tracker from OLE drag and drop methods to see what's going on, but it's certainly much harder than normal debugging. |
Despite the debugging complications, the interactions among the three participants make it possible to do some very sophisticated manipulation using OLE Drag and Drop
—certainly well beyond anything you could accomplish with VFP’s native drag and drop. The beauty of the object model involved leads us to truly admire the folks who designed it.
ClearData, DataObject, GetData, GetFormat, OLECompleteDrag, OLEDrag, OLEDragDrop, OLEDragMode, OLEDragOver, OLEDragPicture, OLEDropEffects, OLEDropHasData, OLEDropMode, OLEDropTextInsertion, OLEGiveFeedback, OLESetData, OLEStartDrag, SetData, SetFormat