WPF 实现文件、图标拖放功能(支持UAC的那种)
WPF实现文件拖放功能,正常情况并没有什么问题,但是如果你的程序使用管理员身份启动,你就会发现文件拖放功能就会失效。
这是因为WPF 在不同UAC等级下,是不允许拖放的。
原理很简单,与桌面相关联的进程为 explorer.exe,即 explorer.exe 这个进程启动的方式是非管理员身份,当你的程序使用管理员身份启动时,就会导致拖放失败。
因为二者的权限不一样,系统不允许不同权限的进程进行通讯,包括进程通讯等操作。
解决方案:
方案一(不推荐):让 explorer.exe 也使用管理员身份启动。举例Win7系统只需这样设置下并重启系统即可,如下图:
这种方案能解决问题,但是你不可能让用户去做这种操作,所以只能算一个解决方案,并不能解决实际的问题。
方案二:让你的程序使用非管理员启动,程序中需要管理员身份的操作,一般为涉及到注册表操作或驱动操作,可以考虑将这部分操作放到一个服务里单独操作,可以理解为程序分成服务与应用程序两块,需要管理员身份操作的
功能部分放到服务里实现,界面相关的操作在应用程序里实现。
这种方案也能解决,并且问题解决的比较彻底,但是项目工程量比较大的情况下,工作量就比较大了,为一个文件拖放的功能,增加了较大的工作量,得不偿失。
方案三:提供一个折中的办法,WPF经过我较长的上网搜索及研究,没有找到合适的办法解决这个问题,但是 WinForm 通过消息Hook却能实现,所以这个折中的办法就是WPF+WinForm来解决这个问题。
下面我们将主要讲解如何使用 WPF+WinForm 解决WPF程序使用管理员身份启动后不能拖放文件的问题。
第一部分:使用 WinForm 解决使用不能拖动的问题,关键代码如下
ElevatedDragDropManager.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Windows; public class ElevatedDragDropManager : IMessageFilter
{
#region "P/Invoke"
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool ChangeWindowMessageFilterEx(IntPtr hWnd, uint msg, ChangeWindowMessageFilterExAction action, ref CHANGEFILTERSTRUCT changeInfo); [DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool ChangeWindowMessageFilter(uint msg, ChangeWindowMessageFilterFlags flags); [DllImport("shell32.dll")]
private static extern void DragAcceptFiles(IntPtr hwnd, bool fAccept); [DllImport("shell32.dll")]
private static extern uint DragQueryFile(IntPtr hDrop, uint iFile, [Out()]
StringBuilder lpszFile, uint cch); [DllImport("shell32.dll")]
private static extern bool DragQueryPoint(IntPtr hDrop, ref POINT lppt); [DllImport("shell32.dll")]
private static extern void DragFinish(IntPtr hDrop); [StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int X; public int Y;
public POINT(int newX, int newY)
{
X = newX;
Y = newY;
} public static implicit operator System.Drawing.Point(POINT p)
{
return new System.Drawing.Point(p.X, p.Y);
} public static implicit operator POINT(System.Drawing.Point p)
{
return new POINT(p.X, p.Y);
}
} private enum MessageFilterInfo : uint
{
None,
AlreadyAllowed,
AlreadyDisAllowed,
AllowedHigher
} private enum ChangeWindowMessageFilterExAction : uint
{
Reset,
Allow,
Disallow
} private enum ChangeWindowMessageFilterFlags : uint
{
Add = 1,
Remove = 2
} [StructLayout(LayoutKind.Sequential)]
private struct CHANGEFILTERSTRUCT
{
public uint cbSize;
public MessageFilterInfo ExtStatus;
}
#endregion public static ElevatedDragDropManager Instance = new ElevatedDragDropManager();
public event EventHandler<ElevatedDragDropArgs> ElevatedDragDrop; private const uint WM_DROPFILES = 0x233;
private const uint WM_COPYDATA = 0x4a; private const uint WM_COPYGLOBALDATA = 0x49;
private readonly bool IsVistaOrHigher = Environment.OSVersion.Version.Major >= 6; private readonly bool Is7OrHigher = (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor >= 1) || Environment.OSVersion.Version.Major > 6; public void EnableDragDrop(IntPtr hWnd)
{
if (Is7OrHigher)
{
CHANGEFILTERSTRUCT changeStruct = new CHANGEFILTERSTRUCT();
changeStruct.cbSize = Convert.ToUInt32(Marshal.SizeOf(typeof(CHANGEFILTERSTRUCT)));
ChangeWindowMessageFilterEx(hWnd, WM_DROPFILES, ChangeWindowMessageFilterExAction.Allow, ref changeStruct);
ChangeWindowMessageFilterEx(hWnd, WM_COPYDATA, ChangeWindowMessageFilterExAction.Allow, ref changeStruct);
ChangeWindowMessageFilterEx(hWnd, WM_COPYGLOBALDATA, ChangeWindowMessageFilterExAction.Allow, ref changeStruct);
}
else if (IsVistaOrHigher)
{
ChangeWindowMessageFilter(WM_DROPFILES, ChangeWindowMessageFilterFlags.Add);
ChangeWindowMessageFilter(WM_COPYDATA, ChangeWindowMessageFilterFlags.Add);
ChangeWindowMessageFilter(WM_COPYGLOBALDATA, ChangeWindowMessageFilterFlags.Add);
} DragAcceptFiles(hWnd, true);
} public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_DROPFILES)
{
HandleDragDropMessage(m);
return true;
}
return false;
} private void HandleDragDropMessage(Message m)
{
dynamic sb = new StringBuilder(260);
uint numFiles = DragQueryFile(m.WParam, 0xffffffffu, sb, 0);
dynamic list = new List<string>(); for (uint i = 0; i <= numFiles - 1; i++)
{
if (DragQueryFile(m.WParam, i, sb, Convert.ToUInt32(sb.Capacity) * 2) > 0)
{
list.Add(sb.ToString());
}
} POINT p = default(POINT);
DragQueryPoint(m.WParam, ref p);
DragFinish(m.WParam); dynamic args = new ElevatedDragDropArgs();
args.HWnd = m.HWnd;
args.Files = list;
args.X = p.X;
args.Y = p.Y; if (ElevatedDragDrop != null)
{
ElevatedDragDrop(this, args);
}
}
} public class ElevatedDragDropArgs : EventArgs
{
public IntPtr HWnd
{
get { return m_HWnd; }
set { m_HWnd = value; }
}
private IntPtr m_HWnd;
public List<string> Files
{
get { return m_Files; }
set { m_Files = value; }
}
private List<string> m_Files;
public int X
{
get { return m_X; }
set { m_X = value; }
}
private int m_X;
public int Y
{
get { return m_Y; }
set { m_Y = value; }
} private int m_Y;
public ElevatedDragDropArgs()
{
Files = new List<string>();
}
}
Form1.cs
注:需要将Form1窗口的AllowDrop属性设置为false,否则无法拖动文件。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms; namespace FileDragDrop
{
public partial class FileDragDrop : Form
{
public FileDragDrop()
{
InitializeComponent();
//this.AllowDrop设置为false
this.AllowDrop = false;
ElevatedDragDropManager filter = new ElevatedDragDropManager();
//开启拖放功能
filter.EnableDragDrop(this.Handle);
//添加消息过滤器
Application.AddMessageFilter(filter);
//设置拖放结束回调
filter.ElevatedDragDrop += this.ElevatedDragDrop;
} //拖放结束事件
private void ElevatedDragDrop(System.Object sender, ElevatedDragDropArgs e)
{
try
{
if (e.HWnd == this.Handle)
{
foreach (string file in e.Files)
{
//拖动文件
MessageBox.Show("ElevatedDragDrop File=" + (file) + "!");
}
}
}
catch (Exception ex)
{
//异常信息
MessageBox.Show("ElevatedDragDrop error=" + (ex.TargetSite?.Name) + "!");
}
}
}
}
最终的效果:
WinForm项目代码链接:https://github.com/zhaobangyu/C-SHAP/tree/WinForm
WPF+WinForm项目代码链接:https://github.com/zhaobangyu/C-SHAP/tree/WPF/FileDragDrop
最新文章
- difference between forward and sendredirect
- Marbles启动信息
- web.xml 配置的详解
- jqgrid在页面出来竖型滚动条自动调整列宽
- Nico Game Studio 2.设置页面读写 纹理载入与选择
- CoreCLR源码探索(三) GC内存分配器的内部实现
- Java中equals和==之间的区别
- asp.net web api 2.2 基础框架(带例子)
- NOIP 2017 Day 0. 游记
- hdu1394 分治 or 线段树
- POSIX信号量
- 低延时的P2P HLS直播技术实践
- layui topbar图标(即返回顶部)未显示的解决方法
- Python——assert(断言函数)
- Natural Language Generation/Abstractive Summarization
- bzoj2243树链剖分+区间合并
- windows安装Anaconda3
- 【LOJ#10131】暗的锁链
- MongoDB 工具助手类(.NET)
- Hyperledger Fabric1.0.0搭建
热门文章
- [python] 基于matplotlib实现树形图的绘制
- 腾讯出品小程序自动化测试框架【Minium】系列(一)环境搭建之第一个测试程序
- 通过Terraform创建GCP Pubsub
- flutter 底部滑动导航,页面滑动同时让底部导航跟着变动,除了点击还可以滑动哦~~
- 【学习笔记】动态树 Link-Cut Tree
- 在spring boot3中使用native image
- Golang编译
- Node.js 应用全链路追踪技术——全链路信息存储
- SpringBoot+MyBatis的动态SQL、使用动态SQL时List传值错误解决方案
- vue学习笔记(一)---- vue指令( v-on 事件绑定 )