
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 ():
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;
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)
{
}
else
{
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