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

最新文章

  1. difference between forward and sendredirect
  2. Marbles启动信息
  3. web.xml 配置的详解
  4. jqgrid在页面出来竖型滚动条自动调整列宽
  5. Nico Game Studio 2.设置页面读写 纹理载入与选择
  6. CoreCLR源码探索(三) GC内存分配器的内部实现
  7. Java中equals和==之间的区别
  8. asp.net web api 2.2 基础框架(带例子)
  9. NOIP 2017 Day 0. 游记
  10. hdu1394 分治 or 线段树
  11. POSIX信号量
  12. 低延时的P2P HLS直播技术实践
  13. layui topbar图标(即返回顶部)未显示的解决方法
  14. Python——assert(断言函数)
  15. Natural Language Generation/Abstractive Summarization
  16. bzoj2243树链剖分+区间合并
  17. windows安装Anaconda3
  18. 【LOJ#10131】暗的锁链
  19. MongoDB 工具助手类(.NET)
  20. Hyperledger Fabric1.0.0搭建

热门文章

  1. [python] 基于matplotlib实现树形图的绘制
  2. 腾讯出品小程序自动化测试框架【Minium】系列(一)环境搭建之第一个测试程序
  3. 通过Terraform创建GCP Pubsub
  4. flutter 底部滑动导航,页面滑动同时让底部导航跟着变动,除了点击还可以滑动哦~~
  5. 【学习笔记】动态树 Link-Cut Tree
  6. 在spring boot3中使用native image
  7. Golang编译
  8. Node.js 应用全链路追踪技术——全链路信息存储
  9. SpringBoot+MyBatis的动态SQL、使用动态SQL时List传值错误解决方案
  10. vue学习笔记(一)---- vue指令( v-on 事件绑定 )