C# 使用Win32 API进行文件拖放在某些应用程序(如文件资源管理器)上不起作用
我已经在.NET核心应用程序上实现了。问题是,它适用于某些应用程序,而不适用于其他一些应用程序C# 使用Win32 API进行文件拖放在某些应用程序(如文件资源管理器)上不起作用,c#,winapi,.net-core,pinvoke,ole,C#,Winapi,.net Core,Pinvoke,Ole,我已经在.NET核心应用程序上实现了。问题是,它适用于某些应用程序,而不适用于其他一些应用程序 作品:记事本++,记事本,写字板,MS Word,Gimp,7Zip 不工作:(Windows)文件浏览器、Chrome、FireFox、VS代码、Libre Writer、Android Studio 为什么会这样 我的实现IDataObject的“DataObject”为EnumFormatEtc()返回这个FORMATETC。其中我只返回一个表单等 new FORMATETC() {
- 作品:记事本++,记事本,写字板,MS Word,Gimp,7Zip
- 不工作:(Windows)文件浏览器、Chrome、FireFox、VS代码、Libre Writer、Android Studio
EnumFormatEtc()
返回这个FORMATETC
。其中我只返回一个表单等
new FORMATETC()
{
cfFormat = CF_HDROP,
ptd = IntPtr.Zero,
dwAspect = DVASPECT.DVASPECT_ICON,
lindex = -1,
tymed = TYMED.TYMED_HGLOBAL
}
在QueryGetData()
上,如果格式的tymed是tymed\u HGLOBAL
,则返回s\u OK表示我正在拖动文件。否则返回DV_E___TYMED,表示我没有该类型的数据
在GetData()
或GetDataHere()
上,如果format.cfFormat==CF_HDROP
和format.tymed==tymed.tymed_HGLOBAL
,我会像这样填充介质:
medium = new STGMEDIUM();
medium.tymed = TYMED.TYMED_HGLOBAL;
medium.unionmember = mem;
medium.pUnkForRelease = IntPtr.Zero;
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;
}
,其中mem
是分配给DROPFILES
的内存,如下所示:
medium = new STGMEDIUM();
medium.tymed = TYMED.TYMED_HGLOBAL;
medium.unionmember = mem;
medium.pUnkForRelease = IntPtr.Zero;
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;
}
相比之下,使用WinForm的方法将文件拖放到文件资源管理器或VS代码中(如下所示)效果很好
var data = new System.Windows.Forms.DataObject(
System.Windows.Forms.DataFormats.FileDrop,
new string[] { file1, file2 });
dummy.DoDragDrop(data, System.Windows.Forms.DragDropEffects.Copy);
您是否考虑过安全问题(UAC)?不在同一UAC级别运行的两个应用程序无法通信(使用D&D)。例如,如果您以标准方式运行Explorer(而非admin),则无法使用以admin身份运行的应用程序进行D&D。请进行一些调试,查看您尝试拖动到这些应用程序时调用了哪些方法,以及它们的要求。并非所有应用程序都能处理CF\u HDROP
。要支持广泛的应用程序,请实现尽可能多的应用程序。实现的格式越多,可以与之交换数据的应用程序就越多。也就是说,DVASPECT\u图标
是错误的dwAspect
对于CF\u HDROP
,请使用DVASPECT\u内容
。而您的缓冲区
缺少一个字节,它需要用一个2字节的空Unicode字符终止字符串列表,但您要用一个空字节终止它。您需要2个空字节,就像每个字符串的结尾一样。如果您仍然有问题,我建议查看,看看它是如何实现System.Windows.Forms.DataFormats.FileDrop
。