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的组合使用
 
效果图:

WPF+WinForm项目代码链接:https://github.com/zhaobangyu/C-SHAP/tree/WPF/FileDragDrop

WPF 实现文件、图标拖放功能(支持UAC的那种)的更多相关文章

  1. WPF拖放功能实现zz

    写在前面:本文为即兴而作,因此难免有疏漏和词不达意的地方.在这里,非常期望您提供评论,分享您的想法和建议. 这是一篇介绍如何在WPF中实现拖放功能的短文. 首先要读者清楚的一件事情是:拖放主要分为拖放 ...

  2. WPF拖放功能实现

    写在前面:本文为即兴而作,因此难免有疏漏和词不达意的地方.在这里,非常期望您提供评论,分享您的想法和建议. 这是一篇介绍如何在WPF中实现拖放功能的短文. 首先要读者清楚的一件事情是:拖放主要分为拖放 ...

  3. WPF开发快速入门【7】WPF的拖放功能(Drag and Drop)

    概述 本文描述WPF的拖放功能(Drag and Drop). 拖放功能涉及到两个功能,一个就是拖,一个是放.拖放可以发生在两个控件之间,也可以在一个控件自己内部拖放.假设界面上有两个控件,一个Tre ...

  4. 如何使用LightningChart拖放功能进行数据转移 ?

    本文主要介绍如何使用LightningChart扩展拖放功能为所有图表组件创建图表,如:系列,标题,轴线等等.支持用鼠标放置自定义对象到另一个图表中,如:可以添加或修改JSON/CSV或其他格式的数据 ...

  5. iOS如何在应用中添加图标更换功能

    一.在info.plist中设置图标信息 首先将需要更换的图标按照下面的方式声明,以便我们能够正常调用文件和方法.注意,每个图标的图标名称和对应的文件名要一一对应. 二.在工程根目录下添加图标文件 图 ...

  6. HOW TO: 在 Visual C# .NET 应用程序中提供文件拖放功能

    本文假定您熟悉下列主题: Windows 窗体列表框控件 Windows 窗体事件处理 生成示例的步骤 列表框控件提供了您需要处理的两个拖放事件: DragEnter 和 DragDrop. 当您在控 ...

  7. WPF 4 动态覆盖图标(Dynamic Overlay Icon)

    原文:WPF 4 动态覆盖图标(Dynamic Overlay Icon)      在<WPF 4 开发Windows 7 任务栏>一文中我们学习了任务栏的相关开发内容,同时也对覆盖图标 ...

  8. c# WPF SVG 文件的引用(SharpVectors)

    原文:c# WPF SVG 文件的引用(SharpVectors) 阿里巴巴矢量图标库提供了大量的 SVG 图标:https://www.iconfont.cn/ 但是 WPF 本身不支持 SVG 格 ...

  9. MVC5:使用Ajax和HTML5实现文件上传功能

    引言 在实际编程中,经常遇到实现文件上传并显示上传进度的功能,基于此目的,本文就为大家介绍不使用flash 或任何上传文件的插件来实现带有进度显示的文件上传功能. 基本功能:实现带有进度条的文件上传功 ...

  10. Draggabilly – 轻松实现拖放功能(Drag & Drop)

    Draggabilly 是一个很小的 JavaScript 库,专注于拖放功能.只需要简单的设置参数就可以在你的网站用添加拖放功能.兼容 IE8+ 浏览器,支持多点触摸.可以灵活绑定事件,支持 Req ...

随机推荐

  1. 【转载】EXCEL VBA UBound(arr,1),UBound(arr,2)解释

    Resize(UBound(arr, 1), UBound(arr, 2) 这句什么意思   resize()是一个扩展单元格地址区域的函数,有两个参数,第一个是行扩展数,第二个是列扩展数   UBo ...

  2. .NET周报【12月第4期 2022-12-31】

    祝大家新年快乐! 国内文章 『 再看.NET7』数值类型 https://mp.weixin.qq.com/s/ctiBMPY6Hditk81AzHSRng 在C#中,有int16,用short来定义 ...

  3. 数据库日志——binlog、redo log、undo log扫盲

    日志是数据库中比较重要的组成部分,很多核心的功能必须依靠日志才能完成. 该篇文章简要介绍了binlog.redo log与undo log,能够在一定程度上拓宽对mysql日志的整体认识. binlo ...

  4. python之路48 django 视图层、模板层

    视图层之必会三板斧 用来处理请求的视图函数都必须返回HttpResponse对象 完全正确 class HttpResponse: pass return HttpResponse() def ren ...

  5. python之路44 jQuery语法应用 与Bootstrap框架

    写的略粗糙 咨询 https://www.cnblogs.com/Dominic-Ji/p/10490669.html 作业讲解 页面简陋定时器: <input type="text& ...

  6. 在函数中设置input的multiple属性以及input的点击事件时,设置失效

    1.在函数中先设置input文件可以多选,然后再设置input框的点击事件情况下,有时候这个多选设置会失效. 我们可以采用下面的方式去解决 <input ref="myInputRef ...

  7. Collection集合常用功能-Iterator接口介绍

    Collection集合常用功能 Collection是所有单列集合的父接口,因此在Collection中定义了单列集合(List和Set)通用的一些方法,这些方法可用于操作所有的单列集合.方法如下︰ ...

  8. Vue02 Node下载安装

    转 https://blog.csdn.net/A_awen/article/details/121952701 1 下载 https://nodejs.org/en/download/ 2 安装 全 ...

  9. 云萌 V2.6.3.0 win10,win11 Windows永久激活工具

    Windows如果一直不激活,其实用起来问题也不大,除了无法修改壁纸.颜色.锁屏.主题以及无法使用微软账号的同步功能等之外,绝大多数的基本功能都可以正常使用.不过该激活还是得激活的.别的不说,就桌面右 ...

  10. 【TS】class类和接口

    class可以用来做数据的存储与回显,能将页面的数据分离出来并提取到class内,函数也可以抽离到class,实例化class进行调用.ts中的class类与js的class类基本相同,不同点在于ts ...