Click here to Skip to main content
15,878,970 members
Articles / Desktop Programming / MFC
Article

File Drag and Drop Encapsulated in a C++ Class

Rate me:
Please Sign up or sign in to vote.
4.22/5 (7 votes)
1 Jul 2002CPOL3 min read 68.8K   1.3K   24   1
Using an iterator to encapsulate DragFileQuery for file drag and drop.

Introduction

The file drag and drop functionality was added into Windows 3.x and has continued to be available in Windows 95/98 as well as Windows NT. File drag and drop, not to be confused with the more complex OLE drag and drop, allows the user of an application to select filenames listed in a Windows Explorer folder list, drag the filenames to an application window and drop them on the application's window. The user then expects those filenames to be available to the application.

This class provides a simpler interface to the file drag and drop functionality than using the DragQueryFile function directly. It encapsulates the handling of the drag and drop into a single class which is used as an iterator to walk through the list of files. The class will also handle the cleanup of the HDROP data structure by calling DragFinish(hDropInfo) when the object's destructor is triggered as the object goes out of scope.

This class also demonstrates the use of forcing the copy constructor and the assignment constructor to be protected in order to prevent the C++ compiler from automatically creating those methods when the class is used inappropriately. The class uses the HDROP handle to the list of dropped files and we only want a single instance of this handle being used. Otherwise, when the object goes out of scope, we could have multiple releases of the same HDROP structure with unknown consequences.

Usage

A typical use for this class is shown below in which a list control in a dialog is filled with file names which the user drags to the dialog from a Windows Explorer window. In order for this to work, you must modify the dialog properties under the Extended Styles tab, ensuring that the Accept files option is turned on. Another alternative is to add a call to the DragAcceptFiles function in the OnCreate handler of a window.

The class is a read only, sequential access iterator type of class with an internal position indicator. It appears to the client to be a tape of file names that can be read one after the other using the sNextFile method. The tape can be rewound to the beginning using the Reset method or the tape can be positioned to the first file using the sFirstFile method. The file name at which the tape is currently positioned can be read using the sCurrFile method. sCurrFile can be used multiple times to re-read the same position of the file name list.

  • sFirstFile (CString buf) - returns the first file in the list
  • sNextFile (CString buf) - returns the next file in the list
  • sCurrFile (CString buf) - returns the current file in the list
  • Reset () - reset the position indicator to before the first file

The file name is returned to the client using a provided CString object. A CString object was selected as the return type due to its versatility and its compatibility with LPCSTR. The client is required to provide the CString object so as to minimize memory management by the RDragDropFiles class, or between the class and the client, by making it clear who owns the buffer.

The RDragDropFiles class uses the operator () as the method to determine if the end of the file list is reached, when iterating over the file list using sNextFile. The client can also check the CString returned using the IsEmpty method of the CString class to see if a file name was found.

//  ....
// other stuff
//  ....

//  add the OnDropFiles command handler to the message map
BEGIN_MESSAGE_MAP(XListDialog, CDialog)
    //{{AFX_MSG_MAP(XListDialog)
    ON_WM_DROPFILES()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

//  ....
// other stuff
//  ....

// 
BOOL XListDialog::OnInitDialog() 
{
    CDialog::OnInitDialog();
    RECT irect;
    m_ListControl.GetWindowRect (&irect);

    m_ListControl.InsertColumn (0, "File Name", LVCFMT_LEFT,
                   irect.right - irect.left - 5);

    return TRUE;
}

void XListDialog::OnDropFiles(HDROP hDropInfo) 
{
    rjc::RDragDropFiles myFiles (hDropInfo);
    CString buf;

    int iStat = 0;
    int iL = 0;
    while (myFiles ()) {
        myFiles.sNextFile (buf);
        iL++;
        iStat = m_ListControl.InsertItem (iL, buf);
    }
}

Below is the source code for the sFirstFile method of the class. This code shows the use of the DragQueryFile function to first find out the length of the file name (actually a pathname), set the CString buffer to an appropriate length, and then fetch the file name using another call to DragQueryFile providing a pointer to the CString buffer.

As the class was developed and tested, I found that using a 1 index for the position indicator made the code easier when allowing the client to use the sFirstFile, sNextFile and the Reset methods in whatever order they wanted.

CString & RDragDropFiles::sFirstFile (CString & sBuff)
{
    ASSERT (hDropInfo);

    iPosition = 1;
    if (iPosition <= nFiles) {
        UINT nLen = DragQueryFile (hDropInfo, iPosition - 1, NULL, 0);
        char *pzsFN = sBuff.GetBufferSetLength (nLen+2);
        DragQueryFile (hDropInfo, iPosition - 1, pzsFN, nLen+2);
        sBuff.ReleaseBuffer ();
    }
    else {
        sBuff.Empty ();
    }
    return sBuff;
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Retired Georgia Southern University
United States United States
Team lead for a point of sale software application written in C and C++. Previous experience with Nortel Networks on software for telecommunications products as well as Program Management.

Education:
BS Computer Science
MBA
Masters in Project Management

Comments and Discussions

 
GeneralVery cool Pin
qbert6553611-Oct-03 17:24
qbert6553611-Oct-03 17:24 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.