The aim of this series of tutorials is to enable the reader to implement complete drag and drop support for their applications. Drag and drop became a standard feature of many Windows applications when Windows 95 was launched. With COM and OLE becoming more mainstream at this time, applications had the power to interact seamlessly with the Windows Shell and even other Windows applications. This flexibility came at a price though. Writing any form of COM or OLE enabled appliction is a complete nightmare, to put it mildly.
This tutorial will ease you through the pain of writing the required OLE interfaces necessary to enable drag and drop behaviour. As usual, we will use pure Win32 API techniques. However, I will be using C++ rather than C, because C++ is definitely the preferred language to write COM interfaces with. It would be a simple matter to convert the code to C as I will also explain.
I intend this tutorial to be written in several parts, as there is alot of information to cover. Also, the components of drag-and-drop lend themselves very nicely to separate topics, so this is the approach I will use. The first tutorial (this one, in fact) will provide an introduction to OLE Drag and Drop. Subsequent tutorials will focus on drag-and drop. Parts 2 and 3 will cover OLE data transfers the IDataObject interface. Part 4 will look at the IEnumFORMATETC interface, whilst parts 5 and 6 will cover drag-sources and drop-targets.
Once we have covered these basic details there will be further tutorials discussing drag-and-drop in more detail.
I strongly suggest you investigate the following sources of information, because this is where I learnt about COM, OLE and drag&drop.
ftp ftp.microsoft.com username "ftp" password "ftp" cd softlib/mslfiles bin get drgdrps.exe get drgdrpt.exe bye
"Drag and Drop" is a term used to describe the action of using a mouse to transfer data from one place to another.
Every Drag and Drop operation is comprised of three elements. These elements are of course COM objects which must be implemented by any application that wants to support drag and drop.
Note that an application doesn't need to support all three COM interfaces - if you just want to make a "drop target", then only the IDropTarget interface is required. Similarly, an application which just supports dragging data from it (and not to it) is required to support the IDropSource and IDataObject interfaces. Of course, an application can implement all three interfaces to support full drag and drop within the same document.
The diagram above illustrates the key components required to support a drag and drop operation. Take a moment to understand what the diagram is presenting. The box on the left is the initiator of a drag-and-drop operation. It has created two COM objects which each expose an interface (IDataObject and IDropSource), which are used by OLE to perform the drag-drop.
The box on the right represents the destination of the drag-and-drop operation. It has created a single COM object (with a single interface IDropTarget). Whenever the mouse is dragged over a drop target window, OLE passes an IDataObject interface to the target which allows the target to "see" the data object exposed by the source. The object doesn't get copied in any way - just the COM interface is made available. When the target extracts data from the data object, the OLE/COM runtime takes care of marshalling the function calls and data across the process boundaries.
In this example the source and destination can be either implemented within the same process, or can be in seperate processes. It isn't important where they are implemented, because the OLE runtime (COM, in fact) takes care of making the Data Object available to the destination process.
The first task any application must perform when it wants to use the OLE functions is to call OleInitialize when it starts, and OleUnintialize when it finishes. This is not quite accurate though - it is better to say the thread that wants to use OLE must call these functions, because COM and OLE must be initialized and uninitialized on a per thread basis:
WINOLEAPI OleInitialize(LPVOID pvReserved); WINOLEAPI OleUninitialize();
At the very heart of OLE drag and drop is an API called DoDragDrop. The function prototype has the following form:
WINOLEAPI DoDragDrop( IDataObject * pDataObject, // Pointer to the data object IDropSource * pDropSource, // Pointer to the source DWORD dwOKEffect, // Effects allowed by the source DWORD * pdwEffect // Pointer to effects on the source );
When an application wants to initiate a drag and drop operation it must call this function. However there are two important steps which must take place before DoDragDrop is called.
Both the IDataObject and IDropSource objects must be created by the initiator of the drag-drop operation, before calling DoDragDrop. Creating these two objects is non-trivial and is therefore covered in the next section of this tutorial. Note that no mention of GUI related objects (such as windows) has been made so far. A drop source is a stand-alone entity that is not tied to any one window, although usually a drag-drop operation is initiated when a window procedure processes a WM_MOUSEMOVE message.
When DoDragDrop is called, a modal message loop is entered which monitors mouse and keyboard messages.
When an application wants to be the recepient of a drag-and-drop operation, it must call the RegisterDragDrop function. Of course, this application must call OleInitialize/OleUninitialize in the same way the source application must.
WINOLEAPI RegisterDragDrop( HWND hwnd, // Handle to a window that can accept drops IDropTarget * pDropTarget // Pointer to object that is to be target of drop );
Looking at the function prototype above reveals the last component to a drag-drop-operation - the IDropTarget COM interface. Also required is a handle to a window, which RegisterDragDrop requires in addition to the IDropTarget interface. This window is registered with the OLE runtime, so that when the mouse is dragged over this window, OLE can call the methods in the IDropTarget interface to notify the application owning that window that a drag-drop operation is in progress.
When a window is to be destroyed, the RevokeDragDrop API must be called:
WINOLEAPI RevokeDragDrop(
HWND hwnd // Handle to a window that can accept drops
);
This API unregisters the specified window with the OLE runtime, and releases the IDropTarget interface used during registration and releases the DropTarget object in the process.
So far I have presented an overview of OLE drag and drop. There is still alot more ground to cover, so over the next parts of this tutorial we will be looking at the core components of drag and drop. Coming up is the subject of OLE data transfers, but for now it would be a good idea to visit http://msdn.microsoft.com and review the documentation for DoDragDrop and RegisterDragDrop.
Click here for OLE Drag and Drop - Part 2
Please send any comments or suggestions to: james@catch22.net
Last modified: 16 February 2005 20:02:27