我一直在尝试将chrome中的gmail附件拖放到我的应用程序中。
可以将文件从电子邮件拖到桌面,然后在那里创建附件,所以我知道这一定是可能的。
我能够让它读取文件名,但是当我从数据对象中读取FileContents时,我得到一个带有文件链接的互联网快捷方式。
以前有人有这个工作吗?目前的代码是硬编码的.txt文件
示例项目可以从以下网址下载:
https://www.dropbox.com/s/jz4zde0mvgxzn1g/DragDropTest.zip?dl=0
我的主要DataObjectWrapper类如下:
要发布所有内容的字符太多,但主要方法是:
public object GetDataNative(string format, bool autoConvert)
{
switch (format)
{
case CFSTR_FILEDESCRIPTOR_A:
IntPtr fileGroupDescriptorAPointer = IntPtr.Zero;
try
{
//use the underlying IDataObject to get the FileGroupDescriptor as a MemoryStream
MemoryStream fileGroupDescriptorStream = (MemoryStream)this.underlyingDataObject.GetData(CFSTR_FILEDESCRIPTOR_A, autoConvert);
byte[] fileGroupDescriptorBytes = new byte[fileGroupDescriptorStream.Length];
fileGroupDescriptorStream.Read(fileGroupDescriptorBytes, 0, fileGroupDescriptorBytes.Length);
fileGroupDescriptorStream.Close();
//copy the file group descriptor into unmanaged memory
fileGroupDescriptorAPointer = Marshal.AllocHGlobal(fileGroupDescriptorBytes.Length);
Marshal.Copy(fileGroupDescriptorBytes, 0, fileGroupDescriptorAPointer, fileGroupDescriptorBytes.Length);
//marshal the unmanaged memory to to FILEGROUPDESCRIPTORA struct
object fileGroupDescriptorObject = Marshal.PtrToStructure(fileGroupDescriptorAPointer, typeof(NativeMethods.FILEGROUPDESCRIPTORA));
NativeMethods.FILEGROUPDESCRIPTORA fileGroupDescriptor = (NativeMethods.FILEGROUPDESCRIPTORA)fileGroupDescriptorObject;
//get the pointer to the first file descriptor
IntPtr fileDescriptorPointer = (IntPtr)((int)fileGroupDescriptorAPointer + Marshal.SizeOf(fileGroupDescriptor.cItems));
NativeMethods.FILEDESCRIPTORA[] fileDescriptors = new NativeMethods.FILEDESCRIPTORA[fileGroupDescriptor.cItems];
//loop for the number of files acording to the file group descriptor
for (int fileDescriptorIndex = 0; fileDescriptorIndex < fileGroupDescriptor.cItems; fileDescriptorIndex++)
{
//marshal the pointer top the file descriptor as a FILEDESCRIPTORA struct and get the file name
NativeMethods.FILEDESCRIPTORA fileDescriptor = (NativeMethods.FILEDESCRIPTORA)Marshal.PtrToStructure(fileDescriptorPointer, typeof(NativeMethods.FILEDESCRIPTORA));
fileDescriptors[fileDescriptorIndex] = fileDescriptor;
//move the file descriptor pointer to the next file descriptor
fileDescriptorPointer = (IntPtr)((int)fileDescriptorPointer + Marshal.SizeOf(fileDescriptor));
}
fileGroupDescriptor.fgd = fileDescriptors;
//return the array of filenames
return fileGroupDescriptor;
}
finally
{
//free unmanaged memory pointer
Marshal.FreeHGlobal(fileGroupDescriptorAPointer);
}
case CFSTR_FILEDESCRIPTOR_W:
IntPtr fileGroupDescriptorWPointer = IntPtr.Zero;
try
{
//use the underlying IDataObject to get the FileGroupDescriptorW as a MemoryStream
MemoryStream fileGroupDescriptorStream = (MemoryStream)this.underlyingDataObject.GetData(CFSTR_FILEDESCRIPTOR_W);
byte[] fileGroupDescriptorBytes = new byte[fileGroupDescriptorStream.Length];
fileGroupDescriptorStream.Read(fileGroupDescriptorBytes, 0, fileGroupDescriptorBytes.Length);
fileGroupDescriptorStream.Close();
//copy the file group descriptor into unmanaged memory
fileGroupDescriptorWPointer = Marshal.AllocHGlobal(fileGroupDescriptorBytes.Length);
Marshal.Copy(fileGroupDescriptorBytes, 0, fileGroupDescriptorWPointer, fileGroupDescriptorBytes.Length);
//marshal the unmanaged memory to to FILEGROUPDESCRIPTORW struct
object fileGroupDescriptorObject = Marshal.PtrToStructure(fileGroupDescriptorWPointer, typeof(NativeMethods.FILEGROUPDESCRIPTORW));
NativeMethods.FILEGROUPDESCRIPTORW fileGroupDescriptor = (NativeMethods.FILEGROUPDESCRIPTORW)fileGroupDescriptorObject;
//get the pointer to the first file descriptor
IntPtr fileDescriptorPointer = (IntPtr)((int)fileGroupDescriptorWPointer + Marshal.SizeOf(fileGroupDescriptor.cItems));
NativeMethods.FILEDESCRIPTORW[] fileDescriptiors = new NativeMethods.FILEDESCRIPTORW[fileGroupDescriptor.cItems];
//loop for the number of files acording to the file group descriptor
for (int fileDescriptorIndex = 0; fileDescriptorIndex < fileGroupDescriptor.cItems; fileDescriptorIndex++)
{
//marshal the pointer top the file descriptor as a FILEDESCRIPTORW struct and get the file name
NativeMethods.FILEDESCRIPTORW fileDescriptor = (NativeMethods.FILEDESCRIPTORW)Marshal.PtrToStructure(fileDescriptorPointer, typeof(NativeMethods.FILEDESCRIPTORW));
fileDescriptiors[fileDescriptorIndex] = fileDescriptor;
//move the file descriptor pointer to the next file descriptor
fileDescriptorPointer = (IntPtr)((int)fileDescriptorPointer + Marshal.SizeOf(fileDescriptor));
}
fileGroupDescriptor.fgd = fileDescriptiors;
//return the array of filenames
return fileGroupDescriptor;
}
finally
{
//free unmanaged memory pointer
Marshal.FreeHGlobal(fileGroupDescriptorWPointer);
}
case CFSTR_FILECONTENTS:
//override the default handling of FileContents which returns the
//contents of the first file as a memory stream and instead return
//a array of MemoryStreams containing the data to each file dropped
//get the array of filenames which lets us know how many file contents exist
string[] fileContentNames = (string[])this.GetData(CFSTR_FILEDESCRIPTOR_W);
//create a MemoryStream array to store the file contents
MemoryStream[] fileContents = new MemoryStream[fileContentNames.Length];
//loop for the number of files acording to the file names
for (int fileIndex = 0; fileIndex < fileContentNames.Length; fileIndex++)
{
//get the data at the file index and store in array
fileContents[fileIndex] = this.GetData(format, fileIndex);
}
//return array of MemoryStreams containing file contents
return fileContents;
case CFSTR_INETURL_A:
//use the underlying IDataObject to get the FileGroupDescriptorW as a MemoryStream
MemoryStream UniformResourceLocatorStream = (MemoryStream)this.underlyingDataObject.GetData(CFSTR_INETURL_A);
byte[] UniformResourceLocatorBytes = new byte[UniformResourceLocatorStream.Length];
UniformResourceLocatorStream.Read(UniformResourceLocatorBytes, 0, UniformResourceLocatorBytes.Length);
UniformResourceLocatorStream.Close();
string url = null;
if (UniformResourceLocatorBytes[1] == 0)
url = Encoding.Unicode.GetString(UniformResourceLocatorBytes);
else
url = Encoding.ASCII.GetString(UniformResourceLocatorBytes);
return url;
case CFSTR_INETURL_W:
//use the underlying IDataObject to get the FileGroupDescriptorW as a MemoryStream
MemoryStream UniformResourceLocatorWStream = (MemoryStream)this.underlyingDataObject.GetData(CFSTR_INETURL_W);
byte[] UniformResourceLocatorWBytes = new byte[UniformResourceLocatorWStream.Length];
UniformResourceLocatorWStream.Read(UniformResourceLocatorWBytes, 0, UniformResourceLocatorWBytes.Length);
UniformResourceLocatorWStream.Close();
string urlW = null;
if (UniformResourceLocatorWBytes[1] == 0)
urlW = Encoding.Unicode.GetString(UniformResourceLocatorWBytes);
else
urlW = Encoding.ASCII.GetString(UniformResourceLocatorWBytes);
return urlW;
case TEXT_X_MOZ_URL:
//use the underlying IDataObject to get the FileGroupDescriptorW as a MemoryStream
MemoryStream textMozStream = (MemoryStream)this.underlyingDataObject.GetData(TEXT_X_MOZ_URL);
byte[] textMozBytes = new byte[textMozStream.Length];
textMozStream.Read(textMozBytes, 0, textMozBytes.Length);
textMozStream.Close();
string urlText = null;
if (textMozBytes[1] == 0)
urlText = Encoding.Unicode.GetString(textMozBytes);
else
urlText = Encoding.ASCII.GetString(textMozBytes);
return urlText;
case "text/html":
//use the underlying IDataObject to get the FileGroupDescriptorW as a MemoryStream
MemoryStream dataFormatStream = (MemoryStream)this.underlyingDataObject.GetData("text/html");
byte[] dataFormatBytes = new byte[dataFormatStream.Length];
dataFormatStream.Read(dataFormatBytes, 0, dataFormatBytes.Length);
dataFormatStream.Close();
string formatText = null;
if (dataFormatBytes[1] == 0)
formatText = Encoding.Unicode.GetString(dataFormatBytes);
else
formatText = Encoding.ASCII.GetString(dataFormatBytes);
return formatText;
}
//use underlying IDataObject to handle getting of data
return this.underlyingDataObject.GetData(format, autoConvert);
}
我可以从中获取相当多的数据,但就像它被丢弃在桌面上一样:
private void Form1_DragDrop(object sender, DragEventArgs e)
{
string[] dataFormats = e.Data.GetFormats();
Dictionary<string, object> dataDictionary = new Dictionary<string, object>();
foreach (string dataFormat in dataFormats)
{
dataDictionary.Add(dataFormat, e.Data.GetData(dataFormat));
Debug.WriteLine(
String.Format("Data Format: {0} Has data: {1} Data: {2}",
dataFormat,
dataDictionary[dataFormat] != null ? "Yes" : "No",
dataDictionary[dataFormat] != null ? dataDictionary[dataFormat] : string.Empty));
}
DataObjectWrapper dataWrapper = new DragDropTest.DataObjectWrapper(e.Data);
DataObjectWrapper.NativeMethods.FILEGROUPDESCRIPTORW fileGroupDescriptorW = dataWrapper.GetFileGroupDescriptorW();
string url = dataWrapper.GetUniformResourceLocatorA();
string urlw = dataWrapper.GetUniformResourceLocatorW();
string mozUrl = dataWrapper.GetTextMozURL();
string textHTML = dataWrapper.GetTExtHtml();
Stream[] streams = dataWrapper.GetFileContents();
byte[] buffer = new byte[1024];
int received = 0;
FileStream fileStream = File.OpenWrite(@"c:\temp\hello.txt");
using (Stream input = streams[0])
{
int size = input.Read(buffer, 0, buffer.Length);
while (size > 0)
{
fileStream.Write(buffer, 0, size);
received += size;
size = input.Read(buffer, 0, buffer.Length);
}
}
fileStream.Flush();
fileStream.Close();
return;
}
我已阅读并尝试过以下链接:
http://dlaa.me/blog/post/9913083
Drag and Drop large virtual files with IStream using VirtualFileDataObject
Drag and drop large virtual files from C# to Windows Explorer
https://msdn.microsoft.com/en-us/library/windows/desktop/bb776902(v=vs.85).aspx#CFSTR_FILECONTENTS
https://msdn.microsoft.com/en-us/library/windows/desktop/bb776904(v=vs.85).aspx
https://dlaa.me/blog/post/9923072
Drag and drop virtual files using IStream
Implementing drag-drop from Chrome on my .NET Windows form
https://blogs.msdn.microsoft.com/adamroot/2008/02/19/shell-style-drag-and-drop-in-net-part-3/
https://blogs.msdn.microsoft.com/adamroot/2008/02/19/shell-style-drag-and-drop-in-net-part-2/
https://blogs.msdn.microsoft.com/adamroot/2008/02/02/dragdroplib-cs/
https://www.codeproject.com/reference/1091137/windows-clipboard-formats
http://dlaa.me/blog/post/9923072
Drag and drop virtual files using IStream
http://www.ookii.org/Blog/opening_files_via_idroptarget_in_net
https://www.codeproject.com/Articles/28209/Outlook-Drag-and-Drop-in-C
答案 0 :(得分:1)
您应该可以使用代码拖放嵌入式图像。但是,附件(例如zip或pdf文件)是从Chrome以“ FileDrop”格式传输的。不幸的是,它使用了DotNet本身不支持的异步拖放接口。这就是为什么GetData(“ FileDrop”)始终返回null的原因。
您需要使用接口IDataObjectAsyncCapability触发下载。但是首先有必要将DataObject拆开以到达基础COM-DataObject:
using System;
using System.Collections.Specialized;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Threading.Tasks;
namespace Dummy
{
public class FileDrop
{
[ComImport]
[Guid("3D8B0590-F691-11d2-8EA9-006097DF5BD4")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDataObjectAsyncCapability
{
void SetAsyncMode([In] Int32 fDoOpAsync);
void GetAsyncMode([Out] out Int32 pfIsOpAsync);
void StartOperation([In] IBindCtx pbcReserved);
void InOperation([Out] out Int32 pfInAsyncOp);
void EndOperation([In] Int32 hResult, [In] IBindCtx pbcReserved, [In] UInt32 dwEffects);
}
public static async Task<StringCollection> GetFileDrop(System.Windows.Forms.DataObject dataobject)
{
if (dataobject.ContainsFileDropList())
{
var files = dataobject.GetFileDropList();
if (files.Count == 0)
{
// try async version
if (await ProcessFileDropAsync(dataobject))
{
files = dataobject.GetFileDropList();
}
}
return files;
}
// return empty collection
return new StringCollection();
}
private static async Task<bool> ProcessFileDropAsync(System.Windows.Forms.DataObject dataobject)
{
// get the internal ole dataobject
FieldInfo innerDataField = dataobject.GetType().GetField("innerData", BindingFlags.NonPublic | BindingFlags.Instance);
var oledataobject = (System.Windows.Forms.IDataObject)innerDataField.GetValue(dataobject);
var type = oledataobject.GetType();
if (type.Name == "OleConverter")
{
// get the COM-object from the OleConverter
FieldInfo innerDataField2 = type.GetField("innerData", BindingFlags.NonPublic | BindingFlags.Instance);
var item = innerDataField2.GetValue(oledataobject);
var asyncitem = item as IDataObjectAsyncCapability;
if (asyncitem != null)
{
var isasync = 0;
asyncitem.GetAsyncMode(out isasync);
if (isasync != 0)
{
var task = Task.Run(() =>
{
asyncitem.StartOperation(null);
// calling GetData after StartOperation will trigger the download in Chrome
// subsequent calls to GetData return cached data
// files are downloaded to something like c:\temp\chrome_drag1234_123456789\yourfilename.here
var result = dataobject.GetData("FileDrop");
asyncitem.EndOperation(0, null, 1); // DROPEFFECT_COPY = 1
});
await task;
return true;
}
}
}
return false;
}
}
}
从放置处理程序调用它,文件应包含附件的路径:
private async void panel_DragDrop(object sender, DragEventArgs e)
{
var files = await FileDrop.GetFileDrop(e.Data as System.Windows.Forms.DataObject);
foreach (var file in files)
{
Console.WriteLine(file);
}
}