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