解决C#拖放文件无效的问题
我们可以向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);
作者:我也是个傻瓜
出处:http://www.cnblogs.com/liweis/
签名:成熟是一种明亮而不刺眼的光辉。