Reputation: 21880
I have had a project for quite a while using C# winforms. I implemented a drag-drop function before windows 7 was released. Worked like a charm. However, when using windows 7 it does not work. The event doesn't even get triggered.
AllowDrop
is set to true. When subscribing to DragEnter
it does not get called in windows 7 (not sure about vista). But on XP it works all the way. The program is run with administritave priviliges.
Is there any difference in the drag drop in windows 7 vs xp? Don't know if it's relevant, but I'm using x64
Upvotes: 48
Views: 28717
Reputation: 176
From here
NOTE: AllowDrop for control must be set to false
Elevated class:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace Drag_n_Drop
{
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>();
}
}
}
Usage:
using Drag_n_Drop;
//...
private void Form1_Load(object sender, EventArgs e)
{
// Вызываем EnableDragDrop() для каждого дискриптора элемента формы, для которого нужно использовать функция DnD
// в данном примере это сама форма и label1
ElevatedDragDropManager.Instance.EnableDragDrop(this.Handle);
ElevatedDragDropManager.Instance.EnableDragDrop(label1.Handle);
ElevatedDragDropManager.Instance.ElevatedDragDrop += Form1_ElevatedDragDrop;
}
private void Form1_ElevatedDragDrop(System.Object sender, ElevatedDragDropArgs e)
{
if (e.HWnd == this.Handle || e.HWnd == label1.Handle)
{
string filelist = String.Empty;
foreach (string file in e.Files)
{
filelist += file + Environment.NewLine;
}
MessageBox.Show(filelist);
}
}
Upvotes: 0
Reputation: 38444
The source and target processes need to have compatible security levels/privileges. For example, if your source is Explorer and it is running with user level privileges, but your target application is running with administrator (elevated) level permission, you will not be able to drag&drop as this is seen as a security issue as the target is running with a higher level of privileges.
Upvotes: 80
Reputation: 1042
I had same problem when debugging a desktop C# application from VS 2015 and Windows 7 x64 as S.O. It was due to the administrator permission applied over the shortcut of my VS IDE in the desktop (see screenshot). Unchecking this option Drag & Drop events raise properly.
Thanks to TimLloyd for his help.
Upvotes: 1
Reputation: 1504
It may be unrelated, but I was having whacky Drag-n-Drop issues with Windows 8. It would work for a while and then stop working. I couldn't drag-n-drop between Explorer, in an editor, etc. It turns out that when I interacted with a Hyper-V VM running windows 7, my drag-n-drop ability was altered (or perhaps it was the ctrl-alt-end keystroke to simulate crtl-alt-delete to Hyper-V). In any event, one the issue occurred, the following resolved it:
I found the resolution to my problem here: Fix Drag Drop Functionality Not Working In Windows 7 Vista XP
Basically the solution was:
Left-Click on a file in explorer, and while holding down the mouse button, press [Esc] then [Ctrl], then release the mouse button. I have to assume that this is resetting some accessibility setting or something.
Upvotes: 1
Reputation: 37
A Minor addition to dmex's post. The following defines the variables and the constant.
private const uint WM_DROPFILES = 0x233;
private const uint WM_COPYDATA = 0x004A;
private const uint WM_COPYGLOBALDATA = 0x0049;
private const uint MSGFLT_ADD = 1;
Also, you may want to consider using ChangeWindowMessageFilterEx
if you're application is on Windows 7. I also believe that OLE drag and drop may not use Windows messaging. So it wouldn't effect that at all.
Upvotes: 1
Reputation: 532
From your application, call ChangeWindowMessageFilter with the following values to allow dragging and dropping to/from your elevated application and non-elevated applications like Explorer:
ChangeWindowMessageFilter (WM_DROPFILES, MSGFLT_ADD);
ChangeWindowMessageFilter (WM_COPYDATA, MSGFLT_ADD);
ChangeWindowMessageFilter (0x0049, MSGFLT_ADD);
Upvotes: 1
Reputation: 941585
It is called UIPI, User Interface Privilege Isolation. Designed to prevent input injection exploits from programs that run with restricted privileges. It can be disabled, you'll need to do this:
<requestedExecutionLevel>
element to true.Never actually tried this, ymmv.
Upvotes: 19