[UE 4.24] Drag and Drop Windows Files to UE4 Project Under Runtime and Get Dropped File Paths.

Hello,

I have question if it’s possible to drag and drop file/files to shipped UE4 project and gives the engine an array of path strings of files which were dropped. (C:\MyFile.txt,C:\MySecondFile.png…)

I have found exactly what I was looking for here: Google Translate (Google translated)

Unfortunately it’s not working for me at some point. Or if you know a better solution how to do it, I would be really grateful!

Here is the code:
WindowsDragFileBorder.h



#include "CoreMinimal.h"
#include "Components/ContentWidget.h"
#include "Widgets/SBoxPanel.h"
#include "Widgets/Layout/SBorder.h"
#include "WindowsDragFileBorder.generated.h"

/**
 *
 */
 //接收SDragBorder拖拽信号
DECLARE_DELEGATE(FOnDragEnterHandle);
DECLARE_DELEGATE(FOnDragLeaveHandle);
DECLARE_DELEGATE(FOnDragOverHandle);
DECLARE_DELEGATE_OneParam(FOnDropHandle, const TArray<FString>&);

//传给UMG
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnDragEnterEvent);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnDragLeaveEvent);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnDragOverEvent);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnDropEvent, const TArray<FString>&, FilesPath);
class AGAMID_API SDragBorder : public SBorder
{
public:

    SLATE_BEGIN_ARGS(SDragBorder)
    {}
    SLATE_EVENT(FOnDragEnterHandle, OnDragEnter)
        SLATE_EVENT(FOnDragLeaveHandle, OnDragLeave)
        SLATE_EVENT(FOnDragOverHandle, OnDragOver)
        SLATE_EVENT(FOnDropHandle, OnDrop)
        SLATE_END_ARGS()


public:
    // SWidget interface
    // End of SWidget interface
    void Construct(const FArguments& InArgs);

    virtual void SetContent(TSharedRef< SWidget > InContent) override;
public:
    // SWidget interface
    virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override;
    // End of SWidget interface
protected:
    // Begin SWidget overrides.
    virtual FVector2D ComputeDesiredSize(float) const override;
    // End SWidget overrides.
private:
    bool isFileDrag(const FDragDropEvent& DragDropEvent);

public:
    /** Drag detection and handling */
    //virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;

    virtual FReply OnDragDetected(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
    virtual void OnDragEnter(FGeometry const& MyGeometry, FDragDropEvent const& DragDropEvent) override;
    virtual void OnDragLeave(FDragDropEvent const& DragDropEvent) override;
    virtual FReply OnDragOver(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) override;
    virtual FReply OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) override;

private:
    /** Delegate triggered when a user's drag enters the bounds of this slot item */
    FOnDragEnterHandle OnDragEnter_Handler;

    /** Delegate triggered when a user's drag leaves the bounds of this slot item */
    FOnDragLeaveHandle OnDragLeave_Handler;

    /** Delegate triggered when a user's drag is dropped in the bounds of this slot item */
    FOnDropHandle OnDrop_Handler;

    FOnDragOverHandle OnDragOver_Handler;

};
UCLASS()
class AGAMID_API UWindowsDragFileBorder : public UContentWidget
{
    GENERATED_BODY()
public:

    void OnDragEnter();
    void OnDragLeave();
    void OnDragOver();
    void OnDragDrop(const TArray<FString>& FilesPath);
    //FReply OnDragOver(FDragDropEvent const& DragDropEvent);
    /** Called when the button is released */
    UPROPERTY(BlueprintAssignable, Category = "WindowsDragFile|Event")
        FOnDragEnterEvent OnDragEnterEvent;
    UPROPERTY(BlueprintAssignable, Category = "WindowsDragFile|Event")
        FOnDragLeaveEvent OnDragLeaveEvent;
    UPROPERTY(BlueprintAssignable, Category = "WindowsDragFile|Event")
        FOnDragOverEvent OnDragOverEvent;
    UPROPERTY(BlueprintAssignable, Category = "WindowsDragFile|Event")
        FOnDropEvent OnDragDropEvent;
protected:
    virtual TSharedRef<SWidget> RebuildWidget() override;

protected:
    TSharedPtr<SDragBorder> MyBorder;
};

WindowsDragFileBorder.cpp



#include "WindowsDragFileBorder.h"

#include "Widgets/SWidget.h"
#include "Widgets/Layout/SBorder.h"
#include "Components/BorderSlot.h"

void SDragBorder::Construct(const FArguments& InArgs)
{
    SBorder::SBorder();
    SBorder::Construct(SBorder::FArguments());
    OnDragEnter_Handler = InArgs._OnDragEnter;
    OnDragLeave_Handler = InArgs._OnDragLeave;
    OnDrop_Handler = InArgs._OnDrop;
    OnDragOver_Handler = InArgs._OnDragOver;
}
void UWindowsDragFileBorder::OnDragEnter()
{
    if (OnDragEnterEvent.IsBound())
    {
        OnDragEnterEvent.Broadcast();
    }
}
void UWindowsDragFileBorder::OnDragLeave()
{
    if (OnDragLeaveEvent.IsBound())
    {
        OnDragLeaveEvent.Broadcast();
    }
}
void UWindowsDragFileBorder::OnDragOver()
{
    if (OnDragOverEvent.IsBound())
    {
        OnDragOverEvent.Broadcast();
    }
}
void UWindowsDragFileBorder::OnDragDrop(const TArray<FString>& FilesPath)
{
    if (OnDragDropEvent.IsBound())
    {
        OnDragDropEvent.Broadcast(FilesPath);
    }

}

TSharedRef<SWidget> UWindowsDragFileBorder::RebuildWidget()
{
    MyBorder = SNew(SDragBorder)
        .OnDragEnter_UObject(this, &UWindowsDragFileBorder::OnDragEnter)
        .OnDragLeave_UObject(this, &UWindowsDragFileBorder::OnDragLeave)
        .OnDragOver_UObject(this, &UWindowsDragFileBorder::OnDragOver)
        .OnDrop_UObject(this, &UWindowsDragFileBorder::OnDragDrop)
        ;
    if (GetChildrenCount() > 0)
    {
        //Cast<UBorderSlot>(GetContentSlot())->BuildSlot(MyBorder.ToSharedRef());

        MyBorder->SetContent(GetContent() ? GetContent()->TakeWidget() : SNullWidget::NullWidget);
    }

    //    ;
    //    ;
    //MyBorder = SNew(SDragBorder);
    return MyBorder.ToSharedRef();
}
void SDragBorder::OnDragEnter(FGeometry const& MyGeometry, FDragDropEvent const& DragDropEvent)
{
    if (isFileDrag(DragDropEvent) && OnDragEnter_Handler.IsBound())
    {
        OnDragEnter_Handler.Execute();
    }
}

void SDragBorder::OnDragLeave(FDragDropEvent const& DragDropEvent)
{
    if (OnDragLeave_Handler.IsBound())
    {
        OnDragLeave_Handler.Execute();
    }
}

FReply SDragBorder::OnDragOver(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent)
{
    bool bisFileDrag = isFileDrag(DragDropEvent);
    if (bisFileDrag)
    {
        if (OnDragOver_Handler.IsBound())
        {
            OnDragOver_Handler.Execute();
        }
        return FReply::Handled();
    }

    return FReply::Handled();
}

FReply SDragBorder::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent)
{
    FExternalDragOperation* DragDropOperation = (FExternalDragOperation*)(DragDropEvent.GetOperation().Get());
    if (DragDropOperation)
    {
        OnDrop_Handler.Execute(DragDropOperation->GetFiles());
    }
    return FReply::Handled();
}

void SDragBorder::SetContent(TSharedRef<SWidget> InContent)
{
    SBorder::SetContent(InContent);
}

int32 SDragBorder::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const
{
    return SBorder::OnPaint(Args, AllottedGeometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled);
}

FVector2D SDragBorder::ComputeDesiredSize(float LayoutScaleMultiplier) const
{
    return DesiredSizeScale.Get() * SCompoundWidget::ComputeDesiredSize(LayoutScaleMultiplier);
}

bool SDragBorder::isFileDrag(const FDragDropEvent& DragDropEvent)
{
    FExternalDragOperation* DragDropOperation = (FExternalDragOperation*)(DragDropEvent.GetOperation().Get());
    if (!DragDropOperation)
    {
        return false;
    }
    if (!DragDropOperation->HasFiles())
    {
        return false;
    }
    return true;
}

FReply SDragBorder::OnDragDetected(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
    return FReply::Handled();
}

I am also work on that. I think window OS handle (hwnd) needs this variable when it created

WS_EX_ACCEPTFILES,

So, you need to create a native OS window with that parameter and after that you need callback functions to drop events.

I managed created a plugin for that. In a couple day I will push it