Drag And Drop between Window Controls

Environment: The only restriction is that you have IE4 (with at least SP2)

Introduction

Many people have been asking for Drag & Drop between windows controls. After reading an article on the CodeGuru site, and trying the functionality of MFC for drag and drop, I decided to implement it in to one of my applications.

The MFC implementation is a very good example of the quality of code that is written after after lengthy heavy technical discussion. In other words, it's bad. It has too much overhead on the OO site, and in the end it doesn4t work (and when it does, it's a miracle). If you don't agree with this statement, step through the MFC code to see what I mean.

This is also a rather weird thing. Microsoft has been promoting Drag&Drop API (D&D API) as one of the major things to implement in a Windows application. Yet, Microsoft doesn't even support it in most if its own applications. Support for it is good on the COM side of things, but how do you implement Drag & Drop from a standard Win32 or MFC application?

I have learned a lot from CodeGuru over the years. So, here's is something back. The secret lies buried in a COM interface called IDropTarget.

How does it all work?

So how does it all work? Well, what we basically do is register the windows we want to use in drag and drop operations with the OS and the D&D API. When a modal drag and drop operation is present, the D&D API will scan that list and if it finds that the cursor is in one the the windows registered, it will notify that window by the interface object IDropTarget. That object is then responsible for handling the result of the drag and drop.

So we link the object up with the window [handle] that will support a drop operation, and call the standard MFC drop API COleDataSource::DoDragDrop(). Below is some documentation on how to do this, the sample distributed with this article shows how to drag and drop text from a listbox, a combobox, and a button between each other. Implementing this for other controls is not that hard.

IDropTarget

IDropTarget is defined in oleidl.h, one of the basic OLE include files. We will implement this interface in a baseclass called ECOleMemDropTarget. This class will handle the calls send by the Drag and Drop API. The class will look for dropped data and check if the type of data passed to it, and registered by the D&D API on the clipboard, is correct. If that is the case, it will let us manipulate it.

The definition for ECOleMemDropTarget looks like this.


interface ECOleMemDropTarget : public IDropTarget
{
public:
ECOleMemDropTarget();
~ECOleMemDropTarget();

// basic IUnknown stuff
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void ** ppvObject); 
ULONG STDMETHODCALLTYPE AddRef(void); 
ULONG STDMETHODCALLTYPE Release(void); 

IDropTarget stuff
HRESULT STDMETHODCALLTYPE DragEnter(struct IDataObject *,unsigned long,struct _POINTL,unsigned long *); 
HRESULT STDMETHODCALLTYPE DragOver(unsigned long,struct _POINTL,unsigned long *); 
HRESULT STDMETHODCALLTYPE DragLeave(void);
HRESULT STDMETHODCALLTYPE Drop(struct IDataObject *,unsigned long,struct _POINTL,unsigned long *);

// called by parents
BOOL Register(CWnd* pWnd, UINT pDataType);
void Revoke();

// call parent we have goodies
virtual void GotDrop(void);
virtual DWORD GotDrag(void);
virtual void GotLeave(void);
virtual DWORD GotEnter(void);
public:
BYTE *m_Data;

CPoint m_DropPoint;

DWORD m_KeyState;

protected:
CWnd* m_DropTargetWnd;

UINT m_RegisterType;

DWORD m_dwRefCount;
};
It inherits from IDropTarget, and implements the needed methods from IUnknown as all COM interface derived classes, and the m_dwRefCount datamember needed for garbage collection/reference counting.

DragEnter, DragOver, DragLeave and Drop are interface methods of IDropTarget.These are the methods that will get called by the D&D API when a drag and drop operation is in progress above our window. We don4t define these as pure virtual functions. Some of our parent will not be interested in what we have to say (yeah, C++ is really like the world out there ;-)), and we dont want to put the burden on them of writing some stub code.

The public datamembers contain data on a D&D call in the works: m_DropPoint contains the screen coordinates of the point of the drop, and m_KeyState the state of some windows key when the user released the mouse. You could edit the functionality of the class so that these contain valid data during the D&D operation.

The code of our class

First are the Register and Revoke members. These will set up a window as a drag and drop client.

BOOL ECOleMemDropTarget::Register(CWnd* pWnd, UINT pDataType)
{
if(NULL == pWnd)
return E_FAIL;

if(0L == pDataType)
return E_FAIL;

// keep
m_DropTargetWnd = pWnd;
m_RegisterType = pDataType;

// this is ok, we have it
DWORD hRes = ::RegisterDragDrop(m_DropTargetWnd->m_hWnd, this);
if(SUCCEEDED(hRes))
return TRUE;

// wont accept data now
return FALSE;
}
We pass the MFC window handle for our window, and the datatype of the data that will be registered on the clipboard and in what we are interested. The code then calls Windows RegisterDragDrop, and that passes our window WIN32 handle to the OS as a valid target for Drag&Drop. Note that we must already have a window handle here, so this call will not succeed from the constructor of window classes. Mission part one ok. Revoke just calls Windows RevokeDragDrop(). This removes the window handle again from the OS D&D API.

Your mission, should you...

To make our code a bit more generic, I derived a class from ECOleMemDropTarget called ECMaterialDropText. Thats a basic class that will support drag and drop for text, and that will handle the text data type from the clipboard.

We need to connect an instance of this class to a window control. The easiest thing to do is just inherit our own custom controls for this from MFC. Lets do this for a button. We bring up the classwizard, press "Add class... new", enter the name ECButton (our whatever you want to call it), and select CButton as a baseclass. OK, and we have our own custom button class. God, don4t we all love that wizard.

We will put a datamember instance of ECOleMemDropTarget in our button class: ECMaterialDropText *m_TargetDrop. In the constructor we create the memory for it. We call the Register() function of the member. Because MFC doesn4t call any Create members, we will do this in a small methode called InitDrag(). That basically just calls our Register() of ECMaterialDropText.

Next, we add handlers for mousebuttons, mousemove4s and a timer function. We use the left mouse button, you could use the right, middle or the n4th mouse button. OnLButtonDown keeps our coordinates and starts the timer, OnLButtonUp stops the timer. The OnTimer method checks if the mouse cursor is still in the window.

Why do we do all this? Well, we only want to start a drag and drop if the user has pressed and moves the mouse in the window (I choose a distance of 10 pixels). The timer checks if that is the case, and if the mouse is outside the button (and a drag and drop not started), it cancels the action. This also prevents a user from pressing the mouse button outside of our window control, and the moving and releasing inside of the control. Ah users, difficult people. The world would be so good without them :-)

The real action for the drag and drop is started in OnMouseMove. If we did the minimum distance we take the text from the control, and pump it to the COleDataSource to start a drag. That part is described in other good articles in the Clipboard area on this great site. And DoDragDrop() starts our action.

Action!

The Drag & Drop API will now modally begin scanning our mouse moves and the windows the mouse is in. If it arrives in our button or one of the registered other drag and drop windows, the API will call the IDropTarget::DragEnter member. We call GotEnter() for our parents, in our case for ECMaterialDropText::GotEnter().

DragEnter must set a constant giving GUI feedback on the action the user can do. For our code, we just call DROPEFFECT_LINK, one of the constants for drag and drop. I suggest you look them up in the MFC docs.

When we move inside a registered D&D window, the D&D API will call IDropTarget::DragOver(), and we call GotDrag(); My implementation from the code does some checking for runtime classes and depending on the window we are in sends some GUI feedback. Check out the implementation in ECMaterialDropText.cpp. Note that Windows itself shows the classical not valid drop cursor if the window the cursor is over is not registered. We also return one of the constants to give GUI feedback for the mouse cursor.

Last, if the user releases the mouse button in a registered window, we get a "notification" call on IDropTarget::Drop(). The code there checks if the data that the D&D API placed in the clipboard is OK for us, and if so calls GotDrop(). We retrieve the text data, and set it in our control.

The D&D API on exit of Drop() returns after the modal loop of DoDragDrop(); and we free the clipboard data. Mission accomplished!

Remarks

Most of the code in the sample is really cut and paste, added after we derived controls with the classwizard. All the mouse button and move stuff is the same, you could put this in a generic class and inherit from it (if you like multiple inheritance).

Dont forget the all important AfxOleInit() in your code. If you dont add that one the Register function will fail.

Error feedback for the code could be better. Hey, I wrote this sample up in an hour or two...

The sample

The sample shows all I wrote down above. As they say, one code snippet shows more then 100000 lines of documentation. If it seems overwhelming at first, just dig in. For reading on the COM stuff, I would suggest a copy of Don Box excellent COM book.

If you have questions, gimme a mail at erik.vangrunderbeeck@village.uunet.be. But do keep in mind that to answer my mail on a regular base, I have to dig through 300 emails a day, and that means 2 weeks between receipt and reply (unless you send mail like "I would like you to have my son..."). Nah. My wife wouldnt like that ;-)

Have fun and write some great code

Downloads

Download demo project - 31 Kb


Comments

  • Comme lisseur GHD est le meilleur choix pour vous

    Posted by iszrpj674 on 07/16/2013 01:04am

    Le Param cadeau ordonné a le ghd mouette V Classic styler dans une riche rubis métallique finish.Suitable pour tous les types de cheveux, ce styler la même funksjonene comme la mouette V Classic styler mode veille habitude ghd inkludert automatique, spenning de vente universel et un fil extra-longue Rotary pour y distillat frihet totale comme vous le style. A Svart vattert sak qui intègre également un tapis de résistant à la chaleur hendig intelligent, plein de plomb, ce casque élégant [url=http://bbeatsinorge.cabanova.com/]lisseur ghd pas cher[/url] Processus de changements de couleur de la texture de surface un peu de cheveux colorés et décolorés. Par conséquent, il est particulièrement important d'éviter plus de stress à la surface de l'ajout håret.I coloré, l'une des plaques soutenus par des ressorts et donner si vous utilisez trop de force au cours de plaques mobiles brevetés stylingen.De fournir une protection supplémentaire et est trois fois plus lisse que disques classiques et de réduire considérablement la friction. En outre, l'une des plaques pris en charge par un ressort et laisser la place si vous utilisez trop de force durant le coiffage. [url=http://bbeatsinorge.cabanova.com/]lisseur ghd pas cher[/url] Troisièmement, ils ont également arrondis barils qui peuvent faire un fer GHD plus polyvalent que beaucoup d'autres types d'appareils de coiffure sur le marché. Si vous souhaitez modifier votre chevelure est souvent avantageux d'utiliser défrisants ghd peut aussi créer des vagues, sauts et loops.Endelig, vous devez sélectionner un fer GHD est conçu pour une utilisation dans une explosion ou frange. GHD IV styler Mini est parfait pour beaucoup moins de cheveux. Combinez ces excellentes caractéristiques redresseurs les plus complets, mais il est plus facile à utiliser sur des petits morceaux de hair.Maybe vous savez ce ghd lisseur

    Reply
  • what’s the different between clarisonic mia and mia2

    Posted by iouwanzi on 06/05/2013 07:36pm

    [url=http://www.miaclarisonicaustralia.org/]clarisonic mia online[/url] Introduktion til Beats by Dr. Dre Executive Hovedtelefoner Direktionen repræsenterer en ny karakteristisk, sofistikeret design for Beats By Dr. Dre brand, der fokuserer på håndværk ved hjælp af førsteklasses materialer såsom aluminium, rustfrit stål og læder. Den bløde læder pandebånd og komfortable ørekopper er designet til lange slid og en unik sammenfoldeligt design gør Beats Executive hovedtelefoner nem at bære on-the-go. Den administrerende har overlegen Active Noise Cancellation (ANC) performance, tunet til uafbrudt lytning nydelse ved 35.000 fod, og overalt i mellem og med iOS kompatibel mikrofon kabel, det giver fuld telefon funktionalitet, herunder besvar afslut, opkald venter, switching og stemmekommandoer . [url=http://www.miaclarisonicaustralia.org/]clarisonic mia 2[/url] IOC og LOCOG ikke havde reageret på en anmodning om at kommentere på tidspunktet for offentliggørelsen. Den officielle sponsor, der er mest tilbøjelige til at føle sig mest forurettede ved stunt er Panasonic.England fodboldspillere brugte Dr. Dre hovedtelefoner ved Euro 2012 for at undgå pressen. Hovedtelefonerne voksede i popularitet på Beijing 2008 Olympiske Lege, efter at selskabet gav dem til basketball stjerne LeBron James, og han gav dem ud til medlemmer af Team USA.Den baghold markedsføring initiativet kommer i hælene på en protest – iværksat af amerikanske sportsfolk, herunder 400m løber Sanya Richards-Ross – kritisere regel 40 i IOC adfærdskodeks. Reglen forbyder atleter fra at nævne deres personlige sponsorer på sociale medier under legene. [url=http://www.australiaclarisonic.com/clarisonic-pro]clarisonic pro[/url] En virkelig afgørende element i de beats forsyne trådløse hovedtelefoner bør virkelig være deres evne til at fange den surround sound effekt fra musikprogrammet gnidningsløst i dine ører. Enheden, uafhængig af tråd, hvis dart den rungende lyd i kontrolleret måde i dine ører, du ikke dybest set høre det, men forstå sin essens også! Dette er faktisk en indbegrebet træk hovedtelefonerne burde besidde. Spændingen når endnu et niveau, hvis du bare kan strejfe om i dit hus, og stadig tage glæde i musikken – enheden er trådløs! Dybden i den musikstykke kan være fuldstændig måles ved dig på denne måde. Funktionen af støjdæmpning er også ekstremt vigtigt, da det fjerner alle de eksterne forstyrrelser og unødig støj effekter og lader dig høre kun det nødvendige indhold af lydfilen. Den trådløse monster magt beats hovedtelefoner med sådanne funktioner er ønskeligt, da du når et ekstra niveau inden for grænserne af at lytte til god musik. For eksempel, hvis der er en fest på din plads, så kan du ikke nyde nogle eksklusive musik gemt i din mobiltelefon med almindelige hovedtelefoner medmindre den har netop nævnte funktion.

    Reply
  • Hva ville livet fremover vil bli mer fargerik Studio

    Posted by mantouhmmm on 06/03/2013 07:59pm

    [url=http://www.beatsbydrestudio.moonfruit.com/]beats by dre studio[/url] dette er lett å finne fra ulike nettsteder som har blitt prøvd og testet over tid. De trommerytmer er en viktig og en svært viktig del av beats samling uansett hva slags valdet du skriver skal de rap beats eller Jazz slår trommer er veldig viktig siden de gir en god følelse til composition.Visit ulike nettsteder og prøve litt av beats som er der og lytte til dem og prøve hva som tilbys. Besøke nettsteder som tilhører de ulike musikkproduksjon skoler for noen tips som hjelper deg i å kombinere din gratis rap beats og andre musikksjanger beats. Å kunne laste ned beats på nettet en av hemmelighetene er å slå sammen flere e-postlister som slår nedlasting nettsteder de vil gi deg siste nytt om downloads. [url=http://www.beatsnorgedre.qsite.dk/]Beats norge[/url] Lav overflod er fortsatt Studio fokus - forutsatt tiltalende akseptabelt i lav frekvens. Ikke som Tour, er Flat lav overflod tykkere og enklere, ingen overdriver bottomward men bare affære behovene til musikk som Hip-Hop. Topp overflod er en av de aspektene som vi aksepterer kritisert on Tour - det er for aciculate og ikke omgjengelige i det hele tatt. Mens Flat betaler ekstra absorpsjon til antitese og lav overflod - litt "overkompensasjon" på toppen frekvens, motvektstrucker og litt defekt av detaljer. Derfor er som en dyktig Flat artikulasjon sentrert i gjennomsnittlig overflod og lav overflod som ikke er faktisk akseptabelt for som liker flammer akutt stemme. På slutten av artikkelen, anerkjennelse jeg hotsalesmart.com til deg, Monster beats by dr. dre flat alene er $ 169 til $ 219 for chargeless forsendelsen hjem. [url=http://www.beatsdrenorge.webgarden.com/]Monster Beats norge[/url] Her er en syv trinns formel for å lage musikk: Trinn 1: Velg materiale til sangen din. Hvis du bruker samples, kompilere alle lydene som du ønsker i din sang ordningen. Du trenger basstrommer, perkusjon, basslinjer, melodiske leder, vokal, pads, og lyden effects.Step2: Song struktur. Forstå hva hver instrumenter rolle er i sangen din vil gi deg en bedre forståelse hva hvert instrument er ment å do.Step3: Få musikken ned. Dette er prosessen med å samle inn dine sang uten redigering. Få en kladd av hva sangen kan høres ut som. Begynn med Beats By Dre Solo først for å få rytmen i sangen går. Deretter ta andre virkemidler i en freestyle måte bare for å få en idé om hva den endelige lyden vil bli.

    Reply
  • Obtener una nueva plancha de pelo Ghd

    Posted by hanmeihm on 05/30/2013 05:10am

    [url=http://www.planchasghdbaratasonline.com/]planchas de pelo ghd[/url] Necesita la medianoche ghd un regalo ideal para cualquier miembro de la chica tipo de cuidado de la familia ni de los seguidores del estilo Si eres uno de ellos, usted debe pensar en el actual d¦ficit de GHD estilo fresco del cilindro. Este tipo de hierro restringido el pelo peinado de descarga es de hecho muy popular, adems de que llegue las fiestas, la actual cabeza de GHD rosa de metal del pelo alisado es en realidad el aumento de los bastidores. [url=http://www.planchasespanaghdtop.net/plancha-pelo-ghd/]plancha pelo ghd[/url] ghd ha sido aclamado como uno de los mejores (si no el mejor) de la marca de planchas para el pelo alrededor. Yo quera una para las edades, pero finalmente pongo la compra en espera de lo que yo pensaba que eran razones muy pr¢cticas. Desde que mi cabello es lacio natural pens que gastar dinero en una plancha no tiene mucho sentido, aunque tena capacidades de estilo adicionales aparte de simplemente enderezar. Finalmente tuve la oportunidad de ver esta plancha en mi lista de deseos cuando ghd (que significa "buen da del pelo") me envi una de sus nuevas Stylers caramelo . Bueno, al parecer me he estado perdiendo todos estos aos! Inspirado en favoritos sweetshop retro, la coleccin cuenta con el caramelo ghd IV styler en tres colores de edicin limitada: la menta, limn y violeta. Yo he optado por la Casa de Moneda, que es super lindo. [url=http://www.ghdplanchasde.blinkweb.com/]planchas ghd baratas[/url] Ghd gold classic styler, completa el acento styler con la estera de calefaccin agresivo, y dos clips de seccionamiento, planchas de pelo GHD es el mtodo basal, a los estilos de anestsicos. El estilo de tus cabellos se podra considerar un desafo, as que utilice su planchas GHD trenzas para casi cualquier acabado de lo banal maravilloso.

    Reply
  • CHI lilla Guitar Collection Keramisk

    Posted by motherdhmm on 05/30/2013 04:17am

    [url=http://www.blog.cheapbeatsbydre.co.nz/beats-by-dre-headphones]beats by dre headphones[/url] Når som helst vi alle kan muligvis korrekt øge de faktiske personlige tresses, arbejder med den rigtige sort forventet aminosyrer, sundhed ernæringsmæssige vitamin kosttilskud, sammen med ernæringsmæssige vitaminer, der er nødvendige for at passende fremskridt med hinanden med velfærd i tresses, den faktiske visse 55% din personlige krøllede hår slutdato tidlig ejakulation er definitivt faktisk udføres underrette de faktiske omstændigheder på dette tidspunkt. [url=http://www.blog.cheapbeatsbydre.co.nz/]beats by dre nz[/url] Denne specifikke helbredstilstand kan opstå på grund af flere årsager. Fra tre eller fire måneder efter en sygdom eller en større operation, kan patienten lider af hårtab. Dette er som regel midlertidige og er relateret til stress af deres særlige sygdom. En anden årsag [url=http://www.buy-beatsdrdre.com/]beats by dre australia[/url] Få et glattejern som din frisør også ville bruge. De fleste frisør saloner har brug for unedbrydelige glattejern som ghd fladjern tilbud holder til at blive brugt hver eneste dag. Derfor har hoveddelen af saloner verden over valgt at benytte GHD glattejernene.

    Reply
  • RichEdit

    Posted by Legacy on 04/22/2002 12:00am

    Originally posted by: Reza

    Great job. I wonder why can not I use RichEditCtrl for drag and drop. Any help?

    Reply
  • How to drag and drop file and folder

    Posted by Legacy on 08/15/2000 12:00am

    Originally posted by: kumars

    Can someone give me some guide on how to do this on a DirTree with Files and Folders.

    Thank you

    Suresh

    Reply
  • very clear briefing of your sample code!!!

    Posted by Legacy on 04/26/2000 12:00am

    Originally posted by: sirigudi

    Thanks a lot for your sample code & the explanation along with it.
    It was of great help for me.
    Sirigudi.

    Reply
  • sample's struct is very clear.

    Posted by Legacy on 03/02/2000 12:00am

    Originally posted by: motse

    thanks , i get very clear about this samples. it's a very
    good MFC design structure.

    Reply
  • Interesting side effect - Part 2

    Posted by Legacy on 12/12/1999 12:00am

    Originally posted by: Patrick Smout

    Hi,
    
    

    The problem that the listbox is filled up with numerous copies when one of its own strings is dropped on it, is caused by the running timer. To solve this problem it is sufficient to kill the timer once a drag and drop operation is initiated. You can make the same modifications to the code for the other controls. BTW, the solution for this problem submitted by Hilda I.Figueroa is unsafe because CacheGlobalData() uses hMem after the memory is freed (does it work anyway?).

    Best regards,

    Patrick

    // *****************************************************************
    // OnMouseMove
    // *****************************************************************
    void CDragDropListBox::OnMouseMove(UINT nFlags, CPoint point)
    {
    if(m_TimerID > 0)
    {
    // check if we really moved enough
    int iX = m_StartPoint.x - point.x;
    int iY = m_StartPoint.y - point.y;
    if((iX*iX + iY*iY) > MINIMUM_MOVE_SQUARE)
    {
    // Insert next 2 lines
    KillTimer(m_TimerID);
    m_TimerID = 0;

    COleDataSource* pSource = new COleDataSource();
    if(pSource)
    {

    Reply
  • Loading, Please Wait ...

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

Top White Papers and Webcasts

  • Packaged application development teams frequently operate with limited testing environments due to time and labor constraints. By virtualizing the entire application stack, packaged application development teams can deliver business results faster, at higher quality, and with lower risk.

  • Java developers know that testing code changes can be a huge pain, and waiting for an application to redeploy after a code fix can take an eternity. Wouldn't it be great if you could see your code changes immediately, fine-tune, debug, explore and deploy code without waiting for ages? In this white paper, find out how that's possible with a Java plugin that drastically changes the way you develop, test and run Java applications. Discover the advantages of this plugin, and the changes you can expect to see …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds