• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

解决C#拖放文件无效的问题

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

我们可以向ArcMap窗口中直接拖放mxd工程文件、shp矢量文件 、tif栅格文件等,十分方便;使用控件的DragEnter和DragDrop即可实现拖放操作,但在Win7和Win10系统中,如果程序以管理员运行,则实现的拖动操作无效。

Windows消息是一种进程间通信机制,为了防止较低等级的进程窗口向较等级进程窗口发送消息,Windows引用了用户界面特权隔离(简称UIPI)机制。正是由于这种机制,导致了如果以管理员运行应用程序,拖放操作就会被系统过滤而无效。

解决方案

采用 ChangeWindowMessageFilterEx 函数,为指定窗口修改用户界面特权隔离 (UIPI) 消息过滤器。

先使用Windows API实现如下类:

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

namespace Frame.Utility.Handler
{
    public sealed class FileDropHandler : IMessageFilter, IDisposable
    {

        #region API函数

        /// <summary>
        /// 指定窗口修改用户界面特权隔离 (UIPI) 消息过滤器
        /// </summary>
        /// <param name="hWnd">窗口句柄</param>
        /// <param name="message">允许或阻止的消息</param>
        /// <param name="action">要执行的操作</param>
        /// <param name="pChangeFilterStruct"></param>
        /// <returns></returns>
        [DllImport("user32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool ChangeWindowMessageFilterEx(IntPtr hWnd, uint message, ChangeFilterAction action, in ChangeFilterStruct pChangeFilterStruct);

        /// <summary>
        /// 窗口是否接受从shell拖放过来的文件
        /// </summary>
        /// <param name="hWnd">窗口句柄</param>
        /// <param name="fAccept">true接收拖拽,false拒绝拖拽</param>
        [DllImport("shell32.dll", SetLastError = false, CallingConvention = CallingConvention.Winapi)]
        private static extern void DragAcceptFiles(IntPtr hWnd, bool fAccept);

        /// <summary>
        /// 成功拖放操作后获取被拖放文件的名称等信息
        /// </summary>
        /// <param name="hWnd">句柄</param>
        /// <param name="iFile">文件索引编号</param>
        /// <param name="lpszFile">存放函数返回的文件路径</param>
        /// <param name="cch">缓冲区的字符数</param>
        /// <returns></returns>
        [DllImport("shell32.dll", SetLastError = false, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Winapi)]
        private static extern uint DragQueryFile(IntPtr hWnd, uint iFile, StringBuilder lpszFile, int cch);

        /// <summary>
        /// 释放shell为传递文件名而开辟的内存空间
        /// </summary>
        /// <param name="hDrop">窗口句柄</param>
        [DllImport("shell32.dll", SetLastError = false, CallingConvention = CallingConvention.Winapi)]
        private static extern void DragFinish(IntPtr hDrop);

        [StructLayout(LayoutKind.Sequential)]
        private struct ChangeFilterStruct
        {
            public uint CbSize;
            private readonly ChangeFilterStatu ExtStatus;
        }

        private enum ChangeFilterAction : uint
        {
            /// <summary>
            /// 允许消息通过过滤器(包括来自低特权的进程)
            /// </summary>
            MSGFLT_ALLOW,

            /// <summary>
            /// 如果消息来自低特权的进程,阻止它转递给窗口
            /// </summary>
            MSGFLT_DISALLOW,

            /// <summary>
            /// 为窗口重置消息过滤器为默认
            /// </summary>
            MSGFLT_RESET

        }

        private enum ChangeFilterStatu : uint
        {
            MSGFLTINFO_NONE,
            MSGFLTINFO_ALREADYALLOWED_FORWND,
            MSGFLTINFO_ALREADYDISALLOWED_FORWND,
            MSGFLTINFO_ALLOWED_HIGHER
        }

        private const uint WM_COPYGLOBALDATA = 0x0049;
        private const uint WM_COPYDATA = 0x004A;
        private const uint WM_DROPFILES = 0x0233;

        #endregion


        private const uint GetIndexCount = 0xFFFFFFFFU;

        private Control _containerControl;

        private readonly bool _disposeControl;

        public FileDropHandler(Control containerControl) : this(containerControl, false) { }

        public FileDropHandler(Control containerControl, bool releaseControl)
        {
            _containerControl = containerControl ?? throw new ArgumentNullException("control", "control is null.");

            if (containerControl.IsDisposed) throw new ObjectDisposedException("control");

            _disposeControl = releaseControl;

            var status = new ChangeFilterStruct() { CbSize = 8 };

            if (!ChangeWindowMessageFilterEx(containerControl.Handle, WM_DROPFILES, ChangeFilterAction.MSGFLT_ALLOW, in status)) throw new Win32Exception(Marshal.GetLastWin32Error());
            if (!ChangeWindowMessageFilterEx(containerControl.Handle, WM_COPYGLOBALDATA, ChangeFilterAction.MSGFLT_ALLOW, in status)) throw new Win32Exception(Marshal.GetLastWin32Error());
            if (!ChangeWindowMessageFilterEx(containerControl.Handle, WM_COPYDATA, ChangeFilterAction.MSGFLT_ALLOW, in status)) throw new Win32Exception(Marshal.GetLastWin32Error());
            DragAcceptFiles(containerControl.Handle, true);

            Application.AddMessageFilter(this);
        }

        public bool PreFilterMessage(ref Message m)
        {
            if (_containerControl == null || _containerControl.IsDisposed) return false;
            if (_containerControl.AllowDrop) return _containerControl.AllowDrop = false;
            if (m.Msg == WM_DROPFILES)
            {
                var handle = m.WParam;

                var fileCount = DragQueryFile(handle, GetIndexCount, null, 0);

                var fileNames = new string[fileCount];

                var sb = new StringBuilder(262);
                var charLength = sb.Capacity;
                for (uint i = 0; i < fileCount; i++)
                {
                    if (DragQueryFile(handle, i, sb, charLength) > 0) fileNames[i] = sb.ToString();
                }
                DragFinish(handle);
                _containerControl.AllowDrop = true;
                _containerControl.DoDragDrop(fileNames, DragDropEffects.All);
                _containerControl.AllowDrop = false;
                return true;
            }
            return false;
        }

        public void Dispose()
        {
            if (_containerControl == null)
            {
                if (_containerControl != null && _disposeControl && !_containerControl.IsDisposed) _containerControl.Dispose();
                Application.RemoveMessageFilter(this);
                _containerControl = null;
            }
        }
    }
}

在窗体中新建全局变量:

public FileDropHandler FileDropHandler;

在窗体的Load函数中初始化需要拖放的控件:

FileDropHandler = new FileDropHandler(gridData);

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
(C#加密)幻术-大踲无形发布时间:2022-07-10
下一篇:
[转载]Hello World Outlook Add-In using C#发布时间:2022-07-10
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap