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
- msdn.microsoft.com The starting place for everything win32 related.
- Inside OLE 2nd edition has alot of very useful information, and is regarded as the “bible” for OLE. It’s a little dated but contains everything you need to know. A “softcopy” version of this book used to be included in MSDN, and maybe it still is. There are also alot of softcopy versions in pdf and chm format floating around the internet.
- ftp.microsoft.com Microsoft’s FTP server contains hundreds of resources dating years back. The most useful thing I’ve found there so far are two small files - drgdrps.exe and drgdrpt.exe. These are self-extracting ZIP files which contain full source to a simple drop-source and drop-target application. To access these files simply goto your command prompt and type:
- Microsoft Technical Articles - in particular the “OLE for Idiots” series, and “What OLE Is Really About”. These articles are quite old now (getting on for 10 years or so) but are still relevant today. A simple google search will locate these articles.
OLE Drag and Drop
“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.
- The Source of the drag-drop is represented by the
IDropSourcecontains methods for generating visual feedback, and for cancelling or completing the drag-drop operation.
- The Target of the drag-drop is represented by the
- The Data being transferred is represented by the
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
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 (
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.
Starting Drag and Drop
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.
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
DoDragDrop is called, a modal message loop is entered which monitors mouse and keyboard messages.
Receiving Drag and Drop data
When an application wants to be the recipient of a drag-and-drop operation, it must call the
RegisterDragDrop function. Of course, this application must call
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.
Coming up in Part 2 - OLE Data Transfers
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