Drag and Drop Introduction


7 minute read  • 

win32

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.

Additional Reading

I strongly suggest you investigate the following sources of information, because this is where I learnt about COM, OLE and drag&drop.

  1. msdn.microsoft.com The starting place for everything win32 related.
  2. 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.
  3. 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:
    ftp ftp.microsoft.com
    username "ftp"
    password "ftp"
    cd softlib/mslfiles
    bin
    get drgdrps.exe
    get drgdrpt.exe
    bye
    
  4. 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 IDropSource interface. The IDropSource contains methods for generating visual feedback, and for cancelling or completing the drag-drop operation.
  • The Target of the drag-drop is represented by the IDropTarget interface.
  • The Data being transferred is represented by the IDataObject interface.

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.

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.

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.

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 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.

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 DoDragDrop and RegisterDragDrop.