VBA Drag & Drop filepath

jorispk

New Member
Joined
Dec 9, 2011
Messages
22
Hi guys,

Yesterday I got some stuff working with dropping content from listbox to listbox.

No I'm trying to get a path from an external file, but I'm still not able to figure out a way to get the filepath...

This is what I have:
Code:
Private Sub test_BeforeDragOver(ByVal Cancel As MSForms.ReturnBoolean, ByVal Data As MSForms.DataObject, ByVal X As Single, ByVal Y As Single, ByVal DragState As Long, _
    ByVal Effect As MSForms.ReturnEffect, ByVal Shift As Integer)
    Cancel = True
    Effect = 1
End Sub
Private Sub test_BeforeDropOrPaste(ByVal Cancel As MSForms.ReturnBoolean, ByVal Action As Long, ByVal Data As MSForms.DataObject, ByVal X As Single, _
    ByVal Y As Single, ByVal Effect As MSForms.ReturnEffect, ByVal Shift As Integer)
    Cancel = True
    Effect = 1
    Dim MyDataObject As DataObject
    Set MyDataObject = New DataObject
    'MyDataObject = GetObject(Data.Files(1))
    Me.test = MyDataObject
End Sub

I thought maybe something as Data.Files(1) would work but it doesn't. The Drag and drop feature works fine though if I say for example Me.test = "check" than it becomes that after dragging the file.

Any suggestions how to get the filepath??

Thank you
 
Hi Jaafar,

I've downloaded this link you provided https://app.box.com/s/vidd4zg01mneb57fa19e2x2wk327af3v for the 64 bit listbox version it worked once for me then haven't been able to get it to work again not sure what conditions were different.

It always loads the userform fine and when you drag a file over the listbox the cursor changes so it has detected the file but the listbox won't add the file path. I noticed when it did work I had to hold the file over the listbox for a second or 2 to ensure the listbox picked up the file - other than this cant explain any more.

I'm using windows 10 and excel 2016 64bit, is there any alternative versions you have to try?

I've searched google extensively and there's nothing that comes close to yours so would love to see this work.

Any help would be appreciated.
 
Upvote 0

Excel Facts

Lock one reference in a formula
Need 1 part of a formula to always point to the same range? use $ signs: $V$2:$Z$99 will always point to V2:Z99, even after copying
Hi Jaafar,

I've downloaded this link you provided https://app.box.com/s/vidd4zg01mneb57fa19e2x2wk327af3v for the 64 bit listbox version it worked once for me then haven't been able to get it to work again not sure what conditions were different.

Hi Handyman84

You are correct. I could replicate the problem you are experiencing in excel 2016 64bit Windows 10.

Short of subclassing the userform which is potentially dangerous and won't work with modeless userforms, I have opted for monitoring incoming sent messages in a loop upon userform activation via the use of the GetMessage API..

The following code seems to work well with Modal as well as Modeless userfoms.
Workbook example


Add a ListBox (ListBox1) to the UserForm, place the following code in the UserForm Module and start dragging files from explorer onto the ListBox:
Code:
Option Explicit

Private Type POINTAPI
  X As Long
  Y As Long
End Type

[URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=If]#If[/URL]  VBA7 Then
    Private Type MSG
        hwnd As LongPtr
        message As Long
        wParam As LongPtr
        lParam As LongPtr
        time As Long
        pt As POINTAPI
    End Type

    [URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=If]#If[/URL]  Win64 Then
        Private Declare PtrSafe Function WindowFromPoint Lib "user32" (ByVal Point As LongPtr) As LongPtr
    [URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=Else]#Else[/URL] 
        Private Declare PtrSafe Function WindowFromPoint Lib "user32" (ByVal xPoint As Long, ByVal yPoint As Long) As LongPtr
    [URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=End]#End[/URL]  If
    Private Declare PtrSafe Function GetMessage Lib "user32" Alias "GetMessageA" (lpMsg As MSG, ByVal hwnd As LongPtr, ByVal wMsgFilterMin As Long, ByVal wMsgFilterMax As Long) As Long
    Private Declare PtrSafe Function DispatchMessage Lib "user32" Alias "DispatchMessageA" (lpMsg As MSG) As LongPtr
    Private Declare PtrSafe Function TranslateMessage Lib "user32" (lpMsg As MSG) As Long
    Private Declare PtrSafe Function WindowFromAccessibleObject Lib "oleacc" (ByVal pacc As IAccessible, phwnd As LongPtr) As Long
    Private Declare PtrSafe Function IsWindow Lib "user32" (ByVal hwnd As LongPtr) As Long
    Private Declare PtrSafe Sub DragAcceptFiles Lib "shell32.dll" (ByVal hwnd As LongPtr, ByVal fAccept As Long)
    Private Declare PtrSafe Sub DragFinish Lib "shell32.dll" (ByVal HDROP As LongPtr)
    Private Declare PtrSafe Function DragQueryFile Lib "shell32.dll" Alias "DragQueryFileA" (ByVal HDROP As LongPtr, ByVal UINT As Long, ByVal lpStr As String, ByVal ch As Long) As Long
    Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
[URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=Else]#Else[/URL] 

    Private Type MSG
        hwnd As Long
        message As Long
        wParam As Long
        lParam As Long
        time As Long
        pt As POINTAPI
    End Type

    Private Declare Function WindowFromPoint Lib "user32" (ByVal xPoint As Long, ByVal yPoint As Long) As Long
    Private Declare Function GetMessage Lib "user32" Alias "GetMessageA" (lpMsg As MSG, ByVal hwnd As Long, ByVal wMsgFilterMin As Long, ByVal wMsgFilterMax As Long) As Long
    Private Declare Function DispatchMessage Lib "user32" Alias "DispatchMessageA" (lpMsg As MSG) As Long
    Private Declare Function TranslateMessage Lib "user32" (lpMsg As MSG) As Long
    Private Declare Function WindowFromAccessibleObject Lib "oleacc" (ByVal pacc As IAccessible, phwnd As Long) As Long
    Private Declare Function IsWindow Lib "user32" (ByVal hwnd As Long) As Long
    Private Declare Sub DragAcceptFiles Lib "shell32.dll" (ByVal hwnd As Long, ByVal fAccept As Long)
    Private Declare Sub DragFinish Lib "shell32.dll" (ByVal HDROP As Long)
    Private Declare Function DragQueryFile Lib "shell32.dll" Alias "DragQueryFileA" (ByVal HDROP As Long, ByVal UINT As Long, ByVal lpStr As String, ByVal ch As Long) As Long
    Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
[URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=End]#End[/URL]  If


Private Sub UserForm_Activate()

    [URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=If]#If[/URL]  VBA7 Then
        Dim hwnd As LongPtr, HDROP As LongPtr
    [URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=Else]#Else[/URL] 
        Dim hwnd As Long, HDROP As Long
    [URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=End]#End[/URL]  If

    Const WM_DROPFILES = &H233
    Dim tMsg As MSG, sFileName As String * 256
    
    Call WindowFromAccessibleObject(Me, hwnd)
    Call DragAcceptFiles(hwnd, True)
    
    Do While GetMessage(tMsg, 0, 0, 0) And IsWindow(hwnd)
        DoEvents
        If tMsg.message = WM_DROPFILES Then
            [URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=If]#If[/URL]  VBA7 And Win64 Then
                Dim lPt As LongPtr
                Call CopyMemory(lPt, tMsg.pt, LenB(tMsg.pt))
                hwnd = WindowFromPoint(lPt)
            [URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=Else]#Else[/URL] 
                hwnd = WindowFromPoint(tMsg.pt.X, tMsg.pt.Y)
            [URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=End]#End[/URL]  If
            If hwnd = Me.ListBox1.[_GethWnd] Then
                HDROP = tMsg.wParam
                ListBox1.AddItem Left(sFileName, DragQueryFile(HDROP, 0, sFileName, Len(sFileName)))
                Call DragFinish(HDROP)
            End If
        End If
        Call TranslateMessage(tMsg)
        Call DispatchMessage(tMsg)
    Loop
    
End Sub
 
Upvote 0
The following should work for 32 and 64 bits :

Code in the userform module:
Code:
Option Explicit

Private Type POINTAPI
  X As Long
  Y As Long
End Type

[URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=If]#If[/URL]  VBA7 Then
    Private Type MSG
        hwnd As LongPtr
        message As Long
        wParam As LongPtr
        lParam As LongPtr
        time As Long
        pt As POINTAPI
    End Type
   
    Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
    Private Declare PtrSafe Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As LongPtr, ByVal hWnd2 As LongPtr, ByVal lpsz1 As String, ByVal lpsz2 As String) As LongPtr
    Private Declare PtrSafe Sub DragAcceptFiles Lib "shell32.dll" (ByVal hwnd As LongPtr, ByVal fAccept As Long)
    Private Declare PtrSafe Sub DragFinish Lib "shell32.dll" (ByVal HDROP As LongPtr)
    Private Declare PtrSafe Function DragQueryFile Lib "shell32.dll" Alias "DragQueryFileA" (ByVal HDROP As LongPtr, ByVal UINT As Long, ByVal lpStr As String, ByVal ch As Long) As Long
    Private Declare PtrSafe Function PeekMessage Lib "user32" Alias "PeekMessageA" (lpMsg As MSG, ByVal hwnd As LongPtr, ByVal wMsgFilterMin As Long, ByVal wMsgFilterMax As Long, ByVal wRemoveMsg As Long) As Long
    Private Declare PtrSafe Function WaitMessage Lib "user32" () As Long
    Private hwnd As LongPtr

[URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=Else]#Else[/URL]
    Private Type MSG
        hwnd As Long
        message As Long
        wParam As Long
        lParam As Long
        time As Long
        pt As POINTAPI
    End Type
   
    Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
    Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
    Private Declare Sub DragAcceptFiles Lib "shell32.dll" (ByVal hwnd As Long, ByVal fAccept As Long)
    Private Declare Sub DragFinish Lib "shell32.dll" (ByVal HDROP As Long)
    Private Declare Function DragQueryFile Lib "shell32.dll" Alias "DragQueryFileA" (ByVal HDROP As Long, ByVal UINT As Long, ByVal lpStr As String, ByVal ch As Long) As Long
    Private Declare Function PeekMessage Lib "user32" Alias "PeekMessageA" (lpMsg As MSG, ByVal hwnd As Long, ByVal wMsgFilterMin As Long, ByVal wMsgFilterMax As Long, ByVal wRemoveMsg As Long) As Long
    Private Declare Function WaitMessage Lib "user32" () As Long
    Private hwnd As Long
[URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=End]#End[/URL]  If

Private Const PM_NOYIELD = &H2
Private Const PM_REMOVE = &H1
Private Const WM_DROPFILES = &H233
Private bUnload As Boolean

Private Sub UserForm_Activate()
    Dim FileDropMessage As MSG
    Dim HDROP As LongPtr
    Dim FileName As String * 256
    Dim ret As Long
   
    'get the listbox handle
    hwnd = FindWindow(vbNullString, Me.Caption)
    hwnd = FindWindowEx(hwnd, 0, vbNullString, vbNullString)
    hwnd = FindWindowEx(hwnd, 0, vbNullString, vbNullString)
   
    'make the listbox accept dropped file
    DragAcceptFiles hwnd, True
   
    bUnload = False
    Do
        'wait for a file to be dropped
        WaitMessage
        Call PeekMessage(FileDropMessage, 0, 0, 0, 0)
        'if file dropped on the listbox then retrieve the name of the dropped file
        If PeekMessage(FileDropMessage, hwnd, WM_DROPFILES, WM_DROPFILES, PM_REMOVE Or PM_NOYIELD) Then
            HDROP = FileDropMessage.wParam
            ret = DragQueryFile(HDROP, 0, FileName, Len(FileName))
            ListBox1.AddItem Left(FileName, ret)
            'Release memory
            DragFinish HDROP
        End If
        DoEvents
    Loop Until bUnload
End Sub

Private Sub UserForm_Terminate()
    'exit msg loop
    bUnload = True
End Sub

Thanks for this code Jaafar, it works great, to be honest. I would just want it to be able to collect more than just one file. How would you do it?
Thanks in advance.
 
Upvote 0
Thanks for this code Jaafar, it works great, to be honest. I would just want it to be able to collect more than just one file. How would you do it?
Thanks in advance.

Hi airnan

Here is the code for dragging multiple files :
Add a ListBox (ListBox1) to the UserForm, place the following code in the UserForm Module and start dragging files from explorer onto the ListBox:


VBA Code:
Option Explicit

Private Type POINTAPI
  X As Long
  Y As Long
End Type

#If VBA7 Then
    Private Type MSG
        hwnd As LongPtr
        message As Long
        wParam As LongPtr
        lParam As LongPtr
        time As Long
        pt As POINTAPI
    End Type

    Private Declare PtrSafe Function GetMessage Lib "user32" Alias "GetMessageA" (lpMsg As MSG, ByVal hwnd As LongPtr, ByVal wMsgFilterMin As Long, ByVal wMsgFilterMax As Long) As Long
    Private Declare PtrSafe Function DispatchMessage Lib "user32" Alias "DispatchMessageA" (lpMsg As MSG) As LongPtr
    Private Declare PtrSafe Function TranslateMessage Lib "user32" (lpMsg As MSG) As Long
    Private Declare PtrSafe Function WindowFromAccessibleObject Lib "oleacc" (ByVal pacc As IAccessible, phwnd As LongPtr) As Long
    Private Declare PtrSafe Function IsWindow Lib "user32" (ByVal hwnd As LongPtr) As Long
    Private Declare PtrSafe Sub DragAcceptFiles Lib "shell32.dll" (ByVal hwnd As LongPtr, ByVal fAccept As Long)
    Private Declare PtrSafe Sub DragFinish Lib "shell32.dll" (ByVal HDROP As LongPtr)
    Private Declare PtrSafe Function DragQueryFile Lib "shell32.dll" Alias "DragQueryFileA" (ByVal HDROP As LongPtr, ByVal UINT As Long, ByVal lpStr As String, ByVal ch As Long) As Long
#Else

    Private Type MSG
        hwnd As Long
        message As Long
        wParam As Long
        lParam As Long
        time As Long
        pt As POINTAPI
    End Type

    Private Declare Function GetMessage Lib "user32" Alias "GetMessageA" (lpMsg As MSG, ByVal hwnd As Long, ByVal wMsgFilterMin As Long, ByVal wMsgFilterMax As Long) As Long
    Private Declare Function DispatchMessage Lib "user32" Alias "DispatchMessageA" (lpMsg As MSG) As Long
    Private Declare Function TranslateMessage Lib "user32" (lpMsg As MSG) As Long
    Private Declare Function WindowFromAccessibleObject Lib "oleacc" (ByVal pacc As IAccessible, phwnd As Long) As Long
    Private Declare Function IsWindow Lib "user32" (ByVal hwnd As Long) As Long
    Private Declare Sub DragAcceptFiles Lib "shell32.dll" (ByVal hwnd As Long, ByVal fAccept As Long)
    Private Declare Sub DragFinish Lib "shell32.dll" (ByVal HDROP As Long)
    Private Declare Function DragQueryFile Lib "shell32.dll" Alias "DragQueryFileA" (ByVal HDROP As Long, ByVal UINT As Long, ByVal lpStr As String, ByVal ch As Long) As Long
#End If



Private Sub UserForm_Activate()

   #If VBA7 Then
        Dim hwnd As LongPtr, HDROP As LongPtr
    #Else
        Dim hwnd As Long, HDROP As Long
    #End If

    Const WM_DROPFILES = &H233
    Dim tMsg As MSG, sFileName As String * 256
    Dim lFilesCount As Long, i As Long


    Call WindowFromAccessibleObject(Me, hwnd)
    Call DragAcceptFiles(ListBox1.[_GethWnd], True)

    Do While GetMessage(tMsg, 0, 0, 0) And IsWindow(hwnd)
        If tMsg.message = WM_DROPFILES Then
            HDROP = tMsg.wParam
            lFilesCount = DragQueryFile(HDROP, &HFFFFFFFF, 0, 0)
            If lFilesCount Then
                For i = 0 To lFilesCount - 1
                    ListBox1.AddItem Left(sFileName, DragQueryFile(HDROP, i, sFileName, Len(sFileName)))
                Next i
            End If
            Call DragFinish(HDROP)
        End If
        Call TranslateMessage(tMsg)
        Call DispatchMessage(tMsg)
    Loop

End Sub
 
Last edited:
Upvote 0
Sorry, but i'm a newbie in VBA. I've tried all version you shared, but no one has working. I've seen a video about drag & drop but i don't know how to create. Could you help me in this case? Thank you very much!

 
Upvote 0
Sorry, but i'm a newbie in VBA. I've tried all version you shared, but no one has working. I've seen a video about drag & drop but i don't know how to create. Could you help me in this case? Thank you very much!

Hi hodangbinh47

Did you put the code in the Userform module ?

Anyway, here is a workbook example you can download.


ExplorerDragNDrop.gif
 
Upvote 0
Can I ask if there is way to drag file (filepatch) to website from excel userform ?
 
Upvote 0

Forum statistics

Threads
1,224,872
Messages
6,181,499
Members
453,047
Latest member
charlie_odd

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top