解决 wpf 管理员权限无法拖放文件的问题

如果你的wpf程序是以管理员权限运行,那么,是无法接收文件资源管理器拖拽文件的事件的,用下面这个Helper类可以解决这个问题

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Interop;

namespace WpfApp1
{
    public class WpfDragHelper
    {


        public event EventHandler DragDrop;
        public string[] DropFilePaths { get; private set; }
        public POINT DropPoint { get; private set; }
        public HwndSource HwndSource { get; set; }

        public void AddHook()
        {
            this.RemoveHook();
            this.HwndSource.AddHook(WndProc);
            IntPtr handle = this.HwndSource.Handle;
            if (IsUserAnAdmin()) RevokeDragDrop(handle);
            DragAcceptFiles(handle, true);
            ChangeMessageFilter(handle);
        }

        public void RemoveHook()
        {
            this.HwndSource.RemoveHook(WndProc);
            DragAcceptFiles(this.HwndSource.Handle, false);
        }

        private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            if (TryGetDropInfo(msg, wParam, out string[] filePaths, out POINT point))
            {
                DropPoint = point; //这个point需要除以windows的dpi,才能得出在wpf窗口中的真正坐标
                DropFilePaths = filePaths;
                DragDrop?.Invoke(this, null);
                handled = true;
            }
            return IntPtr.Zero;
        }

        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool ChangeWindowMessageFilterEx(IntPtr hWnd, uint msg, uint action, ref CHANGEFILTERSTRUCT pChangeFilterStruct);

        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool ChangeWindowMessageFilter(uint msg, uint flags);

        [DllImport("shell32.dll")]
        private static extern void DragAcceptFiles(IntPtr hWnd, bool fAccept);

        [DllImport("shell32.dll", CharSet = CharSet.Unicode)]
        private static extern uint DragQueryFile(IntPtr hWnd, uint iFile, StringBuilder lpszFile, int cch);

        [DllImport("shell32.dll")]
        private static extern bool DragQueryPoint(IntPtr hDrop, out POINT lppt);

        [DllImport("shell32.dll")]
        private static extern void DragFinish(IntPtr hDrop);

        [DllImport("ole32.dll")]
        private static extern int RevokeDragDrop(IntPtr hWnd);

        [DllImport("shell32.dll")]
        private static extern bool IsUserAnAdmin();

        [StructLayout(LayoutKind.Sequential)]
        public struct POINT
        {
            public int X;
            public int Y;
        }

        [StructLayout(LayoutKind.Sequential)]
        struct CHANGEFILTERSTRUCT
        {
            public uint cbSize;
            public uint ExtStatus;
        }

        const uint WM_COPYGLOBALDATA = 0x0049;
        const uint WM_COPYDATA = 0x004A;
        const uint WM_DROPFILES = 0x0233;
        const uint MSGFLT_ALLOW = 1;
        const uint MSGFLT_ADD = 1;
        const int MAX_PATH = 260;

        private static void ChangeMessageFilter(IntPtr handle)
        {
            Version ver = Environment.OSVersion.Version;
            bool isVistaOrHigher = ver >= new Version(6, 0);
            bool isWin7OrHigher = ver >= new Version(6, 1);
            if (isVistaOrHigher)
            {
                var status = new CHANGEFILTERSTRUCT { cbSize = 8 };
                foreach (uint msg in new[] { WM_DROPFILES, WM_COPYGLOBALDATA, WM_COPYDATA })
                {
                    bool error = false;
                    if (isWin7OrHigher) error = !ChangeWindowMessageFilterEx(handle, msg, MSGFLT_ALLOW, ref status);
                    else error = !ChangeWindowMessageFilter(msg, MSGFLT_ADD);
                    if (error) throw new Win32Exception(Marshal.GetLastWin32Error());
                }
            }
        }

        private static bool TryGetDropInfo(int msg, IntPtr wParam, out string[] dropFilePaths, out POINT dropPoint)
        {
            dropFilePaths = null;
            dropPoint = new POINT();
            if (msg != WM_DROPFILES) return false;
            uint fileCount = DragQueryFile(wParam, uint.MaxValue, null, 0);
            dropFilePaths = new string[fileCount];
            for (uint i = 0; i < fileCount; i++)
            {
                var sb = new StringBuilder(MAX_PATH);
                uint result = DragQueryFile(wParam, i, sb, sb.Capacity);
                if (result > 0) dropFilePaths[i] = sb.ToString();
            }
            DragQueryPoint(wParam, out dropPoint);
            DragFinish(wParam);
            return true;
        }
    }
}

使用方法:

WpfDragHelper _wpfDragHelper ;
        public MainWindow()
        {
            this.InitializeComponent();
            var _wpfDragHelper = new WpfDragHelper();
            this.SourceInitialized += (sender, e) =>
            {
                var helper = new WindowInteropHelper(this);
                _wpfDragHelper.HwndSource = HwndSource.FromHwnd(helper.Handle);
                _wpfDragHelper.AddHook();
            };
            this.Closing += (sender, e) =>
            {
                _wpfDragHelper.RemoveHook();
            };
            _wpfDragHelper.DragDrop += (sender, e) =>
            {
                MessageBox.Show(_wpfDragHelper.DropFilePaths[0]);
            };
        }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值