I have implemented file drag-and-drop using Win32 API on a .NET Core app. The problem is, it works with some applications, and not with some other applications.
- Works: Notepad++, Notepad, WordPad, MS Word, Gimp, 7Zip
- Doesn't work: (Windows) File Explorer, Chrome, FireFox, VS Code, Libre Writer, Android Studio
Why is it so?
My "DataObject" implementing IDataObject returns this one FORMATETC
for EnumFormatEtc()
. In which I return only one FORMATETC.
new FORMATETC()
{
cfFormat = CF_HDROP,
ptd = IntPtr.Zero,
dwAspect = DVASPECT.DVASPECT_ICON,
lindex = -1,
tymed = TYMED.TYMED_HGLOBAL
}
On QueryGetData()
, if the format's tymed is TYMED_HGLOBAL
, return S_OK meaning I am dragging a file. Otherwise return DV_E_TYMED meaning I don't have that type of data.
On GetData()
or GetDataHere()
, if format.cfFormat == CF_HDROP
and format.tymed == TYMED.TYMED_HGLOBAL
, I filled the medium
like so:
medium = new STGMEDIUM();
medium.tymed = TYMED.TYMED_HGLOBAL;
medium.unionmember = mem;
medium.pUnkForRelease = IntPtr.Zero;
, where mem
is the memory allocated with a DROPFILES
like so:
IntPtr CreateDropFiles(string[] strFiles)
{
var buffer = new MemoryStream();
var df = new DROPFILES();
IntPtr ipGlobal = IntPtr.Zero;
int bufferLength;
foreach(var file in strFiles)
{
var b = Encoding.Unicode.GetBytes(file);
buffer.Write(b, 0, b.Length);
buffer.WriteByte(0);
buffer.WriteByte(0);
}
buffer.WriteByte(0);
bufferLength = (int)buffer.Length;
// Allocate and get pointer to global memory
int intTotalLen = Marshal.SizeOf(df) + bufferLength;
ipGlobal = Marshal.AllocHGlobal(intTotalLen);
df.pFiles = Marshal.SizeOf(df);
df.fWide = true;
Marshal.StructureToPtr(df, ipGlobal, true);
var ipNew = new IntPtr(ipGlobal.ToInt64() + Marshal.SizeOf(df));
Marshal.Copy(buffer.ToArray(), 0, ipNew, bufferLength);
return ipGlobal;
}
In contrast, file drag-and-drop to File Explorer or VS Code using WinForm's method like the following worked just fine.
var data = new System.Windows.Forms.DataObject(
System.Windows.Forms.DataFormats.FileDrop,
new string[] { file1, file2 });
dummy.DoDragDrop(data, System.Windows.Forms.DragDropEffects.Copy);