Link to home
Start Free TrialLog in
Avatar of hplus
hplus

asked on

CListCtrl Drag and Drop

I'm having trouble implementing a CListCtrl with drag&drop support.  The problem is I can't seem to get the CListCtrl registered as a drop target.  I'm NOT using Doc/View Architecture so I have to use a COleDropTarget.  I have a COleDropTarget derived object as a member of my CListCtrl and I am calling COleDropTarget::Register in CListCtrl::Create.  The Register function always fails.  And it doesn't recognize it as a drop target.
ASKER CERTIFIED SOLUTION
Avatar of Meir Rivkin
Meir Rivkin
Flag of Israel image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
In my Dialog-based AppWizard test app, I had to add:

  if ( !AfxOleInit() ) {
      AfxMessageBox("OhNo!");
      return FALSE;
  }
at the beginning of InitInstance.
=-=-=-=-=-=-=-=-=-=-=-
I then created a class derived from COleDropTarget:

class CMyDropTarget : public COleDropTarget
{
public:
    virtual DROPEFFECT OnDragOver( CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point );
};

I put its implementation at the top of the dlg's .cpp file:
  DROPEFFECT CMyDropTarget::OnDragOver( CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point )
  {
    return( DROPEFFECT_COPY );
  }

=-=-=-=-=-=-=-=-=-=-=-
I added this line at the top in the dialog's header:
   #include <afxole.h>

and this line to the dlg's class def:

    CMyDropTarget m_DropTarget;

I added this line in OnInitDialog:

    BOOL fRet= m_DropTarget.Register( GetDlgItem( IDC_LIST1 ) );

=-=-=-=-=-=-=-=-=-=-=-
To avoid an ASSERT at program exit, I used the ClassWizard to added a DestroyWindow handler to the dlg:

   BOOL CD5Dlg::DestroyWindow()
   {
      m_DropTarget.Revoke();
      return CDialog::DestroyWindow();
   }

=-=-=-=-=-=-=-=-=-=-
As you can see, in my test app, I avoided deriving from CListCtrl -- I create and maintain the DropTarget handling in the parent dialog.  You may find this the easier technique -- at least when starting out.  When you really get the hang of it, you can go ahead and do the DropTarget handling in your CListCtrl-derived class.

-- Dan
Avatar of hplus
hplus

ASKER

Thanks for your replies.  To sedgwick, my email address is shoguntim@aol.com.  To Dan, I think i tried it this way too, but the difference was that I was using a CFrameWnd instead of a CDialog as the parent window.  But I'm going to try this out once i get back home.  
hi hplus,
Did you try my solution?  I see that you feel that it was flawed in some way, since you accepted sedgwick's answer.

I'm quite sure that persons who later pay to see this PAQ will want to see that excellent code.  Could you post the relevant details and describe what was wrong with my solution?

Thanks!

-- Dan
would it help if i'll post mine?
DDListCtrl: Extended List Control class with local drag & drop and automatic scrolling, plus OLE drap & drop:

//DDListCtrl.h
////////////////////////////////////////////////////////////////////
// DDListCtrl -- Extended List Control class with local drag & drop and
//               automatic scrolling, plus OLE drap & drop
//
// Author: Jean-Claude DAUPHIN, CI/INF UNESCO
//

#if !defined(AFX_DDLISTCTRL_H__E418A1A1_BA82_11D2_B742_0000E2039B5F__INCLUDED_)
#define AFX_DDLISTCTRLEXT_H__E418A1A1_BA82_11D2_B742_0000E2039B5F__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000

/////////////////////////////////////////////////////////////////////////////
// COleListCtrlDropTarget window

class COleListCtrlDropTarget : public COleDropTarget
{
// Construction
public:
    COleListCtrlDropTarget();

// Implementation
public:
    virtual ~COleListCtrlDropTarget();  
   
   /**
    * These members MUST be overridden for an OLE drop target
    * See DRAG and DROP section of OLE classes reference
    **/
   DROPEFFECT OnDragEnter(CWnd* pWnd, COleDataObject* pDataObject, DWORD
                                                dwKeyState, CPoint point );
   DROPEFFECT OnDragOver(CWnd* pWnd, COleDataObject* pDataObject, DWORD
                                               dwKeyState, CPoint point );
   void OnDragLeave(CWnd* pWnd);              
   
   BOOL OnDrop(CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT
                                          dropEffect, CPoint point );
};

//////////////////////////////////////////////
// Structure used for transfering list data
//
//typedef struct _LVITEM {
//    UINT mask;
//    int iItem;
//    int iSubItem;
//    UINT state;
//    UINT stateMask;
//    LPTSTR pszText;
//    int cchTextMax;
//    int iImage;
//    LPARAM lParam;
//#if (_WIN32_IE >= 0x0300)
//    int iIndent;
//#endif
//} LVITEM, FAR *LPLVITEM;

struct ListInfo
{
      LV_ITEM lvi;
      char szLabel[256];
};

//////////////////////////////////
// Control types

enum {CT_LIST, CT_EDIT, CT_TREE};

/////////////////////////////////////////////////////////////////////////////
// CDDListCtrl window

class CDDListCtrl : public CListCtrl
{

// Construction
public:
      CDDListCtrl();

// Attributes
private:
      /**
     * Needed to make this control an OLE data SOURCE
       * (see OnLButtonDown)
     **/
       COleDataSource m_COleDataSource;

public:

// Operations
public:
    /*****  
     * Initialization method REQUIRED for controls created by
     * a dialog template. Dynamically created controls are  
     * initialized in the OnCreate. OnCreate is not called for
       * controls created by a template since the Windows controls
       * are created before the CWnd objects.
     *****/
    void Initialize();
   
      /**
     * Get and set the source rectangle for drag/drop operation
     **/
      void  SetDragSourceRect();
    CRect GetDragSourceRect();

// Overrides
      // ClassWizard generated virtual function overrides
      //{{AFX_VIRTUAL(CDDListCtrl)
      protected:
      //}}AFX_VIRTUAL

// Implementation
public:
      virtual ~CDDListCtrl();

    /*****
     * COleListCtrlDropTarget, derived from COleDropTarget gives us
     * the functionality to be an OLE drop target.
     * COleListCtrlDropTarget.Register() must be called to register
     * the CWnd as an OLE drop target.
     *****/
    COleListCtrlDropTarget m_DropTarget;
      CRect m_DragSourceRect;

    /**
       * Variables used for automatic scrolling
       **/
      int m_nDelayInterval;
      int m_nScrollMargin;
      int m_nScrollInterval;

      BOOL        m_bDragging;
      CImageList* m_pImageList;
      int         m_iDragItem; // Source item index on which d&d started
      int         m_iDropItem; // Target item index

      BOOL        m_bSource;   // True if list is source
      BOOL        m_bTarget;   // True if list is target

      /**
       * Options available
       **/
      BOOL        m_bLocalDD;   // True if local Drag&Drop allowed
      BOOL        m_bScrolling; // True if auto scrolling
      BOOL        m_bRemove;    // True if D&D items must be removed

      void SetLocalDD(BOOL bState)   { m_bLocalDD   = bState; }
    void SetScrolling(BOOL bState) { m_bScrolling = bState; }
      void SetRemove(BOOL bState)    { m_bScrolling = bState; }

      /**
       * Array used for saving D&D item indexes and delete them
       **/
      int*        m_pSaveIndItem;
      int         m_nItem;

      void RemoveHighlightFromDropTarget();
      int HighlightDropTarget (CPoint point);
      void SelectDropTarget(int iItem);

      // Generated message map functions
protected:

      //{{AFX_MSG(CDDListCtrl)
      afx_msg void OnTimer(UINT nIDEvent);
      afx_msg void OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult);
      afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
      //}}AFX_MSG

      DECLARE_MESSAGE_MAP()
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_DDLISTCTRL_H__E418A1A1_BA82_11D2_B742_0000E2039B5F__INCLUDED_)


//DDListCtrl.cpp
////////////////////////////////////////////////////////////////////
// DDListCtrl.cpp -- implementation file
//
// Extended List Control class with OLE Drag & Drop and optional:
//             - local drag & drop
//             - automatic scrolling,
//             - Removing of dragged items
//
//
// Author: Jean-Claude DAUPHIN, CI/INF UNESCO
//
// The following source of information have been invaluable for
// succeeding in this task:
//
// Lstdrg.exe -- Microsoft sample which implement OLE drag & drop
// for a ListBox Control and an Edit Control.
//
// Wicked code article written by J. Prosise (MSJ August 98)
///////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "DDListCtrl.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CDDListCtrl


//------------------------------------------------------------------------------
// void CDDListCtrl::Initialize()
//
// Calls the Register method of m_DropTarget to register this control as a drop
// target with the OLE dll's.
//
// We need to call this method in the Dialog CMyDlg::OnInitDialog() or
// CFormView::OnInitialUpdate for controls created by a dialog template since
// the OnCreate does not get called for template created  controls (this is
// because the windows controls get created before the CWnd wrappers).
//-----------------------------------------------------------------------------
void CDDListCtrl::Initialize()
{  
    // Register the COleDropTarget object with the OLE dll's
    BOOL bSuccess = m_DropTarget.Register(this);
    if (!bSuccess)
       AfxMessageBox("Ole Register Drop Target Failed");    
}                                                                            


CDDListCtrl::CDDListCtrl()
{
      m_iDragItem  = -1;
      m_bDragging  = FALSE;
      m_pImageList = NULL;

      m_bSource = FALSE;
      m_bTarget = FALSE;

      // By default, all options are available
      m_bLocalDD   = TRUE; // Local Drag & Drop
      m_bScrolling = TRUE; // Auto Scrolling
      m_bRemove    = TRUE; // Remove items

      m_pSaveIndItem = NULL;
      m_nItem = 0;

    m_nDelayInterval = 300;  // Default delay interval = 500 milliseconds
      m_nScrollMargin = 10;    // Default scroll margin = 10 pixels
      m_nScrollInterval = 100; // Default scroll interval = 200 milliseconds
}

CDDListCtrl::~CDDListCtrl()
{
      // Delete the image list created by CreateDragImage
      if (m_pImageList != NULL)
            delete m_pImageList;
}


BEGIN_MESSAGE_MAP(CDDListCtrl, CListCtrl)
      //{{AFX_MSG_MAP(CDDListCtrl)
      ON_WM_TIMER()
      ON_NOTIFY_REFLECT(LVN_BEGINDRAG, OnBegindrag)
      //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDDListCtrl message handlers

//---------------------------------------------------------------------
// int CDDListCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
//
// THIS FUNCTION ONLY GETS CALLED FOR DYNAMICALLY CREATED CONTROLS.
//
// FOR CONTROLS CREATED BY A DIALOG TEMPLATE , Initialize() must be
// called in the OnInitialUpdate method of the CFormView or CMyDialog.
//---------------------------------------------------------------------
int CDDListCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CWnd::OnCreate(lpCreateStruct) == -1)          
        return -1;
     
      //SetExtendedStyle(LVS_EX_GRIDLINES);
   
      // Register the COleDropTarget object with the OLE dll's
    BOOL bSuccess = m_DropTarget.Register(this);
   
    if (!bSuccess)
    {
       AfxMessageBox("Ole Register Drop Target Failed");    
       return -1;
    }
     return 0;
}

//-------------------------------------------------------------------------------
// void CDDListCtrl::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult)
//
// LVN_BEGINDRAG notifies a list view control's parent window that a drag-and-drop
// operation involving the left mouse button is being initiated. Message
// reflection lets us handle messages for the control, within the control itself.
//-------------------------------------------------------------------------------

void CDDListCtrl::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult)
{
      NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
      
    int iItem =  ((NM_LISTVIEW*) pNMHDR)->iItem;

      m_iDragItem = iItem;   // Item on which D&D is started
      m_iDropItem = -1;      // Not yet known
      m_bDragging = TRUE;    // D&D started
      
      m_bSource = TRUE;      // We start D&D on the source
      m_bTarget = FALSE;     // Not yet known

      m_nItem = GetSelectedCount();    // Used for counting number of selected items
      
      // Allocate an array for saving item indexes
      m_pSaveIndItem = new int[m_nItem];
      
      // Create global memory for sharing dragdrop data, we allocate
      // space for 2 int and nItem ListInfo structures
    HGLOBAL hgData = GlobalAlloc(GPTR,m_nItem*sizeof(ListInfo)+2*sizeof(int));  
    ASSERT(hgData!=NULL);
    char* p = (char*) GlobalLock(hgData);
    ASSERT(p!=NULL);

      // Place control type in first 2 bytes
      *(int *) (p) = CT_LIST;
     
      // Place number of list items in next 2 bytes
      *(int *) (p+sizeof(int)) = m_nItem;
      
      //  Then the nItem ListInfo structures will start at:
    ListInfo* lpData = (ListInfo*) (p + 2*sizeof(int));

      int jItem = -1;
    int i = 0;
      while ((jItem = GetNextItem(jItem,LVNI_ALL | LVNI_SELECTED)) > -1)
    {
       ASSERT(i>=0 && i <m_nItem);
         ZeroMemory(&lpData[i], sizeof(ListInfo));
      
         lpData[i].lvi.mask       = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE;
         lpData[i].lvi.stateMask  = LVIS_DROPHILITED | LVIS_FOCUSED | LVIS_SELECTED;
       lpData[i].lvi.pszText    = (char*) &(lpData[i].szLabel);
         lpData[i].lvi.iItem      = jItem;
         lpData[i].lvi.cchTextMax = 255;
      
         BOOL bSuccess = GetItem(&(lpData[i].lvi));
         ASSERT(bSuccess);
         m_pSaveIndItem[i] = jItem;
       i++;
      }
      
      // Cache the data, and initiate DragDrop
    m_COleDataSource.CacheGlobalData(CF_TEXT, hgData);          

      // Set drag/drop source rectangle (screen coord)
    SetDragSourceRect();
   
    DROPEFFECT dropEffect =
       m_COleDataSource.DoDragDrop(DROPEFFECT_COPY|DROPEFFECT_MOVE,NULL);  
     
     
    if (m_bRemove && (dropEffect&DROPEFFECT_MOVE)==DROPEFFECT_MOVE)    
    {
        //  Delete items in reverse order so that indexes are preserved
         for (i=m_nItem-1; i>=0; i--)
         {
          jItem = m_pSaveIndItem[i];
              // If the list is source and target and..
                  // Index of dragged item will change if dropped above itself
              if (m_bSource && m_bTarget)
              {
                 ASSERT(m_iDropItem>=0);
                 if (jItem > m_iDropItem) jItem += m_nItem;
          }
              BOOL bSuccess = DeleteItem(jItem);
              ASSERT(bSuccess);
         }
        // Set the list box selected item to the previous item
        //SetCurSel(nItem-1);                                            
    }
      m_bSource = FALSE;
      m_bTarget = FALSE;
      m_iDropItem = -1;
      delete[] m_pSaveIndItem;
      m_pSaveIndItem = NULL;
      m_nItem = 0;
      *pResult = 0;
}

//----------------------------------------------------------------------------------
// void CDDListCtrl::OnTimer(UINT nIDEvent)
//
// Implements automatic scrolling by setting a timer when the cursor moves
// within m_nScrollMargin pixels (default=10) of the list ctrl window's top or
// bottom border. The relevant code is in COleListCtrlDropTarget::OnDragOver:
//
// if (( point.y <= pDDList->m_nScrollMargin) ||
//              (point.y >= cy - pDDList->m_nScrollMargin))
//         {
//              TRACE("\nTimer set for scrolling");
//              pDDList->SetTimer (1, pDDList->m_nDelayInterval, NULL);
//         }
// Initially, the timer is set to fire after 500 milliseconds. If the cursor moves
// before the timer fires, the timer is reset. If however the cursor relains
// motionless until the timer interval expires, a WM_TIMER ensues and
// CDDListCtrl::OnTimer scrolls the window by sending it a WS_VSCROLL message.
// OnTimer also programs the timer to fire again after 200  milliseconds so that
// subsequent scrolls will hapen more quickly. The messages don't stop until the
// cursor is moved or the list view is scrolled as far as it possibly can.
//----------------------------------------------------------------------------------
void CDDListCtrl::OnTimer(UINT nIDEvent)
{
      CListCtrl::OnTimer(nIDEvent);
      if (!m_bScrolling)
            return;
   
      // Reset the timer.
      SetTimer (1, m_nScrollInterval, NULL);

      // Get the current cursor position and window height.
      DWORD dwPos = ::GetMessagePos ();
      CPoint point (LOWORD (dwPos), HIWORD (dwPos));
      ScreenToClient (&point);

      CRect rect;
      GetClientRect (rect);
      int cy = rect.Height ();
   
      // Scroll the window if the cursor is near the top or bottom.
      if (point.y <= m_nScrollMargin)
      {
            int iFirstVisible = GetTopIndex ();

            m_pImageList->DragShowNolock (FALSE);
            SendMessage (WM_VSCROLL, MAKEWPARAM (SB_LINEUP, 0), NULL);
            m_pImageList->DragShowNolock (TRUE);

            //  Kill the timer if the window did not scroll, or redraw the
            //  drop target highlight if the window did scroll.
            if (GetTopIndex () == iFirstVisible)
                  KillTimer (1);
            else
            {
                  HighlightDropTarget (point);
                  return;
            }
      }
      else if (point.y >= cy - m_nScrollMargin)
      {
            int iFirstVisible = GetTopIndex ();
            m_pImageList->DragShowNolock (FALSE);

            SendMessage (WM_VSCROLL, MAKEWPARAM (SB_LINEDOWN, 0), NULL);
            m_pImageList->DragShowNolock (TRUE);

            // Kill the timer if the window did not scroll, or redraw the
            // drop target highlight if the window did scroll.
            if (GetTopIndex () == iFirstVisible)
                  KillTimer (1);
            else
            {
                  HighlightDropTarget (point);
                  return;
            }
      }
}

//----------------------------------------------------------------------------------
// int CDDListCtrl::HighlightDropTarget(CPoint point)
//
// Highlights the item on which the cursor is over.
//----------------------------------------------------------------------------------
int CDDListCtrl::HighlightDropTarget(CPoint point)
{
      // Find out which item (if any) the cursor is over.
      UINT nFlags;
      int iItem = HitTest (point, &nFlags);
      if (iItem == -1)
            return iItem;
      
      //  Highlight the item, or unhighlight all items
      //  if the cursor isn't over an item.
      SelectDropTarget (iItem);

      // Return the index of the highlighted item.
      return iItem;
}


void CDDListCtrl::RemoveHighlightFromDropTarget()
{
   if (m_iDropItem >= 0)
   {
      BOOL bSuccess = SetItemState (m_iDropItem, 0, LVIS_DROPHILITED);
        //ASSERT(bSuccess);
        /**
       * Redraw item
         **/
        RedrawItems (m_iDropItem, m_iDropItem);
   }
}

//----------------------------------------------------------------------------------
// void CDDListCtrl::SelectDropTarget(int iItem)
//
// if iItem >= 0, updates the highlighted item, else if iItem<0, unlights all items
//----------------------------------------------------------------------------------
void CDDListCtrl::SelectDropTarget(int iItem)
{
      BOOL bSuccess;
      if (iItem >=0)
      {
         RemoveHighlightFromDropTarget();

         // Highlight the new one
         bSuccess = SetItemState(iItem, LVIS_DROPHILITED, LVIS_DROPHILITED);
         ASSERT(bSuccess);
       RedrawItems (iItem, iItem);
       m_iDropItem = iItem;
         UpdateWindow ();
      }
      else
      {
            for (int i=0; i<GetItemCount(); i++)
            {
                  bSuccess = SetItemState (i, 0, LVIS_DROPHILITED);
                  ASSERT(bSuccess);
            }
            UpdateWindow ();
      }
}

CRect CDDListCtrl::GetDragSourceRect()
{  
     //  return the drag/drop source rect (maintained in view class)
    return m_DragSourceRect;
}

void CDDListCtrl::SetDragSourceRect()
{                                                            
    CRect ListWindowRect;
   
    GetWindowRect(&ListWindowRect);

    // Set drag/drop source rectangle (screen coord)
       // *(maintained in the view class)
    m_DragSourceRect = ListWindowRect;    
}

/////////////////////////////////////////////////////////////////////////////
// COleListCtrlDropTarget - Enable OLE dragdrop for the ListCtrl control

COleListCtrlDropTarget::COleListCtrlDropTarget() {}

COleListCtrlDropTarget::~COleListCtrlDropTarget() {}

//-----------------------------------------------------------------------------------
// DROPEFFECT COleListCtrlDropTarget::OnDragEnter(CWnd* pWnd, COleDataObject*
//           pDataObject, DWORD dwKeyState, CPoint point )
//
// Called by OLE dll's when drag cursor FIRST enters a window that is REGISTERED
//  with the OLE dll's
//
//Parameters
//----------
//
// pWnd        -- Points to the window the cursor is entering.
// pDataObject -- Points to the data object containing the data
//                that can be dropped.
// dwKeyState  -- Contains the state of the modifier keys.
//                This is a combination of any number of the following:
//                MK_CONTROL, MK_SHIFT, MK_ALT, MK_LBUTTON,
//                MK_MBUTTON, and MK_RBUTTON.
//
// point       -- Contains the current location of the cursor in
//                client coordinates.
//
// Return Value : The effect that would result if a drop were
//-------------   attempted at the location specified by point.
//                It can be one or more of the following:
//
//     DROPEFFECT_NONE   -A drop would not be allowed.
//     DROPEFFECT_COPY   -A copy operation would be performed.
//     DROPEFFECT_MOVE   -A move operation would be performed.
//     DROPEFFECT_LINK   -A link from the dropped data to the
//                        original data would be established.
//     DROPEFFECT_SCROLL -A drag scroll operation is about to occur
//                        or is occurring in the target.
//-----------------------------------------------------------------------------------
DROPEFFECT COleListCtrlDropTarget::OnDragEnter(CWnd* pWnd, COleDataObject*
           pDataObject, DWORD dwKeyState, CPoint point )
{
         CDDListCtrl* pDDList = (CDDListCtrl*) pWnd;
 
      // If local Drag&Drop not allowed and point is inside of the
      // source list ctrl, don't allow a drop
      if (!(pDDList->m_bLocalDD) && pDDList->m_bSource)
      {
            CPoint pt = point;
        pWnd->ClientToScreen(&pt); // Convert client point to screen point
        if (pDDList->GetDragSourceRect().PtInRect(pt))
           return DROPEFFECT_NONE;
      }
      
      // Check if the Control key was pressed
    if ((dwKeyState&MK_CONTROL) == MK_CONTROL)
        return DROPEFFECT_COPY; // Copy source text
    else
        return DROPEFFECT_MOVE; // Move source text  
}

//---------------------------------------------------------------------------------
// void COleListCtrlDropTarget::OnDragLeave(CWnd* pWnd)
//
// Called by OLE dll's when drag cursor leaves a window that is REGISTERed with
// the OLE dll's.
//
// pWnd points to the window the cursor is leaving.
//---------------------------------------------------------------------------------
void COleListCtrlDropTarget::OnDragLeave(CWnd* pWnd)
{
         CDDListCtrl* pDDList = (CDDListCtrl*) pWnd;
      pDDList->RemoveHighlightFromDropTarget();

    // Call base class implementation
    COleDropTarget:: OnDragLeave(pWnd);
}

//----------------------------------------------------------------------------------
// DROPEFFECT COleListCtrlDropTarget::OnDragOver(CWnd* pWnd, COleDataObject*
//           pDataObject, DWORD dwKeyState, CPoint point )
//
// Called by OLE dll's when cursor is dragged over a window that is REGISTERed with
// the OLE dll's.
//
//Parameters
//----------
// pWnd        -- points to the window that the cursor is over.
// pDataObject -- points to the data object that contains the data
//                to be dropped.
// dwKeyState  -- Contains the state of the modifier keys.
//                This is a combination of any number of the
//                following:
//                MK_CONTROL, MK_SHIFT, MK_ALT, MK_LBUTTON,
//                MK_MBUTTON, and MK_RBUTTON.
// point       -- Contains the current location of the cursor in
//                client coordinates.
//
//Return Value:
//------------   The effect that would result if a drop were attempted
//               at the location specified by point.
//               It can be one or more of the following:
//
//DROPEFFECT_NONE   A drop would not be allowed.
//
//DROPEFFECT_COPY   A copy operation would be performed.
//
//DROPEFFECT_MOVE   A move operation would be performed.
//
//DROPEFFECT_LINK   A link from the dropped data to the original data would be established.
//
//DROPEFFECT_SCROLL   Indicates that a drag scroll operation is about to occur or is occurring in the target.
//
// Note: OnDragOver is like WM_MOUSEMOVE message, in that CALLS TO IT
// ARE GENERATED REPEATEDLY as the pointer moves around the window
//----------------------------------------------------------------------------------
DROPEFFECT COleListCtrlDropTarget::OnDragOver(CWnd* pWnd, COleDataObject*
           pDataObject, DWORD dwKeyState, CPoint point )
{                              

      CDDListCtrl* pDDList = (CDDListCtrl*) pWnd;

      pDDList->KillTimer (1);

      // If local Drag & Drop not allowed and drop point is inside
      // of the source list ctrl, don't allow a drop.
      if (!(pDDList->m_bLocalDD) && pDDList->m_bSource)
      {
            CPoint pt = point;
          pWnd->ClientToScreen(&pt);   // convert client to screen
        if (pDDList->GetDragSourceRect().PtInRect(pt))
           return DROPEFFECT_NONE;
      }
      
    if (pDDList->m_bScrolling)
      {
          // Stop the scroll timer if it's running.
          pDDList->KillTimer (1);
      }
      // Highlight the drop target if the cursor is over an item.
      int iItem = pDDList->HighlightDropTarget (point);

      if (pDDList->m_bScrolling)
      {
         // Set a timer if the cursor is at the top or
         // bottom of the window.
         CRect rect;
         pDDList->GetClientRect (rect);
         int cy = rect.Height ();

         if (( point.y <= pDDList->m_nScrollMargin) ||
              (point.y >= cy - pDDList->m_nScrollMargin))
         {
              TRACE("\nTimer set for scrolling");
              pDDList->SetTimer (1, pDDList->m_nDelayInterval, NULL);
         }
      }
    if ((dwKeyState&MK_CONTROL) == MK_CONTROL)
        return DROPEFFECT_COPY;
    else
        return DROPEFFECT_MOVE;    
}

//----------------------------------------------------------------------------------
// BOOL COleListCtrlDropTarget::OnDrop(CWnd* pWnd, COleDataObject* pDataObject,
//                 DROPEFFECT dropEffect, CPoint point )
//
// Called by OLE dll's when item is dropped in a window that is REGISTERed with the
// OLE dll's.
//
//Parameters
//----------
// pWnd        -- Points to the window the cursor is currently over.
//
// pDataObject -- points to the data object that contains the data
//                to be dropped.
//
// dropEffect  -- The effect that the user chose for the drop operation. It can be one or more of the following:
//
//DROPEFFECT_COPY   A copy operation would be performed.
//
//DROPEFFECT_MOVE   A move operation would be performed.
//
//DROPEFFECT_LINK   A link from the dropped data to the original data would be established.
//
// point       -- Contains the location of the cursor, in pixels,
//                relative to the screen.
//----------------------------------------------------------------------------------
BOOL COleListCtrlDropTarget::OnDrop(CWnd* pWnd, COleDataObject* pDataObject,
                 DROPEFFECT dropEffect, CPoint point )
{          
    HGLOBAL   hGlobal;

      TRACE("\nOnDrop");

      CDDListCtrl* pDDList = (CDDListCtrl*) pWnd;

      // Stop the scroll timer if it's running.
      pDDList->KillTimer (1);
      
      // Flag the list as target
      pDDList->m_bTarget = TRUE;
      
      // Find out the drop item
      int iItem;
      if (pDDList->GetItemCount() == 0)
            iItem = 0;  // List is empty
      else
      {
         // Find drop element in list
       UINT nFlags;
         point.y += 5;
         iItem = pDDList->HitTest (point, &nFlags);
         if (iItem == -1)
         {
               // Get coordinates of top and bottom visible points
               int iTopItem = pDDList->GetTopIndex();
               int iBotItem = iTopItem + pDDList->GetCountPerPage() -1;
               if (iBotItem > pDDList->GetItemCount()-1)
                     iBotItem = pDDList->GetItemCount() - 1;
               CPoint topPoint, botPoint;
               BOOL bSuccess = pDDList->GetItemPosition(iTopItem, &topPoint);
               ASSERT(bSuccess);
               bSuccess = pDDList->GetItemPosition(iBotItem, &botPoint);
               ASSERT(bSuccess);

               if (point.y <= topPoint.y+5)
                    iItem = 0;
               else if (point.y >botPoint.y)
                  iItem = pDDList->GetItemCount(); // Add at the end
           else
               {
                       // If there was an error adding the text to the control
              // return FALSE so that the text is not removed from
                    // the drop source
                    return FALSE;
               }

         }
      }
    pDDList->m_iDropItem = iItem;
      ASSERT(pDDList->m_iDropItem>=0);

      if (pDDList->m_bSource && pDDList->m_bTarget)
      {      
            // Check that we don't drop on dragged items
            TRACE("\niItem=%d pSaveInItem[0]=%d pSaveInItem[0]=%d",
                            iItem,pDDList->m_pSaveIndItem[0],pDDList->m_pSaveIndItem[pDDList->m_nItem-1]);
            if (iItem >= pDDList->m_pSaveIndItem[0] &&
                iItem <= pDDList->m_pSaveIndItem[pDDList->m_nItem-1])
            {
                // Display an error message if the move is illegal.
                AfxMessageBox (_T ("An item can't be dropped onto itself"));
                pDDList->SelectDropTarget(-1);
                  // If there was an error adding the text to the control
            // return FALSE so that the text is not removed from
                  // the drop source
                  return FALSE;
            }
       }

    // Get List data from COleDataObject
      hGlobal = pDataObject->GetGlobalData(CF_TEXT);
      
      // Get pointer to data
    PVOID p = GlobalLock(hGlobal);    
    ASSERT(p!=NULL);

      // Get the type of source control
      int ctrlType = *(int *) (p);
      if (ctrlType == CT_LIST)
      {
         // Source Ctrl is a list, get number of items
         int nItem = *(int *) ((char*)p + sizeof(int));
         ListInfo* pData = (ListInfo*) ((char*)p + 2*sizeof(int));
       
         // Add the item(s) to the list
            int iNewItem;
         for (int i=0; i<nItem; i++)
         {
            pData[i].lvi.iItem = iItem;
            iItem++;
            iNewItem = pDDList->InsertItem(&(pData[i].lvi));
          ASSERT(iNewItem >= 0);
         }
        
         // Unlight all list items
       pDDList->SelectDropTarget(-1);
        
         // Select the newly added item.
       BOOL bSuccess = pDDList->SetItemState(iNewItem, LVIS_SELECTED, LVIS_SELECTED);
    }
      else
      {
            AfxMessageBox("List -- Source control not defined");
      }
      
      // Unlock memory
    GlobalUnlock(hGlobal);
   
    return TRUE;
}


SelectInfo: Interface for the CSelectInfo class.
A dummy class for demo


//SelectInfo.h

#if !defined(AFX_SELECTINFO_H__F68B2E26_A10D_11D4_8C0D_0050043EB83D__INCLUDED_)
#define AFX_SELECTINFO_H__F68B2E26_A10D_11D4_8C0D_0050043EB83D__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

class CSelectInfo  
{
public:
      CStringArray m_asNames;
      CWordArray m_aRowsVar;
      CWordArray m_aColsVar;
      CWordArray m_aDataVar;
      CWordArray m_aPagesVar;
public:
      CSelectInfo(){}
      virtual ~CSelectInfo(){}

};

#endif // !defined(AFX_SELECTINFO_H__F68B2E26_A10D_11D4_8C0D_0050043EB83D__INCLUDED_)




CListSelectData:
CListSelectData objects store a pointer to the CStringArray object,
initialized externally to contain the complete list of strings from which
the selection  with occur.
 
//ListSelectData.h

class CListSelectData
{
protected:
   // Attributes
   CStringArray* m_pData;

   // Implementation
public:
      CListSelectData(CStringArray* pData);        

      virtual ~CListSelectData();

      // Extract list item indexes
    virtual void FillIndexArray(CListCtrl& listCtrl, CWordArray& aIdx);
   
      // Fill List Ctrl
      virtual void FillListCtrl(CListCtrl& listCtrl);
    virtual void FillListCtrl(CListCtrl& listCtrl, CWordArray& aIdx);
};


//ListSelectData.cpp
////////////////////////////////////////////////////////////////////////////////////
// ListSelectData.cpp -- implementation file for class CListSelectData
//
//
//

#include "stdafx.h"
#include "ListSelectData.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define MAX_ITEMLEN 40

//------------------------------------------------------------------------------
// CListSelectData::CListSelectData(CStringArray* pData)
//
//
// This constructor initializes a CListSelectData object, pData points to an
// array of strings which contains the full list of strings.
//------------------------------------------------------------------------------
CListSelectData::CListSelectData(CStringArray* pData)
{
      ASSERT(pData != NULL);
      m_pData   = pData;
}


CListSelectData::~CListSelectData()
{
}
//---------------------------------------------------------------------------
// void CListSelectData::FillListCtrl(CListCtrl& listCtrl)
//
// Fill the list ctrl with ALL strings from m_pData
//---------------------------------------------------------------------------
void CListSelectData::FillListCtrl(CListCtrl& listCtrl)
{
      LV_ITEM lvI;
      // Initialize LV_ITEM members that are common to all items
      lvI.mask      = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;
      lvI.state     = 0;
      lvI.stateMask = 0;
      lvI.iImage    = 0;

    CString str;
      for (int i = 0; i < m_pData->GetSize(); i++)
      {
            lvI.iItem    = i;
            lvI.iSubItem = 0;
            str          = (*m_pData)[i];
            lvI.pszText  = (LPSTR)LPCTSTR(str);

            lvI.cchTextMax = MAX_ITEMLEN;
            lvI.lParam = (LPARAM) i;
        if (listCtrl.InsertItem(&lvI) == -1)
                AfxMessageBox(_T("ListSelectData::FillListCtrl error"), MB_OK);
      }
}

//+--------------------------------------------------------------------------
// void CListSelectData::FillListCtrl(CListCtrl& listCtrl, CWordArray& aIdx)
//
// FILL THE LIST CTRL with strings from m_pData whose indexes are stored in
// aIdx array.
//---------------------------------------------------------------------------
void CListSelectData::FillListCtrl(CListCtrl& listCtrl, CWordArray& aIdx)
{
      LV_ITEM lvI;
      // Initialize LV_ITEM members that are common to all items
      lvI.mask      = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;
      lvI.state     = 0;
      lvI.stateMask = 0;
      lvI.iImage    = 0;

    CString str;
      for (int i = 0; i < aIdx.GetSize(); i++)
      {
            int idx = aIdx[i];
            ASSERT(idx>=0 && idx<m_pData->GetSize());

            lvI.iItem    = i;
            lvI.iSubItem = 0;
            str          = (*m_pData)[idx];
            lvI.pszText  = (LPSTR)LPCTSTR(str);

            lvI.cchTextMax = MAX_ITEMLEN;
            lvI.lParam = (LPARAM) idx;
            if (listCtrl.InsertItem(&lvI) == -1)
                AfxMessageBox(_T("ListSelectData::FillListCtrl error"), MB_OK);
      }
}

//-----------------------------------------------------------------------------
// void CListSelectData::FillIndexArray(CListCtrl& listCtrl, CWordArray& aIdx)
//
//
// FILL THE INDEX ARRAY with the indexes (in m_pData) of the strings contained
// in the list control.
//-----------------------------------------------------------------------------
void CListSelectData::FillIndexArray(CListCtrl& listCtrl, CWordArray& aIdx)
{
      LV_ITEM lvI;
      // Initialize LV_ITEM members that are common to all items
      lvI.mask       = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;
      lvI.state      = 0;
      lvI.stateMask  = 0;
      lvI.iImage     = 0;
      lvI.cchTextMax = MAX_ITEMLEN;
      TCHAR sText[MAX_ITEMLEN];
      int nIdx = listCtrl.GetItemCount();
      aIdx.SetSize(nIdx);

      for (int i = 0; i < listCtrl.GetItemCount(); i++)
      {
            lvI.iItem       = i;
            lvI.iSubItem    = 0;
               lvI.pszText     = (LPSTR)LPCTSTR(sText);
            lvI.cchTextMax  = MAX_ITEMLEN;
            listCtrl.GetItem(&lvI);
            aIdx[i]         = (short)lvI.lParam; // Store String array(m_pData) index
      }
}




// ddDemoDlg.h : header file
//

#if !defined(AFX_DDDEMODLG_H__F68B2E1C_A10D_11D4_8C0D_0050043EB83D__INCLUDED_)
#define AFX_DDDEMODLG_H__F68B2E1C_A10D_11D4_8C0D_0050043EB83D__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

/////////////////////////////////////////////////////////////////////////////
// CDdDemoDlg dialog

#include "DDListCtrl.h"

class CSelectInfo;
class CListSelectData;

class CDdDemoDlg : public CDialog
{
// Construction
public:
      CDdDemoDlg(CSelectInfo *pSelectInfo, CWnd* pParent = NULL);      // standard constructor

// Dialog Data
      //{{AFX_DATA(CDdDemoDlg)
      enum { IDD = IDD_DDDEMO_DIALOG };
            // NOTE: the ClassWizard will add data members here
      //}}AFX_DATA

      // ClassWizard generated virtual function overrides
      //{{AFX_VIRTUAL(CDdDemoDlg)
      public:
      virtual BOOL DestroyWindow();
      protected:
      virtual void DoDataExchange(CDataExchange* pDX);      // DDX/DDV support
      //}}AFX_VIRTUAL

// Implementation

      CListSelectData* m_pData;
      CSelectInfo* m_pSelectInfo;    

      CDDListCtrl m_listVars;

      CDDListCtrl m_listRows;
      CDDListCtrl m_listCols;
      CDDListCtrl m_listData;
      CDDListCtrl m_listPages;

protected:
      HICON m_hIcon;

      // Generated message map functions
      //{{AFX_MSG(CDdDemoDlg)
      virtual BOOL OnInitDialog();
      afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
      afx_msg void OnPaint();
      afx_msg HCURSOR OnQueryDragIcon();
      //}}AFX_MSG
      DECLARE_MESSAGE_MAP()
};

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_DDDEMODLG_H__F68B2E1C_A10D_11D4_8C0D_0050043EB83D__INCLUDED_)




// ddDemoDlg.cpp : implementation file
//

#include "stdafx.h"
#include "ddDemo.h"
#include "DDListCtrl.h"
#include "ddDemoDlg.h"
#include "SelectInfo.h"
#include "ListSelectData.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
      CAboutDlg();

// Dialog Data
      //{{AFX_DATA(CAboutDlg)
      enum { IDD = IDD_ABOUTBOX };
      //}}AFX_DATA

      // ClassWizard generated virtual function overrides
      //{{AFX_VIRTUAL(CAboutDlg)
      protected:
      virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
      //}}AFX_VIRTUAL

// Implementation
protected:
      //{{AFX_MSG(CAboutDlg)
      //}}AFX_MSG
      DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
      //{{AFX_DATA_INIT(CAboutDlg)
      //}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
      CDialog::DoDataExchange(pDX);
      //{{AFX_DATA_MAP(CAboutDlg)
      //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
      //{{AFX_MSG_MAP(CAboutDlg)
            // No message handlers
      //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDdDemoDlg dialog

CDdDemoDlg::CDdDemoDlg(CSelectInfo *pSelectInfo, CWnd* pParent /*=NULL*/)
      : CDialog(CDdDemoDlg::IDD, pParent)
{
      //{{AFX_DATA_INIT(CDdDemoDlg)
            // NOTE: the ClassWizard will add member initialization here
      //}}AFX_DATA_INIT
      // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
      m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

      ASSERT_POINTER(pSelectInfo, CSelectInfo);
    m_pSelectInfo     = pSelectInfo;

      m_pData     = new CListSelectData(&m_pSelectInfo->m_asNames);



   
      //{{AFX_DATA_INIT(CPivotTableDlg)
            // NOTE: the ClassWizard will add member initialization here
      //}}AFX_DATA_INIT
}


void CDdDemoDlg::DoDataExchange(CDataExchange* pDX)
{
      CDialog::DoDataExchange(pDX);
      //{{AFX_DATA_MAP(CDdDemoDlg)
            // NOTE: the ClassWizard will add DDX and DDV calls here
      //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CDdDemoDlg, CDialog)
      //{{AFX_MSG_MAP(CDdDemoDlg)
      ON_WM_SYSCOMMAND()
      ON_WM_PAINT()
      ON_WM_QUERYDRAGICON()
      //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDdDemoDlg message handlers

BOOL CDdDemoDlg::OnInitDialog()
{
      CDialog::OnInitDialog();

      // Add "About..." menu item to system menu.

      // IDM_ABOUTBOX must be in the system command range.
      ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
      ASSERT(IDM_ABOUTBOX < 0xF000);

      CMenu* pSysMenu = GetSystemMenu(FALSE);
      if (pSysMenu != NULL)
      {
            CString strAboutMenu;
            strAboutMenu.LoadString(IDS_ABOUTBOX);
            if (!strAboutMenu.IsEmpty())
            {
                  pSysMenu->AppendMenu(MF_SEPARATOR);
                  pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
            }
      }

      // Set the icon for this dialog.  The framework does this automatically
      //  when the application's main window is not a dialog
      SetIcon(m_hIcon, TRUE);                  // Set big icon
      SetIcon(m_hIcon, FALSE);            // Set small icon
      

      //----------------------------
      // Subclass the list controls
      //----------------------------
      m_listVars.SubclassDlgItem(IDC_LIST_VAR, this);
      m_listRows.SubclassDlgItem(IDC_LIST_ROWS, this);
      m_listCols.SubclassDlgItem(IDC_LIST_COLS, this);
      m_listData.SubclassDlgItem(IDC_LIST_DATA, this);
      m_listPages.SubclassDlgItem(IDC_LIST_PAGES, this);

    //----------------------------------------------------------
      // Create one column for the "List of var" List view control
      //----------------------------------------------------------
      CString s(TCHAR('M'),29);
      int len = m_listVars.GetStringWidth(s)+15;
      LV_COLUMN lvC;
      lvC.mask = LVCF_FMT | LVCF_WIDTH;
      lvC.fmt  = LVCFMT_LEFT;  // Left-align column
      lvC.cx   = len;          // Width of column in pixels
      if (m_listVars.InsertColumn(0,&lvC) == -1)
            return FALSE;
      m_listVars.DeleteAllItems();

      m_listVars.SetLocalDD(FALSE);   // Disable local Drag&Drop
      m_listVars.SetScrolling(FALSE); // and auto scrolling


      // Create a column for the row variables list view control.
    if (m_listRows.InsertColumn(0,&lvC) == -1)
            return FALSE;
      m_listRows.DeleteAllItems();

      // Create a column for the column variables list view control.
    if (m_listCols.InsertColumn(0,&lvC) == -1)
            return FALSE;
      m_listCols.DeleteAllItems();

      // Create a column for the data variables list view control.
    if (m_listData.InsertColumn(0,&lvC) == -1)
            return FALSE;
      m_listData.DeleteAllItems();

      // Create a column for the page variables view control.
    if (m_listPages.InsertColumn(0,&lvC) == -1)
            return FALSE;
      m_listPages.DeleteAllItems();

      //------------------------------------------
      // Set the content of the list view controls
      //------------------------------------------
      CWordArray aVars;
      int size = m_pSelectInfo->m_asNames.GetSize();
      aVars.SetSize(size);
      // Initially the list of available variables contains all variables
      for (int i=0; i<size; i++)
            aVars[i] = i;
   
      // Fill the list of variables
      m_pData->FillListCtrl(m_listVars, aVars);
      m_pData->FillListCtrl(m_listRows, m_pSelectInfo->m_aRowsVar);
      m_pData->FillListCtrl(m_listCols, m_pSelectInfo->m_aColsVar);  
      m_pData->FillListCtrl(m_listData, m_pSelectInfo->m_aDataVar);
      m_pData->FillListCtrl(m_listPages, m_pSelectInfo->m_aPagesVar);


      // Initialize the list controls for Drag&Drop
      m_listVars.Initialize();
      m_listRows.Initialize();
      m_listCols.Initialize();
      m_listData.Initialize();
      m_listPages.Initialize();

      
      return TRUE;  // return TRUE unless you set the focus to a control
                    // EXCEPTION: OCX Property Pages should return FALSE
}

void CDdDemoDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
      if ((nID & 0xFFF0) == IDM_ABOUTBOX)
      {
            CAboutDlg dlgAbout;
            dlgAbout.DoModal();
      }
      else
      {
            CDialog::OnSysCommand(nID, lParam);
      }
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CDdDemoDlg::OnPaint()
{
      if (IsIconic())
      {
            CPaintDC dc(this); // device context for painting

            SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

            // Center icon in client rectangle
            int cxIcon = GetSystemMetrics(SM_CXICON);
            int cyIcon = GetSystemMetrics(SM_CYICON);
            CRect rect;
            GetClientRect(&rect);
            int x = (rect.Width() - cxIcon + 1) / 2;
            int y = (rect.Height() - cyIcon + 1) / 2;

            // Draw the icon
            dc.DrawIcon(x, y, m_hIcon);
      }
      else
      {
            CDialog::OnPaint();
      }
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CDdDemoDlg::OnQueryDragIcon()
{
      return (HCURSOR) m_hIcon;
}


BOOL CDdDemoDlg::DestroyWindow()
{
      // TODO: Add your specialized code here and/or call the base class
      delete m_pData;
      
      return CDialog::DestroyWindow();
}


it is dialog-based application.

enjoy the ride