Drag and Drop from Explorer to a TreeView

Many professional applications allow dragging and dropping of files from Windows Explorer to the application.  Indeed, one of the great advantages of Windows it that it adopts an easy and intuitive user-interface which allows the user to manipulate objects (specifically files) with little to no keyboard input required.  Implementing this functionality is relatively simple. 

Windows sends the WM_DROPFILES message to a control, when the user has dropped a file (or group of files) onto that control.  The control must then use the parameters of that message in conjunction with a few API calls to ascertain which files were dropped and how many were dropped.  In order to realize this functionality with a TreeView control, the first goal is to subclass it's window procedure. Then, within the window procedure, look for the WM_DROPFILES message, and process it accordingly.

KEYWORDS:  WM_DROPFILES, WindowProc, DragQueryPoint, DragQueryFile, DragFinish
 
 
 

//in header...

    Controls::TWndMethod OldTreeViewWP;
    void __fastcall NewTreeViewWP(TMessage &Msg);
 

 


 

//---------------------------------------------------------------------------
//in source...

__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
    //turn on file d&d for the TreeView
    DragAcceptFiles(TreeView1->Handle, true);

    //save the old window procedure
    OldTreeViewWP = TreeView1->WindowProc;

    //assign a new window procedure
    TreeView1->WindowProc = NewTreeViewWP;
}

//---------------------------------------------------------------------------

//new TreeView window procedure
void __fastcall TForm1::NewTreeViewWP(TMessage &Msg)
{
    if (Msg.Msg == WM_DROPFILES)
    {
       //find the point and node of the drop
       POINT P;
       DragQueryPoint((HDROP)Msg.WParam, &P);
       TTreeNode *DropNode = TreeView1->GetNodeAt(P.x, P.y);

       //find the number of files dropped
       int num_files = DragQueryFile((HDROP)Msg.WParam, 0xFFFFFFFF,
                                      (LPSTR)NULL, NULL);

       TreeView1->Items->BeginUpdate();
       for (int index = 0; index < num_files; index++)
       {
           //find the length of the filename
           int NameLength = DragQueryFile((HDROP)Msg.WParam, index,
                                           NULL, NULL);

           char *FileName = new char[NameLength];

           //get the filename
           DragQueryFile((HDROP)Msg.WParam, index, FileName, NameLength);

           //add it to the TreeView
           TreeView1->Items->Add(DropNode, FileName);

           delete [] FileName;
       }
       TreeView1->Items->EndUpdate();

       DragFinish((HDROP)Msg.WParam);
       Msg.Result = 0;
    }
    OldTreeViewWP(Msg);
}

//---------------------------------------------------------------------------

void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
    //restore the original window procedure
    TreeView1->WindowProc = OldTreeViewWP;

    //turn off file d&d for the TreeView
    DragAcceptFiles(TreeView1->Handle, false); 
}