管理员权限下程序拖放功能失效问题

前言

  最近写的一个小工具因涉及到系统文件的操作,故需要以管理员身份运行,但这影响到了程序的文件拖放功能,即DragDrop事件。而一番搜索后,发现这个问题还是令很多人感到棘手的,而大部分网友给出的解决方法均是效果不佳。很幸运的是博主发现了一个很稳的解决方法,这里做个记录。

原因

  不同权限提升级别的程序之间是无法共享拖放消息的,这就导致了例如RequireAdministrator权限提升级别的程序读取不到InvokeAsUser权限提升级别的Windows Explorer中的文件数据的问题。即低权限的进程无法向高权限的进程发送任何高于WM_USER的消息,而低于WM_USER的消息一部分也会因为安全原因被禁止。故同样级别的权限提升账户运行的程序则可以共享拖放消息。

解决

  综合原因分析,可以得知通常所用的AllowDrop只限于同级别权限的程序之间共享消息。故要解决这个问题则可以使用传统的拖放方法,即WndProc函数中的消息。
  这里需要注意的是,此解决方案无需启用控件的AllowDrop属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
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;
protected ElevatedDragDropManager()
{
Application.AddMessageFilter(this);
}

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>();
}
}

使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private void Form1_ElevatedDragDrop(System.Object sender, ElevatedDragDropArgs e)
{
// Add the files to listview
if (e.HWnd == listView1.Handle)
{
foreach (string file in e.Files)
{
listView1.Items.Add(file);
}
}
}

private void Form1_Load(object sender, EventArgs e)
{
ElevatedDragDropManager.Instance.EnableDragDrop(listView1.Handle);
// Enable elevated drag drop on listView1. Note that I used the Handle property
ElevatedDragDropManager.Instance.ElevatedDragDrop += Form1_ElevatedDragDrop;
}
-------------本文结束❤感谢阅读-------------

本文标题:管理员权限下程序拖放功能失效问题

文章作者:三水非冰

发布时间:2018年12月23日

最后更新:2018年12月23日

原始链接:https://www.sanshuifeibing.cn/posts/3ef39864.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

如果觉得我的文章对您有用,请随意打赏,您的支持将鼓励我继续创作。