I have been trying to implement drag and drop a gmail attachment from chrome into my application.
Its possible to drag the file from the email to the desktop and it create the attachment there so I know this must be possible.
I have been able to get it to read the file name, but when I read FileContents from the data object I get an internet shortcut with a link to the file.
Has anyone got this working before? the code at the moment is hard coded for a .txt file
The sample project can be downloaded from:
https://www.dropbox.com/s/jz4zde0mvgxzn1g/DragDropTest.zip?dl=0
My main DataObjectWrapper class is as follows:
there are too many characters to post all of it but the main method is:
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);
}
I can get quite a bit of data out of it, but just not in the same was as if it was dropped on the desktop:
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;
}
I have read and tried the below links already:
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
https://blogs.msdn.microsoft.com/adamroot/2008/02/19/shell-style-drag-and-drop-in-net-wpf-and-winforms/
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-wpf-and-winforms/
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