解决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/
签名:成熟是一种明亮而不刺眼的光辉。

浙公网安备 33010602011771号