Search code examples
c++buildervcl

How RichEdit can accept file drag & dropping in BCB or Delphi program?


I'm writing a program that could drag and drop text files onto the form to show and edit it by RichEdit.

I've used ChangeWindowMessageFilterEx to make sure that WM_DROPFILES and WM_COPYDATA can received by my Main Form:

  ChangeWindowMessageFilterEx(Handle, WM_DROPFILES, MSGFLT_ADD, NULL);
  ChangeWindowMessageFilterEx(Handle, WM_COPYDATA, MSGFLT_ADD, NULL);
  ChangeWindowMessageFilter(73 , MSGFLT_ADD);

and call DragAcceptFiles(Handle, true) in the form creation function.

Now the drag operation is valid on any places of the window but except the RichEdit, the cursor shows a deny icon when dragging on the RichEdit.

Dragging on any components, eg. text editors, panels, combo boxes and buttons, on the form can lead to receive the WM_DROPFILES message, but except RichEdit.

Actually, I'm sure that it is possible to drag files on the RichEdit because I have wrote the code last year, but I have lost the source code and forgot it. I'm trying to rebuild the same one now.

Here is the google drive download link to the executable file that I have finished last year. And here is the github url to the uncompleted source code that I'm writing currently.

Thank you for your watching.


Solution

  • I don't know why TRichEdit does not receive WM_DROPFILES when using a message map, but you could handle the WindowProc of the TRichEdit.

    A possilble implementation could look like this:

    • Drop a TRichEdit on your Form
    • Modify header file

      private:    
      TWndMethod OldWindowProc;
      void __fastcall NewWindowProc(TMessage& Msg);
      
    • Add implementation

      __fastcall TForm1::TForm1(TComponent* Owner)
      : TForm(Owner)
      {
          OldWindowProc = RichEdit1->WindowProc;
          RichEdit1->WindowProc = NewWindowProc;
          DragAcceptFiles(RichEdit1->Handle, true);
      }    
      
      void __fastcall TForm1::NewWindowProc(TMessage& Msg)
      {
          switch (Msg.Msg) {
              case WM_DROPFILES:
              {
                  HDROP DropH = (HDROP)Msg.WParam;
                  int droppedFileCount = DragQueryFile(DropH, 0xFFFFFFFF, NULL, 0);
                  TStringList* Buffer = new TStringList();
                  for (int i = 0; i < droppedFileCount; i++) {
                      int fileNameLength = DragQueryFile(DropH, i, NULL, 0);
                      String FileName;
                      FileName.SetLength(fileNameLength);
                      DragQueryFile(DropH, i, FileName.w_str(), fileNameLength + 1);
                      Buffer->LoadFromFile(FileName);
                      RichEdit1->Lines->AddStrings(Buffer);
                      RichEdit1->Lines->Add("");
                  }
                  delete Buffer;
                  DragFinish(DropH);
                  Msg.Result = 0;
                  break;
              }
              case CM_RECREATEWND:
                  DragAcceptFiles(RichEdit1->Handle, true);
                  break;
          default:;
          }
          OldWindowProc(Msg);
      }