OleDataObject.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Runtime.InteropServices;
  6. using System.Runtime.InteropServices.ComTypes;
  7. using System.Runtime.Serialization.Formatters.Binary;
  8. using System.Text;
  9. using Avalonia.Input.DragDrop;
  10. using Avalonia.Win32.Interop;
  11. using IDataObject = System.Runtime.InteropServices.ComTypes.IDataObject;
  12. namespace Avalonia.Win32
  13. {
  14. class OleDataObject : Avalonia.Input.DragDrop.IDataObject
  15. {
  16. private IDataObject _wrapped;
  17. public OleDataObject(IDataObject wrapped)
  18. {
  19. _wrapped = wrapped;
  20. }
  21. public bool Contains(string dataFormat)
  22. {
  23. return GetDataFormatsCore().Any(df => StringComparer.OrdinalIgnoreCase.Equals(df, dataFormat));
  24. }
  25. public IEnumerable<string> GetDataFormats()
  26. {
  27. return GetDataFormatsCore().Distinct();
  28. }
  29. public string GetText()
  30. {
  31. return GetDataFromOleHGLOBAL(DataFormats.Text, DVASPECT.DVASPECT_CONTENT) as string;
  32. }
  33. public IEnumerable<string> GetFileNames()
  34. {
  35. return GetDataFromOleHGLOBAL(DataFormats.FileNames, DVASPECT.DVASPECT_CONTENT) as IEnumerable<string>;
  36. }
  37. public object Get(string dataFormat)
  38. {
  39. return GetDataFromOleHGLOBAL(dataFormat, DVASPECT.DVASPECT_CONTENT);
  40. }
  41. private object GetDataFromOleHGLOBAL(string format, DVASPECT aspect)
  42. {
  43. FORMATETC formatEtc = new FORMATETC();
  44. formatEtc.cfFormat = ClipboardFormats.GetFormat(format);
  45. formatEtc.dwAspect = aspect;
  46. formatEtc.lindex = -1;
  47. formatEtc.tymed = TYMED.TYMED_HGLOBAL;
  48. if (_wrapped.QueryGetData(ref formatEtc) == 0)
  49. {
  50. _wrapped.GetData(ref formatEtc, out STGMEDIUM medium);
  51. try
  52. {
  53. if (medium.unionmember != IntPtr.Zero && medium.tymed == TYMED.TYMED_HGLOBAL)
  54. {
  55. if (format == DataFormats.Text)
  56. return ReadStringFromHGlobal(medium.unionmember);
  57. if (format == DataFormats.FileNames)
  58. return ReadFileNamesFromHGlobal(medium.unionmember);
  59. byte[] data = ReadBytesFromHGlobal(medium.unionmember);
  60. if (IsSerializedObject(data))
  61. {
  62. using (var ms = new MemoryStream(data))
  63. {
  64. ms.Position = DataObject.SerializedObjectGUID.Length;
  65. BinaryFormatter binaryFormatter = new BinaryFormatter();
  66. return binaryFormatter.Deserialize(ms);
  67. }
  68. }
  69. return data;
  70. }
  71. }
  72. finally
  73. {
  74. UnmanagedMethods.ReleaseStgMedium(ref medium);
  75. }
  76. }
  77. return null;
  78. }
  79. private bool IsSerializedObject(byte[] data)
  80. {
  81. if (data.Length < DataObject.SerializedObjectGUID.Length)
  82. return false;
  83. for (int i = 0; i < DataObject.SerializedObjectGUID.Length; i++)
  84. if (data[i] != DataObject.SerializedObjectGUID[i])
  85. return false;
  86. return true;
  87. }
  88. private static IEnumerable<string> ReadFileNamesFromHGlobal(IntPtr hGlobal)
  89. {
  90. List<string> files = new List<string>();
  91. int fileCount = UnmanagedMethods.DragQueryFile(hGlobal, -1, null, 0);
  92. if (fileCount > 0)
  93. {
  94. for (int i = 0; i < fileCount; i++)
  95. {
  96. int pathLen = UnmanagedMethods.DragQueryFile(hGlobal, i, null, 0);
  97. StringBuilder sb = new StringBuilder(pathLen+1);
  98. if (UnmanagedMethods.DragQueryFile(hGlobal, i, sb, sb.Capacity) == pathLen)
  99. {
  100. files.Add(sb.ToString());
  101. }
  102. }
  103. }
  104. return files;
  105. }
  106. private static string ReadStringFromHGlobal(IntPtr hGlobal)
  107. {
  108. IntPtr ptr = UnmanagedMethods.GlobalLock(hGlobal);
  109. try
  110. {
  111. return Marshal.PtrToStringAuto(ptr);
  112. }
  113. finally
  114. {
  115. UnmanagedMethods.GlobalUnlock(hGlobal);
  116. }
  117. }
  118. private static byte[] ReadBytesFromHGlobal(IntPtr hGlobal)
  119. {
  120. IntPtr source = UnmanagedMethods.GlobalLock(hGlobal);
  121. try
  122. {
  123. int size = (int)UnmanagedMethods.GlobalSize(hGlobal).ToInt64();
  124. byte[] data = new byte[size];
  125. Marshal.Copy(source, data, 0, size);
  126. return data;
  127. }
  128. finally
  129. {
  130. UnmanagedMethods.GlobalUnlock(hGlobal);
  131. }
  132. }
  133. private IEnumerable<string> GetDataFormatsCore()
  134. {
  135. var enumFormat = _wrapped.EnumFormatEtc(DATADIR.DATADIR_GET);
  136. if (enumFormat != null)
  137. {
  138. enumFormat.Reset();
  139. FORMATETC[] formats = new FORMATETC[1];
  140. int[] fetched = { 1 };
  141. while (fetched[0] > 0)
  142. {
  143. fetched[0] = 0;
  144. if (enumFormat.Next(1, formats, fetched) == 0 && fetched[0] > 0)
  145. {
  146. if (formats[0].ptd != IntPtr.Zero)
  147. Marshal.FreeCoTaskMem(formats[0].ptd);
  148. yield return ClipboardFormats.GetFormat(formats[0].cfFormat);
  149. }
  150. }
  151. }
  152. }
  153. }
  154. }