locked
How to drag and drop files from explorer to elevated with administrator right application in Windows 10? RRS feed

  • Question

  • I found the source codes for my problem on

    https://www.mpgh.net/forum/33-visual-basic-programming/571955-run-administrator-prevents-drag-drop-working.html?__cf_chl_jschl_tk__=d41deeef6564ecf2dd61e02aba2a12aeaa050251-1606269527-0-ATtS2tYj17giFybMyqeCSCoK9kDwm-a7Cafvlenm5KPjyNeWkb048fFdCiW2be-hRV_vp2pbOiz7-mo-uStzBBulFlHsiXO6GA35bj_tR7QcrF89YvsY8UmTW6iuaus1VDihZHGR3N2fobTIx4miE9N1GccXoQjxei-Bp5cxCbqed9OIeSrF9pd061roY-J5XLQpQH2haKRo192H51_XG6GRDXlHH8t3hkKv7NP8G08b61v0W6m3tP47MHcF7_PCKWpQTphwkLanN0W0dZ2R6XBoQZ6T6vuohCyb8b80Eg

    But it will not work on Windows 10, how to drag and drop in Windows 10? thank you.

    The code is below

    Imports System.Text Imports System.Runtime.InteropServices Namespace Utilities Public Class ElevatedDragDropManager Implements IMessageFilter #Region "P/Invoke" <DllImport("user32.dll")> _ Private Shared Function ChangeWindowMessageFilterEx(hWnd As IntPtr, msg As UInteger, action As ChangeWindowMessageFilterExAction, ByRef changeInfo As CHANGEFILTERSTRUCT) As <MarshalAs(UnmanagedType.Bool)> Boolean End Function <DllImport("user32.dll")> _ Private Shared Function ChangeWindowMessageFilter(msg As UInteger, flags As ChangeWindowMessageFilterFlags) As <MarshalAs(UnmanagedType.Bool)> Boolean End Function <DllImport("shell32.dll")> _ Private Shared Sub DragAcceptFiles(hwnd As IntPtr, fAccept As Boolean) End Sub <DllImport("shell32.dll")> _ Private Shared Function DragQueryFile(hDrop As IntPtr, iFile As UInteger, <Out()> lpszFile As StringBuilder, cch As UInteger) As UInteger End Function <DllImport("shell32.dll")> _ Private Shared Function DragQueryPoint(hDrop As IntPtr, ByRef lppt As POINT) As Boolean End Function <DllImport("shell32.dll")> _ Private Shared Sub DragFinish(hDrop As IntPtr) End Sub <StructLayout(LayoutKind.Sequential)> _ Private Structure POINT Public X As Integer Public Y As Integer Public Sub New(newX As Integer, newY As Integer) X = newX Y = newY End Sub Public Shared Widening Operator CType(p As POINT) As Drawing.Point Return New Drawing.Point(p.X, p.Y) End Operator Public Shared Widening Operator CType(p As Drawing.Point) As POINT Return New POINT(p.X, p.Y) End Operator End Structure Private Enum MessageFilterInfo As UInteger None AlreadyAllowed AlreadyDisAllowed AllowedHigher End Enum Private Enum ChangeWindowMessageFilterExAction As UInteger Reset Allow Disallow End Enum Private Enum ChangeWindowMessageFilterFlags As UInteger Add = 1 Remove = 2 End Enum <StructLayout(LayoutKind.Sequential)> _ Private Structure CHANGEFILTERSTRUCT Public cbSize As UInteger Public ExtStatus As MessageFilterInfo End Structure #End Region Public Shared Instance As New ElevatedDragDropManager() Public Event ElevatedDragDrop As EventHandler(Of ElevatedDragDropArgs) Private Const WM_DROPFILES As UInteger = &H233 Private Const WM_COPYDATA As UInteger = &H4A Private Const WM_COPYGLOBALDATA As UInteger = &H49 Private ReadOnly IsVistaOrHigher As Boolean = Environment.OSVersion.Version.Major >= 6 Private ReadOnly Is7OrHigher As Boolean = (Environment.OSVersion.Version.Major = 6 AndAlso Environment.OSVersion.Version.Minor >= 1) OrElse Environment.OSVersion.Version.Major > 6 Protected Sub New() Application.AddMessageFilter(Me) End Sub Public Sub EnableDragDrop(hWnd As IntPtr) If Is7OrHigher Then Dim changeStruct As New CHANGEFILTERSTRUCT() changeStruct.cbSize = CUInt(Marshal.SizeOf(GetType(CHANGEFILTERSTRUCT))) ChangeWindowMessageFilterEx(hWnd, WM_DROPFILES, ChangeWindowMessageFilterExAction.Allow, changeStruct) ChangeWindowMessageFilterEx(hWnd, WM_COPYDATA, ChangeWindowMessageFilterExAction.Allow, changeStruct) ChangeWindowMessageFilterEx(hWnd, WM_COPYGLOBALDATA, ChangeWindowMessageFilterExAction.Allow, changeStruct) ElseIf IsVistaOrHigher Then ChangeWindowMessageFilter(WM_DROPFILES, ChangeWindowMessageFilterFlags.Add) ChangeWindowMessageFilter(WM_COPYDATA, ChangeWindowMessageFilterFlags.Add) ChangeWindowMessageFilter(WM_COPYGLOBALDATA, ChangeWindowMessageFilterFlags.Add) End If DragAcceptFiles(hWnd, True) End Sub Public Function PreFilterMessage(ByRef m As Message) As Boolean Implements IMessageFilter.PreFilterMessage If m.Msg = WM_DROPFILES Then HandleDragDropMessage(m) Return True End If Return False End Function Private Sub HandleDragDropMessage(m As Message) Dim sb = New StringBuilder(260) Dim numFiles As UInteger = DragQueryFile(m.WParam, &HFFFFFFFFUI, sb, 0) Dim list = New List(Of String)() For i As UInteger = 0 To numFiles - 1 If DragQueryFile(m.WParam, i, sb, CUInt(sb.Capacity) * 2) > 0 Then list.Add(sb.ToString()) End If Next Dim p As POINT DragQueryPoint(m.WParam, p) DragFinish(m.WParam) Dim args = New ElevatedDragDropArgs() args.HWnd = m.HWnd args.Files = list args.X = p.X args.Y = p.Y RaiseEvent ElevatedDragDrop(Me, args) End Sub End Class Public Class ElevatedDragDropArgs Inherits EventArgs Public Property HWnd() As IntPtr Get Return m_HWnd End Get Set(value As IntPtr) m_HWnd = value End Set End Property Private m_HWnd As IntPtr Public Property Files() As List(Of String) Get Return m_Files End Get Set(value As List(Of String)) m_Files = value End Set End Property Private m_Files As List(Of String) Public Property X() As Integer Get Return m_X End Get Set(value As Integer) m_X = value End Set End Property Private m_X As Integer Public Property Y() As Integer Get Return m_Y End Get Set(value As Integer) m_Y = value End Set End Property Private m_Y As Integer Public Sub New() Files = New List(Of String)() End Sub End Class End Namespace

    Private Sub Form1_Load(sender As System.Object, e As EventArgs) Handles MyBase.Load
    	ElevatedDragDropManager.Instance.EnableDragDrop(DataGridView1.Handle) ' Enable elevated drag drop on DataGridView1. Note that I used the Handle property
    	AddHandler ElevatedDragDropManager.Instance.ElevatedDragDrop, AddressOf Form1_ElevatedDragDrop
    End Sub
    
    Private Sub Form1_ElevatedDragDrop(sender As System.Object, e As ElevatedDragDropArgs)
    	If e.HWnd = DataGridView1.Handle Then ' Check where the drag drop came from
    		For Each file In e.Files
    			MsgBox(file) ' Show all the files that were drag-dropped
    		Next
    	End If
    End Sub


    • Edited by gaxjyxq Wednesday, November 25, 2020 6:00 AM
    Wednesday, November 25, 2020 5:56 AM

Answers

  • It works on my OS (Windows 10, 1909)

    IObitUnlocker also calls ChangeWindowMessageFilter DragAcceptFiles

    • Marked as answer by gaxjyxq Thursday, November 26, 2020 1:41 PM
    Thursday, November 26, 2020 11:22 AM
  • Sorry, it also works well on my Windows 10 20H now.
    • Edited by gaxjyxq Thursday, November 26, 2020 1:24 PM
    • Marked as answer by gaxjyxq Thursday, November 26, 2020 1:41 PM
    Thursday, November 26, 2020 1:12 PM
  • Yes, it works well in Windows 7.
    • Marked as answer by gaxjyxq Thursday, November 26, 2020 1:41 PM
    Thursday, November 26, 2020 1:16 PM

All replies

  • If I remember correctly changing the message filter only worked around UIPI for old-style drag and drop with the WM_DROPFILES message.  However, it never worked around the restrictions for drag and drop between an un-elevated source and an elevated target using the COM interfaces like IDropSource, IDropTarget, etc.

    Perhaps in Windows 10 MS has closed the door on the undocumented workaround for WM_DROPFILES.

    Wednesday, November 25, 2020 10:23 AM
  • Did you test the code you found in a Win 8.1 or Win7 system?
    Thursday, November 26, 2020 10:49 AM
  • It works on my OS (Windows 10, 1909)

    IObitUnlocker also calls ChangeWindowMessageFilter DragAcceptFiles

    • Marked as answer by gaxjyxq Thursday, November 26, 2020 1:41 PM
    Thursday, November 26, 2020 11:22 AM
  • Sorry, it also works well on my Windows 10 20H now.
    • Edited by gaxjyxq Thursday, November 26, 2020 1:24 PM
    • Marked as answer by gaxjyxq Thursday, November 26, 2020 1:41 PM
    Thursday, November 26, 2020 1:12 PM
  • Yes, it works well in Windows 7.
    • Marked as answer by gaxjyxq Thursday, November 26, 2020 1:41 PM
    Thursday, November 26, 2020 1:16 PM