Implementing Reusable Drag '& Drop Classes

IDataObject,IEnumFORMATETC,IDropSource,IDropTarget,IDragSourceHelper,IDropTargetHelper

Tools used: Microsoft. Platform SDK Whistler Beta 1 and VC++ 6.0 (SP5), WTL
Platform used: Windows 2000

I tried to create as generic Drag and Drop classes as possible. Here is what I came up with. I think it's a good starting point if you're looking to add drag and drop support to your app. The demo project has sample code for various clipboard formats:
  • CF_TEXT
  • CF_HDROP
  • CF_BITMAP
  • CF_DIB
  • CF_ENHMETAFILE
and MEDIUMs:
  • TYMED_HGLOBAL
  • TYMED_ISTREAM
  • TYMED_ENHMF
  • TYMED_GDI

Some screenshots of image drag and drop from static window:

Fig. 1. Dragging from static window to WordPad

Fig. 2. Using Clipboard

Fig. 3. Pasting the above clipboard contents into WordPad


Usage:
To enable your window as a DropTarget.

  • Derive a class from CIDropTarget.
  • Override OnDrop. Return true or false from this method. If true, base class will free the medium. If false, it won't free the medium.
  • Call ::RegisterDragDrop for your window.
  • Add Supported formats by calling CIDropTarget::AddSuportedFormat.
  • Optionally override other methods such as DragOver and DragLeave. I used it for the tree to highlight the current item.

Example:

class CTreeDropTarget : public CIDropTarget { public: virtual bool OnDrop(FORMATETC* pFmtEtc, STGMEDIUM& medium, DWORD *pdwEffect) { if(pFmtEtc->cfFormat == CF_TEXT && medium.tymed == TYMED_HGLOBAL) { // Handle it } return true; } // etc...

};

In your Window derived class create a member of CTreeDropTarget. Then initialize it like this:

{
  // ...
  m_pDropTarget = new CTreeDropTarget(m_hWnd);
  RegisterDragDrop(m_hWnd,m_pDropTarget);
  // create the supported formats:
  FORMATETC ftetc = {0}; 
  ftetc.cfFormat  = CF_TEXT; 
  ftetc.dwAspect  = DVASPECT_CONTENT; 
  ftetc.lindex    = -1; 
  ftetc.tymed     = TYMED_HGLOBAL; 
  m_pDropTarget->AddSuportedFormat(ftetc); 
  ftetc.cfFormat  = CF_HDROP; 
  m_pDropTarget->AddSuportedFormat(ftetc);
  //...
}

That's all for drop target.

To enable your window as the Drag and Drop source:

  • Catch the Windows message that initiates the drag and drop such as TVN_BEGINDRAG.
  • In the message function handler create new CIDataObject and CIDropSource.
  • Create the clipboard formats and medium for those formats.
  • Call SetData to add the clipboard formats and medium to DataObject. Second parameter to SetData indicates if DataObject should take the ownership of medium or not. If set to TRUE, then DataObject takes the ownership of your medium, you don't need to free it. Otherwise, it will make a copy of your medium without releasing the one you gave it.

Example:

LRESULT OnBegindrag(...)
{
   CIDropSource* pdsrc = new CIDropSource;
   CIDataObject* pdobj = new CIDataObject(pdsrc);
   // Init the supported format
   FORMATETC fmtetc = {0}; 
   fmtetc.cfFormat  = CF_TEXT; 
   fmtetc.dwAspect  = DVASPECT_CONTENT; 
   fmtetc.lindex    = -1; 
   fmtetc.tymed     = TYMED_HGLOBAL;
   // Init the medium used
   STGMEDIUM medium = {0};
   medium.tymed     = TYMED_HGLOBAL;
 
   // medium.hGlobal = init to something
   // Add it to DataObject
   pdobj->SetData(&fmtetc,&medium,TRUE);   
// Release the medium for me   // add more formats and medium if needed // Initiate the Drag & Drop ::DoDragDrop(pdobj, pdsrc, DROPEFFECT_COPY, &dwEffect); }

To use the shell's drag image manager (comes with Windows 2000):

You don't need to add the support for it if you are acting as drop target. It is encapsulated in CIDropTarget class. If you're acting as data source:

  • Create an instance of CDragSourceHelper before calling ::DoDragDrop.
  • Call CDragSourceHelper::InitializeFromWindow or CDragSourceHelper::InitializeFromBitmap.

Adding the Copy/Paste through clipboard is not much work either.

Example:

LRESULT OnContextMenu(...)
{
   // ...
   CIDataObject* pdobj = new CIDataObject(NULL);  
   // Init FORMATETC and STGMEDIUM just like before
   // Add the format and medium to Dataobject>
   pdobj->SetData(&fmtetc,&medium,TRUE);
   // Add data to clipboard
   OleSetClipboard(pdobj);
 
   OleFlushClipboard();  // render the data on clipboard, 
                        // so it's available even if we 
                        // close the app
   // ...
}

References:

Downloads

Download demo project - 76 Kb
Download source - 6 Kb


Comments

  • Build Error

    Posted by Legacy on 05/31/2001 12:00am

    Originally posted by: amir

    sorry, perhaps I am stupid, but find these errors.
    After download wtl31, after resequence the include directory.
    win2000 server, vs6 sp4. thanks.

    --------------------Configuration: DragDrop - Win32 Debug--------------------
    Compiling...
    stdafx.cpp
    d:\program files\microsoft visual studio\wtl31\include\atlframe.h(275) : error C2146: syntax error : missing ';' before identifier 'lpnm'
    d:\program files\microsoft visual studio\wtl31\include\atlframe.h(875) : see reference to class template instantiation 'WTL::CFrameWindowImplBase<TBase,TWinTraits>' being compiled
    d:\program files\microsoft visual studio\wtl31\include\atlframe.h(275) : error C2501: 'LPNMREBARCHEVRON' : missing storage-class or type specifiers
    d:\program files\microsoft visual studio\wtl31\include\atlframe.h(875) : see reference to class template instantiation 'WTL::CFrameWindowImplBase<TBase,TWinTraits>' being compiled
    d:\program files\microsoft visual studio\wtl31\include\atlframe.h(275) : error C2501: 'lpnm' : missing storage-class or type specifiers
    d:\program files\microsoft visual studio\wtl31\include\atlframe.h(875) : see reference to class template instantiation 'WTL::CFrameWindowImplBase<TBase,TWinTraits>' being compiled
    Error executing cl.exe.

    DragDrop.exe - 3 error(s), 0 warning(s)

    • for 'lpnm', you need vc7 or newer platform sdk

      Posted by jauming on 09/27/2007 10:45pm

      for 'lpnm', you need vc7 or newer platform sdk

      Reply
    Reply
  • Where is atlres.h?

    Posted by Legacy on 05/29/2001 12:00am

    Originally posted by: JMR

    I can't compile the sample. Can't find atlres.h

    • atlres.h is in wtl 8.0

      Posted by jauming on 09/27/2007 10:43pm

      http://sourceforge.net/project/showfiles.php?group_id=109071

      Reply
    • Please help me

      Posted by dcvkhuong on 04/24/2005 01:22am

      I can't compile the sample. Can't find atlres.h. Can you send it to me. Thanks very much

      Reply
    • Please help me

      Posted by dcvkhuong on 04/24/2005 01:20am

      I can't compile the sample. Can't find atlres.h. Can you send it to me. Thanks very much. Please send it to my email address: khuongdcv@yahoo.com

      Reply
    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • 10 Rules that Make or Break Enterprise App Development Projects In today's app-driven world, application development is a top priority. Even so, 68% of enterprise application delivery projects fail. Designing and building applications that pay for themselves and adapt to future needs is incredibly difficult. Executing one successful project is lucky, but making it a repeatable process and strategic advantage? That's where the money is. With help from our most experienced project leads and software engineers, …

  • Live Event Date: September 10, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild". This loop of continuous delivery and continuous feedback is …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds