csharpc-sharpdotnetxamlavaloniauicross-platformcross-platform-xamlavaloniaguimulti-platformuser-interfacedotnetcore
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
170 lines
5.7 KiB
170 lines
5.7 KiB
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.Input;
|
|
using Avalonia.Win32.Interop;
|
|
|
|
namespace Avalonia.Win32
|
|
{
|
|
class OleDataObject : Avalonia.Input.IDataObject
|
|
{
|
|
private IOleDataObject _wrapped;
|
|
|
|
public OleDataObject(IOleDataObject wrapped)
|
|
{
|
|
_wrapped = wrapped;
|
|
}
|
|
|
|
public bool Contains(string dataFormat)
|
|
{
|
|
return GetDataFormatsCore().Any(df => StringComparer.OrdinalIgnoreCase.Equals(df, dataFormat));
|
|
}
|
|
|
|
public IEnumerable<string> GetDataFormats()
|
|
{
|
|
return GetDataFormatsCore().Distinct();
|
|
}
|
|
|
|
public string GetText()
|
|
{
|
|
return GetDataFromOleHGLOBAL(DataFormats.Text, DVASPECT.DVASPECT_CONTENT) as string;
|
|
}
|
|
|
|
public IEnumerable<string> GetFileNames()
|
|
{
|
|
return GetDataFromOleHGLOBAL(DataFormats.FileNames, DVASPECT.DVASPECT_CONTENT) as IEnumerable<string>;
|
|
}
|
|
|
|
public object Get(string dataFormat)
|
|
{
|
|
return GetDataFromOleHGLOBAL(dataFormat, DVASPECT.DVASPECT_CONTENT);
|
|
}
|
|
|
|
private object GetDataFromOleHGLOBAL(string format, DVASPECT aspect)
|
|
{
|
|
FORMATETC formatEtc = new FORMATETC();
|
|
formatEtc.cfFormat = ClipboardFormats.GetFormat(format);
|
|
formatEtc.dwAspect = aspect;
|
|
formatEtc.lindex = -1;
|
|
formatEtc.tymed = TYMED.TYMED_HGLOBAL;
|
|
if (_wrapped.QueryGetData(ref formatEtc) == 0)
|
|
{
|
|
_wrapped.GetData(ref formatEtc, out STGMEDIUM medium);
|
|
try
|
|
{
|
|
if (medium.unionmember != IntPtr.Zero && medium.tymed == TYMED.TYMED_HGLOBAL)
|
|
{
|
|
if (format == DataFormats.Text)
|
|
return ReadStringFromHGlobal(medium.unionmember);
|
|
if (format == DataFormats.FileNames)
|
|
return ReadFileNamesFromHGlobal(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
|
|
{
|
|
UnmanagedMethods.ReleaseStgMedium(ref medium);
|
|
}
|
|
}
|
|
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>();
|
|
int fileCount = UnmanagedMethods.DragQueryFile(hGlobal, -1, null, 0);
|
|
if (fileCount > 0)
|
|
{
|
|
for (int i = 0; i < fileCount; i++)
|
|
{
|
|
int pathLen = UnmanagedMethods.DragQueryFile(hGlobal, i, null, 0);
|
|
StringBuilder sb = new StringBuilder(pathLen+1);
|
|
|
|
if (UnmanagedMethods.DragQueryFile(hGlobal, i, sb, sb.Capacity) == pathLen)
|
|
{
|
|
files.Add(sb.ToString());
|
|
}
|
|
}
|
|
}
|
|
return files;
|
|
}
|
|
|
|
private static string ReadStringFromHGlobal(IntPtr hGlobal)
|
|
{
|
|
IntPtr ptr = UnmanagedMethods.GlobalLock(hGlobal);
|
|
try
|
|
{
|
|
return Marshal.PtrToStringAuto(ptr);
|
|
}
|
|
finally
|
|
{
|
|
UnmanagedMethods.GlobalUnlock(hGlobal);
|
|
}
|
|
}
|
|
|
|
private static byte[] ReadBytesFromHGlobal(IntPtr hGlobal)
|
|
{
|
|
IntPtr source = UnmanagedMethods.GlobalLock(hGlobal);
|
|
try
|
|
{
|
|
int size = (int)UnmanagedMethods.GlobalSize(hGlobal).ToInt64();
|
|
byte[] data = new byte[size];
|
|
Marshal.Copy(source, data, 0, size);
|
|
return data;
|
|
}
|
|
finally
|
|
{
|
|
UnmanagedMethods.GlobalUnlock(hGlobal);
|
|
}
|
|
}
|
|
|
|
private IEnumerable<string> GetDataFormatsCore()
|
|
{
|
|
var enumFormat = _wrapped.EnumFormatEtc(DATADIR.DATADIR_GET);
|
|
if (enumFormat != null)
|
|
{
|
|
enumFormat.Reset();
|
|
FORMATETC[] formats = new FORMATETC[1];
|
|
int[] fetched = { 1 };
|
|
while (fetched[0] > 0)
|
|
{
|
|
fetched[0] = 0;
|
|
if (enumFormat.Next(1, formats, fetched) == 0 && fetched[0] > 0)
|
|
{
|
|
if (formats[0].ptd != IntPtr.Zero)
|
|
Marshal.FreeCoTaskMem(formats[0].ptd);
|
|
|
|
yield return ClipboardFormats.GetFormat(formats[0].cfFormat);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|