Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Drag, drop, cut, copy and paste operations on lists of files using MFC

0.00/5 (No votes)
5 Apr 2003 1  
Article that explains drag, drop, cut, copy and paste operations on lists of files using MFC

Introduction

In the given article practically all operations on moving group of files from one application to another are described. I have considered both reception of files by the given application and transfer of files from the given application in other programs. In the article the operations drag and drop, cut, copy, paste are described. The technique is shown using the demonstration project.

Developing the program Mp3 Music Explorer I have confronted the fact that in the documentation from Microsoft, and also on the known sites devoted to development of the software there is no example, in which all necessary operations on moving files would be presented. Therefore I have created the demonstration project FilesDragDrop. It is based on the MFC SDI project. For the files display the class CListView is used.

Receiving the Drop of the list of files in the application is possible by two ways: using the message WM_DROPFILES and using the OLE mechanism. Both ways, as well as transfer of a file through Clip Board, use one structure of file description DROPFILES. For dragging of a file from the application only the mechanism Ole is used. Therefore all operations of moving files I implemented using the OLE technology.

Initialization

The realization of moving of files is possible without such concepts as OLE Server and OLE Client. They are excessive for this task. It is possible to use the usual MFC project. But for the necessary OLE classes to work we need to initialize OLE library. For this purpose the following lines are inserted into the function CFilesDragDropApp:: InitInstance ():

// Initialize OLE 2.0 libraries

if (!AfxOleInit())
{
    AfxMessageBox("AfxOleInit Error!");
    return FALSE;
}

Receiving the files in the application

For receiving files using Drag&Drop technology I used OnDragOver and OnDrop notifications. In the OnDragOver function I determine if the list of files or something else is carried above a window and I return assumed result of the operation. If it is not the files - the returned value is DROPEFFECT_NONE. It allows the system to establish the correct cursor of the mouse. In the OnDrop function the extraction of files and the clearing of the buffer are made. For these functions to work the window should be registered as handler of the operation Drag&Drop. For the registration the object such as COleDropTarget is used as follows:

void CFilesDragDropView::OnInitialUpdate()
{
...
VERIFY( m_DropTarget.Register(this) );
...
}

Clip Board and Drag&Drop use the same structure for data transfer. In processing the messages OnPaste and OnDrop there is an extraction of the list of files from the object COleDataObject:

void CFilesDragDropView::OnEditPaste() 
{
  COleDataObject DataObject;
  if( DataObject.AttachClipboard() )
  {
    DataObjectToList(&DataObject);
  } 
}

BOOL CFilesDragDropView::OnDrop(COleDataObject* pDataObject, 
        DROPEFFECT dropEffect, CPoint point) 
{
   BOOL bRet = DataObjectToList(pDataObject);
   ...
}

Data type, used for transferring the files is CF_HDROP. The data are passed through the global memory, its handle it is possible to take from COleDataObject using GetData function. The amount of transferred files and paths to them can be received with the help of handle using function DragQueryFile ( CFilesDragDropView:: FileNamesToList). The received files are displayed in a ListView window.

Transfer of files from the application

To transfer files from the application using Copy/Paste and Drag&Drop technologies it is necessary to create structure DROPFILES. This structure corresponds to a data type CF_HDROP of the exchange buffer. The paths to files in the structure are separated from each other by symbol '\0 ', the end of the list of files is marked by two symbols '\0 '. There is a standard function of path extraction from the buffer - DragQueryFile, but there is no standard function for creating a buffer. For this purpose I have designed a class CDropFiles. The class is used in the  following way:

  • First function AddFile enters all the paths of transferred files
  • Then the function CreateBuffer creates a necessary data structure. For access to the structure the functions GetBuffer and GetBuffSize are used. When using Copy or Cut command, the data generated in CDropFile:: m_pBuff are entered in the exchange buffer between the applications by function SetClipboardData.

In Drag&Drop technology for the transfer of files from the application the function OnBeginDrag is used. It is called by the message LVN_BEGINDRAG of CListCtrl class. If we use a window, which does not generate the similar message, it is possible to use the message WM_LBUTTONDOWN. The data for the transfer are entered in object COleDataSource by the function CacheGlobalData, the data transfer is carried out by DoDragDrop function. For the object COleDataSource to work it is necessary to create COleDropSource object. This object is not used in any way in transfer. All necessary actions it carries out in the constructor. Memory of the exchange buffer is emptied by the receiving party.

The text of function

void CFilesDragDropView::OnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult) 
{
  NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

  CDropFiles DropFiles; // My class for creating DROPFILES struct


  if(!PrepareFileBuff(DropFiles))
  {
    ASSERT(0);
  }
  COleDropSource DropSource;
  COleDataSource DropData;
  HGLOBAL hMem = ::GlobalAlloc(GMEM_ZEROINIT|GMEM_MOVEABLE|GMEM_DDESHARE, 
    DropFiles.GetBuffSize()); 
  memcpy( (char*)::GlobalLock(hMem), DropFiles.GetBuffer(), 
    DropFiles.GetBuffSize() );
  ::GlobalUnlock(hMem);
  DropData.CacheGlobalData( CF_HDROP, hMem );
  DROPEFFECT de = DropData.DoDragDrop(DROPEFFECT_COPY|DROPEFFECT_MOVE,NULL);
  if(de == DROPEFFECT_COPY)
  {
    // Copy files if CTRL btn is hold;

  }
  else
  {
    // Move files, as default;

    DeleteSelectedFiles();
  }

  *pResult = 0;
}

Testing of the demonstration project

If you transfer files from any catalogue to the FilesDragDrop application, and then from the application to another catalogue, the files will be really transferred. That's why when testing I recommend to use the special temporary catalogues to avoid the transfer of necessary files.

Links

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here