Browse Source

Allow Winforms + WPF compatible object drag

pull/1417/head
boombuler 8 years ago
parent
commit
ed4a85fef9
  1. 51
      src/Windows/Avalonia.Win32/DataObject.cs
  2. 26
      src/Windows/Avalonia.Win32/OleDataObject.cs

51
src/Windows/Avalonia.Win32/DataObject.cs

@ -8,11 +8,16 @@ using Avalonia.Controls.DragDrop;
using Avalonia.Win32.Interop;
using IDataObject = Avalonia.Controls.DragDrop.IDataObject;
using IOleDataObject = System.Runtime.InteropServices.ComTypes.IDataObject;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace Avalonia.Win32
{
class DataObject : IDataObject, IOleDataObject
{
// Compatibility with WinForms + WPF...
internal static readonly byte[] SerializedObjectGUID = new Guid("FD9EA796-3B13-4370-A679-56106BB288FB").ToByteArray();
class FormatEnumerator : IEnumFORMATETC
{
private FORMATETC[] _formats;
@ -249,7 +254,51 @@ namespace Avalonia.Win32
return WriteStringToHGlobal(ref hGlobal, Convert.ToString(data));
if (dataFormat == DataFormats.FileNames && data is IEnumerable<string> files)
return WriteFileListToHGlobal(ref hGlobal, files);
return DV_E_TYMED;
if (data is Stream stream)
{
byte[] buffer = new byte[stream.Length - stream.Position];
stream.Read(buffer, 0, buffer.Length);
return WriteBytesToHGlobal(ref hGlobal, buffer);
}
if (data is IEnumerable<byte> bytes)
{
var byteArr = bytes is byte[] ? (byte[])bytes : bytes.ToArray();
return WriteBytesToHGlobal(ref hGlobal, byteArr);
}
return WriteBytesToHGlobal(ref hGlobal, SerializeObject(data));
}
private byte[] SerializeObject(object data)
{
using (var ms = new MemoryStream())
{
ms.Write(SerializedObjectGUID, 0, SerializedObjectGUID.Length);
BinaryFormatter binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize(ms, data);
return ms.ToArray();
}
}
private int WriteBytesToHGlobal(ref IntPtr hGlobal, byte[] data)
{
int required = data.Length;
if (hGlobal == IntPtr.Zero)
hGlobal = UnmanagedMethods.GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, required);
long available = UnmanagedMethods.GlobalSize(hGlobal).ToInt64();
if (required > available)
return STG_E_MEDIUMFULL;
IntPtr ptr = UnmanagedMethods.GlobalLock(hGlobal);
try
{
Marshal.Copy(data, 0, ptr, data.Length);
return unchecked((int)UnmanagedMethods.HRESULT.S_OK);
}
finally
{
UnmanagedMethods.GlobalUnlock(hGlobal);
}
}
private int WriteFileListToHGlobal(ref IntPtr hGlobal, IEnumerable<string> files)

26
src/Windows/Avalonia.Win32/OleDataObject.cs

@ -1,8 +1,10 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using Avalonia.Controls.DragDrop;
using Avalonia.Win32.Interop;
@ -62,7 +64,19 @@ namespace Avalonia.Win32
return ReadStringFromHGlobal(medium.unionmember);
if (format == DataFormats.FileNames)
return ReadFileNamesFromHGlobal(medium.unionmember);
return ReadBytesFromHGlobal(medium.unionmember);
byte[] data = ReadBytesFromHGlobal(medium.unionmember);
if (IsSerializedObject(data))
{
using (var ms = new MemoryStream(data))
{
ms.Position = DataObject.SerializedObjectGUID.Length;
BinaryFormatter binaryFormatter = new BinaryFormatter();
return binaryFormatter.Deserialize(ms);
}
}
return data;
}
}
finally
@ -73,6 +87,16 @@ namespace Avalonia.Win32
return null;
}
private bool IsSerializedObject(byte[] data)
{
if (data.Length < DataObject.SerializedObjectGUID.Length)
return false;
for (int i = 0; i < DataObject.SerializedObjectGUID.Length; i++)
if (data[i] != DataObject.SerializedObjectGUID[i])
return false;
return true;
}
private static IEnumerable<string> ReadFileNamesFromHGlobal(IntPtr hGlobal)
{
List<string> files = new List<string>();

Loading…
Cancel
Save