Browse Source

MicroCOM Drag'n'Drop and Clipboard

pull/7506/head
Max Katz 5 years ago
parent
commit
ecd6192806
  1. 16
      src/Windows/Avalonia.Win32/ClipboardFormats.cs
  2. 13
      src/Windows/Avalonia.Win32/ClipboardImpl.cs
  3. 257
      src/Windows/Avalonia.Win32/DataObject.cs
  4. 17
      src/Windows/Avalonia.Win32/DragSource.cs
  5. 84
      src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
  6. 4
      src/Windows/Avalonia.Win32/OleContext.cs
  7. 50
      src/Windows/Avalonia.Win32/OleDataObject.cs
  8. 21
      src/Windows/Avalonia.Win32/OleDragSource.cs
  9. 88
      src/Windows/Avalonia.Win32/OleDropTarget.cs
  10. 128
      src/Windows/Avalonia.Win32/Win32Com/win32.idl

16
src/Windows/Avalonia.Win32/ClipboardFormats.cs

@ -14,11 +14,11 @@ namespace Avalonia.Win32
class ClipboardFormat class ClipboardFormat
{ {
public short Format { get; private set; } public ushort Format { get; private set; }
public string Name { get; private set; } public string Name { get; private set; }
public short[] Synthesized { get; private set; } public short[] Synthesized { get; private set; }
public ClipboardFormat(string name, short format, params short[] synthesized) public ClipboardFormat(string name, ushort format, params short[] synthesized)
{ {
Format = format; Format = format;
Name = name; Name = name;
@ -28,12 +28,12 @@ namespace Avalonia.Win32
private static readonly List<ClipboardFormat> FormatList = new List<ClipboardFormat>() private static readonly List<ClipboardFormat> FormatList = new List<ClipboardFormat>()
{ {
new ClipboardFormat(DataFormats.Text, (short)UnmanagedMethods.ClipboardFormat.CF_UNICODETEXT, (short)UnmanagedMethods.ClipboardFormat.CF_TEXT), new ClipboardFormat(DataFormats.Text, (ushort)UnmanagedMethods.ClipboardFormat.CF_UNICODETEXT, (short)UnmanagedMethods.ClipboardFormat.CF_TEXT),
new ClipboardFormat(DataFormats.FileNames, (short)UnmanagedMethods.ClipboardFormat.CF_HDROP), new ClipboardFormat(DataFormats.FileNames, (ushort)UnmanagedMethods.ClipboardFormat.CF_HDROP),
}; };
private static string QueryFormatName(short format) private static string QueryFormatName(ushort format)
{ {
StringBuilder sb = new StringBuilder(MAX_FORMAT_NAME_LENGTH); StringBuilder sb = new StringBuilder(MAX_FORMAT_NAME_LENGTH);
if (UnmanagedMethods.GetClipboardFormatName(format, sb, sb.Capacity) > 0) if (UnmanagedMethods.GetClipboardFormatName(format, sb, sb.Capacity) > 0)
@ -41,7 +41,7 @@ namespace Avalonia.Win32
return null; return null;
} }
public static string GetFormat(short format) public static string GetFormat(ushort format)
{ {
lock (FormatList) lock (FormatList)
{ {
@ -58,7 +58,7 @@ namespace Avalonia.Win32
} }
} }
public static short GetFormat(string format) public static ushort GetFormat(string format)
{ {
lock (FormatList) lock (FormatList)
{ {
@ -68,7 +68,7 @@ namespace Avalonia.Win32
int id = UnmanagedMethods.RegisterClipboardFormat(format); int id = UnmanagedMethods.RegisterClipboardFormat(format);
if (id == 0) if (id == 0)
throw new Win32Exception(); throw new Win32Exception();
pd = new ClipboardFormat(format, (short)id); pd = new ClipboardFormat(format, (ushort)id);
FormatList.Add(pd); FormatList.Add(pd);
} }
return pd.Format; return pd.Format;

13
src/Windows/Avalonia.Win32/ClipboardImpl.cs

@ -78,12 +78,13 @@ namespace Avalonia.Win32
public async Task SetDataObjectAsync(IDataObject data) public async Task SetDataObjectAsync(IDataObject data)
{ {
Dispatcher.UIThread.VerifyAccess(); Dispatcher.UIThread.VerifyAccess();
var wrapper = new DataObject(data); using var wrapper = new DataObject(data);
var i = OleRetryCount; var i = OleRetryCount;
while (true) while (true)
{ {
var hr = UnmanagedMethods.OleSetClipboard(wrapper); var ptr = MicroCom.MicroComRuntime.GetNativeIntPtr<Win32Com.IDataObject>(wrapper, true);
var hr = UnmanagedMethods.OleSetClipboard(ptr);
if (hr == 0) if (hr == 0)
break; break;
@ -106,9 +107,9 @@ namespace Avalonia.Win32
if (hr == 0) if (hr == 0)
{ {
var wrapper = new OleDataObject(dataObject); using var proxy = MicroCom.MicroComRuntime.CreateProxyFor<Win32Com.IDataObject>(dataObject, false);
var wrapper = new OleDataObject(proxy);
var formats = wrapper.GetDataFormats().ToArray(); var formats = wrapper.GetDataFormats().ToArray();
Marshal.ReleaseComObject(dataObject);
return formats; return formats;
} }
@ -130,9 +131,9 @@ namespace Avalonia.Win32
if (hr == 0) if (hr == 0)
{ {
var wrapper = new OleDataObject(dataObject); using var proxy = MicroCom.MicroComRuntime.CreateProxyFor<Win32Com.IDataObject>(dataObject, false);
var wrapper = new OleDataObject(proxy);
var rv = wrapper.Get(format); var rv = wrapper.Get(format);
Marshal.ReleaseComObject(dataObject);
return rv; return rv;
} }

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

@ -8,22 +8,50 @@ using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes; using System.Runtime.InteropServices.ComTypes;
using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Serialization.Formatters.Binary;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.MicroCom;
using Avalonia.Win32.Interop; using Avalonia.Win32.Interop;
using FORMATETC = Avalonia.Win32.Interop.FORMATETC;
using IDataObject = Avalonia.Input.IDataObject; using IDataObject = Avalonia.Input.IDataObject;
namespace Avalonia.Win32 namespace Avalonia.Win32
{ {
class DataObject : IDataObject, IOleDataObject internal static class DataObjectEx
{
public static unsafe IDataObject GetAvaloniaObject(this Win32Com.IDataObject pDataObj)
{
switch (pDataObj)
{
case null:
throw new ArgumentNullException(nameof(pDataObj));
case DataObject avnObj:
return avnObj;
case OleDataObject oleAvnObj:
return oleAvnObj;
default:
var guid = MicroComRuntime.GetGuidFor(typeof(Win32Com.IAvnDataObject));
var rv = ((MicroComProxyBase)pDataObj).QueryInterface(guid, out var ppv);
return rv == 0
? MicroComRuntime.GetObjectFromCcw(ppv) as DataObject
: new OleDataObject(pDataObj);
}
}
}
internal class DataObject : IDataObject, Win32Com.IAvnDataObject, IMicroComShadowContainer
{ {
// Compatibility with WinForms + WPF... // Compatibility with WinForms + WPF...
internal static readonly byte[] SerializedObjectGUID = new Guid("FD9EA796-3B13-4370-A679-56106BB288FB").ToByteArray(); internal static readonly byte[] SerializedObjectGUID = new Guid("FD9EA796-3B13-4370-A679-56106BB288FB").ToByteArray();
private static Dictionary<IntPtr, IDataObject> _avnDataObject = new Dictionary<IntPtr, IDataObject>();
class FormatEnumerator : IEnumFORMATETC class FormatEnumerator : Win32Com.IEnumFORMATETC, IMicroComShadowContainer
{ {
private FORMATETC[] _formats; private FORMATETC[] _formats;
private int _current; private uint _current;
private FormatEnumerator(FORMATETC[] formats, int current) public MicroComShadow Shadow { get; set; }
private FormatEnumerator(FORMATETC[] formats, uint current)
{ {
_formats = formats; _formats = formats;
_current = current; _current = current;
@ -38,7 +66,7 @@ namespace Avalonia.Win32
private FORMATETC ConvertToFormatEtc(string aFormatName) private FORMATETC ConvertToFormatEtc(string aFormatName)
{ {
FORMATETC result = default(FORMATETC); FORMATETC result = default(FORMATETC);
result.cfFormat = ClipboardFormats.GetFormat(aFormatName); result.cfFormat = (ushort)ClipboardFormats.GetFormat(aFormatName);
result.dwAspect = DVASPECT.DVASPECT_CONTENT; result.dwAspect = DVASPECT.DVASPECT_CONTENT;
result.ptd = IntPtr.Zero; result.ptd = IntPtr.Zero;
result.lindex = -1; result.lindex = -1;
@ -46,59 +74,80 @@ namespace Avalonia.Win32
return result; return result;
} }
public void Clone(out IEnumFORMATETC newEnum) public unsafe uint Next(uint celt, FORMATETC* rgelt, uint* results)
{
newEnum = new FormatEnumerator(_formats, _current);
}
public int Next(int celt, FORMATETC[] rgelt, int[] pceltFetched)
{ {
if (rgelt == null) if (rgelt == null)
return unchecked((int)UnmanagedMethods.HRESULT.E_INVALIDARG); return (uint)UnmanagedMethods.HRESULT.E_INVALIDARG;
int i = 0; uint i = 0;
while (i < celt && _current < _formats.Length) while (i < celt && _current < _formats.Length)
{ {
rgelt[i] = _formats[_current]; rgelt[i] = _formats[_current];
_current++; _current++;
i++; i++;
} }
if (pceltFetched != null)
pceltFetched[0] = i;
if (i != celt) if (i != celt)
return unchecked((int)UnmanagedMethods.HRESULT.S_FALSE); return (uint)UnmanagedMethods.HRESULT.S_FALSE;
return unchecked((int)UnmanagedMethods.HRESULT.S_OK);
// "results" parameter can be NULL if celt is 1.
if (celt != 1 || results != default)
*results = i;
return 0;
} }
public int Reset() public uint Skip(uint celt)
{
_current += Math.Min(celt, int.MaxValue - _current);
if (_current >= _formats.Length)
return (uint)UnmanagedMethods.HRESULT.S_FALSE;
return 0;
}
public void Reset()
{ {
_current = 0; _current = 0;
return unchecked((int)UnmanagedMethods.HRESULT.S_OK);
} }
public int Skip(int celt) public Win32Com.IEnumFORMATETC Clone()
{
return new FormatEnumerator(_formats, _current);
}
public void Dispose()
{
}
public void OnReferencedFromNative()
{
}
public void OnUnreferencedFromNative()
{ {
_current += Math.Min(celt, int.MaxValue - _current);
if (_current >= _formats.Length)
return unchecked((int)UnmanagedMethods.HRESULT.S_FALSE);
return unchecked((int)UnmanagedMethods.HRESULT.S_OK);
} }
} }
private const int DV_E_TYMED = unchecked((int)0x80040069); private const uint DV_E_TYMED = 0x80040069;
private const int DV_E_DVASPECT = unchecked((int)0x8004006B); private const uint DV_E_DVASPECT = 0x8004006B;
private const int DV_E_FORMATETC = unchecked((int)0x80040064); private const uint DV_E_FORMATETC = 0x80040064;
private const int OLE_E_ADVISENOTSUPPORTED = unchecked((int)0x80040003); private const uint OLE_E_ADVISENOTSUPPORTED = 0x80040003;
private const int STG_E_MEDIUMFULL = unchecked((int)0x80030070); private const uint STG_E_MEDIUMFULL = 0x80030070;
private const int GMEM_ZEROINIT = 0x0040; private const int GMEM_ZEROINIT = 0x0040;
private const int GMEM_MOVEABLE = 0x0002; private const int GMEM_MOVEABLE = 0x0002;
IDataObject _wrapped; IDataObject _wrapped;
public MicroComShadow Shadow { get; set; }
public DataObject(IDataObject wrapped) public DataObject(IDataObject wrapped)
{ {
if (_wrapped is DataObject)
{
throw new InvalidOperationException();
}
_wrapped = wrapped; _wrapped = wrapped;
} }
@ -131,123 +180,123 @@ namespace Avalonia.Win32
#region IOleDataObject #region IOleDataObject
int IOleDataObject.DAdvise(ref FORMATETC pFormatetc, ADVF advf, IAdviseSink adviseSink, out int connection) unsafe int Win32Com.IDataObject.DAdvise(FORMATETC* pFormatetc, int advf, void* adviseSink)
{ {
if (_wrapped is IOleDataObject ole) if (_wrapped is Win32Com.IDataObject ole)
return ole.DAdvise(ref pFormatetc, advf, adviseSink, out connection); return ole.DAdvise(pFormatetc, advf, adviseSink);
connection = 0; return 0;
return OLE_E_ADVISENOTSUPPORTED;
} }
void IOleDataObject.DUnadvise(int connection) void Win32Com.IDataObject.DUnadvise(int connection)
{ {
if (_wrapped is IOleDataObject ole) if (_wrapped is Win32Com.IDataObject ole)
ole.DUnadvise(connection); ole.DUnadvise(connection);
Marshal.ThrowExceptionForHR(OLE_E_ADVISENOTSUPPORTED); throw new COMException(nameof(OLE_E_ADVISENOTSUPPORTED), unchecked((int)OLE_E_ADVISENOTSUPPORTED));
} }
int IOleDataObject.EnumDAdvise(out IEnumSTATDATA enumAdvise) unsafe void* Win32Com.IDataObject.EnumDAdvise()
{ {
if (_wrapped is IOleDataObject ole) if (_wrapped is Win32Com.IDataObject ole)
return ole.EnumDAdvise(out enumAdvise); return ole.EnumDAdvise();
enumAdvise = null; return null;
return OLE_E_ADVISENOTSUPPORTED;
} }
IEnumFORMATETC IOleDataObject.EnumFormatEtc(DATADIR direction) Win32Com.IEnumFORMATETC Win32Com.IDataObject.EnumFormatEtc(int direction)
{ {
if (_wrapped is IOleDataObject ole) if (_wrapped is Win32Com.IDataObject ole)
return ole.EnumFormatEtc(direction); return ole.EnumFormatEtc(direction);
if (direction == DATADIR.DATADIR_GET) if ((DATADIR)direction == DATADIR.DATADIR_GET)
return new FormatEnumerator(_wrapped); return new FormatEnumerator(_wrapped);
throw new NotSupportedException(); throw new COMException(nameof(UnmanagedMethods.HRESULT.E_NOTIMPL), unchecked((int)UnmanagedMethods.HRESULT.E_NOTIMPL));
} }
int IOleDataObject.GetCanonicalFormatEtc(ref FORMATETC formatIn, out FORMATETC formatOut) unsafe FORMATETC Win32Com.IDataObject.GetCanonicalFormatEtc(FORMATETC* formatIn)
{ {
if (_wrapped is IOleDataObject ole) if (_wrapped is Win32Com.IDataObject ole)
return ole.GetCanonicalFormatEtc(ref formatIn, out formatOut); return ole.GetCanonicalFormatEtc(formatIn);
formatOut = new FORMATETC(); var formatOut = new FORMATETC();
formatOut.ptd = IntPtr.Zero; formatOut.ptd = IntPtr.Zero;
return unchecked((int)UnmanagedMethods.HRESULT.E_NOTIMPL);
throw new COMException(nameof(UnmanagedMethods.HRESULT.E_NOTIMPL), unchecked((int)UnmanagedMethods.HRESULT.E_NOTIMPL));
} }
void IOleDataObject.GetData(ref FORMATETC format, out STGMEDIUM medium) unsafe uint Win32Com.IDataObject.GetData(FORMATETC* format, Interop.STGMEDIUM* medium)
{ {
if (_wrapped is IOleDataObject ole) if (_wrapped is Win32Com.IDataObject ole)
{ {
ole.GetData(ref format, out medium); return ole.GetData(format, medium);
return;
} }
if(!format.tymed.HasAllFlags(TYMED.TYMED_HGLOBAL))
Marshal.ThrowExceptionForHR(DV_E_TYMED);
if (format.dwAspect != DVASPECT.DVASPECT_CONTENT) if (!format->tymed.HasAllFlags(TYMED.TYMED_HGLOBAL))
Marshal.ThrowExceptionForHR(DV_E_DVASPECT); return DV_E_TYMED;
if (format->dwAspect != DVASPECT.DVASPECT_CONTENT)
return DV_E_DVASPECT;
string fmt = ClipboardFormats.GetFormat(format.cfFormat); string fmt = ClipboardFormats.GetFormat(format->cfFormat);
if (string.IsNullOrEmpty(fmt) || !_wrapped.Contains(fmt)) if (string.IsNullOrEmpty(fmt) || !_wrapped.Contains(fmt))
Marshal.ThrowExceptionForHR(DV_E_FORMATETC); return DV_E_FORMATETC;
medium = default(STGMEDIUM); * medium = default(Interop.STGMEDIUM);
medium.tymed = TYMED.TYMED_HGLOBAL; medium->tymed = TYMED.TYMED_HGLOBAL;
int result = WriteDataToHGlobal(fmt, ref medium.unionmember); return WriteDataToHGlobal(fmt, ref medium->unionmember);
Marshal.ThrowExceptionForHR(result);
} }
void IOleDataObject.GetDataHere(ref FORMATETC format, ref STGMEDIUM medium) unsafe uint Win32Com.IDataObject.GetDataHere(FORMATETC* format, Interop.STGMEDIUM* medium)
{ {
if (_wrapped is IOleDataObject ole) if (_wrapped is Win32Com.IDataObject ole)
{ {
ole.GetDataHere(ref format, ref medium); return ole.GetDataHere(format, medium);
return;
} }
if (medium.tymed != TYMED.TYMED_HGLOBAL || !format.tymed.HasAllFlags(TYMED.TYMED_HGLOBAL)) if (medium->tymed != TYMED.TYMED_HGLOBAL || !format->tymed.HasAllFlags(TYMED.TYMED_HGLOBAL))
Marshal.ThrowExceptionForHR(DV_E_TYMED); return DV_E_TYMED;
if (format.dwAspect != DVASPECT.DVASPECT_CONTENT) if (format->dwAspect != DVASPECT.DVASPECT_CONTENT)
Marshal.ThrowExceptionForHR(DV_E_DVASPECT); return DV_E_DVASPECT;
string fmt = ClipboardFormats.GetFormat(format.cfFormat); string fmt = ClipboardFormats.GetFormat(format->cfFormat);
if (string.IsNullOrEmpty(fmt) || !_wrapped.Contains(fmt)) if (string.IsNullOrEmpty(fmt) || !_wrapped.Contains(fmt))
Marshal.ThrowExceptionForHR(DV_E_FORMATETC); return DV_E_FORMATETC;
if (medium.unionmember == IntPtr.Zero) if (medium->unionmember == IntPtr.Zero)
Marshal.ThrowExceptionForHR(STG_E_MEDIUMFULL); return STG_E_MEDIUMFULL;
int result = WriteDataToHGlobal(fmt, ref medium.unionmember); return WriteDataToHGlobal(fmt, ref medium->unionmember);
Marshal.ThrowExceptionForHR(result);
} }
int IOleDataObject.QueryGetData(ref FORMATETC format) unsafe uint Win32Com.IDataObject.QueryGetData(FORMATETC* format)
{ {
if (_wrapped is IOleDataObject ole) if (_wrapped is Win32Com.IDataObject ole)
return ole.QueryGetData(ref format); {
if (format.dwAspect != DVASPECT.DVASPECT_CONTENT) return ole.QueryGetData(format);
}
if (format->dwAspect != DVASPECT.DVASPECT_CONTENT)
return DV_E_DVASPECT; return DV_E_DVASPECT;
if (!format.tymed.HasAllFlags(TYMED.TYMED_HGLOBAL)) if (!format->tymed.HasAllFlags(TYMED.TYMED_HGLOBAL))
return DV_E_TYMED; return DV_E_TYMED;
string dataFormat = ClipboardFormats.GetFormat(format.cfFormat); var dataFormat = ClipboardFormats.GetFormat(format->cfFormat);
if (!string.IsNullOrEmpty(dataFormat) && _wrapped.Contains(dataFormat))
return unchecked((int)UnmanagedMethods.HRESULT.S_OK); if (string.IsNullOrEmpty(dataFormat) || !_wrapped.Contains(dataFormat))
return DV_E_FORMATETC; return DV_E_FORMATETC;
return 0;
} }
void IOleDataObject.SetData(ref FORMATETC formatIn, ref STGMEDIUM medium, bool release) unsafe uint Win32Com.IDataObject.SetData(FORMATETC* pformatetc, Interop.STGMEDIUM* pmedium, int fRelease)
{ {
if (_wrapped is IOleDataObject ole) if (_wrapped is Win32Com.IDataObject ole)
{ {
ole.SetData(ref formatIn, ref medium, release); return ole.SetData(pformatetc, pmedium, fRelease);
return;
} }
Marshal.ThrowExceptionForHR(unchecked((int)UnmanagedMethods.HRESULT.E_NOTIMPL)); return (uint)UnmanagedMethods.HRESULT.E_NOTIMPL;
} }
private int WriteDataToHGlobal(string dataFormat, ref IntPtr hGlobal) private uint WriteDataToHGlobal(string dataFormat, ref IntPtr hGlobal)
{ {
object data = _wrapped.Get(dataFormat); object data = _wrapped.Get(dataFormat);
if (dataFormat == DataFormats.Text || data is string) if (dataFormat == DataFormats.Text || data is string)
@ -288,7 +337,7 @@ namespace Avalonia.Win32
} }
} }
private unsafe int WriteBytesToHGlobal(ref IntPtr hGlobal, ReadOnlySpan<byte> data) private unsafe uint WriteBytesToHGlobal(ref IntPtr hGlobal, ReadOnlySpan<byte> data)
{ {
int required = data.Length; int required = data.Length;
if (hGlobal == IntPtr.Zero) if (hGlobal == IntPtr.Zero)
@ -312,7 +361,7 @@ namespace Avalonia.Win32
} }
} }
private int WriteFileListToHGlobal(ref IntPtr hGlobal, IEnumerable<string> files) private uint WriteFileListToHGlobal(ref IntPtr hGlobal, IEnumerable<string> files)
{ {
if (!files?.Any() ?? false) if (!files?.Any() ?? false)
return unchecked((int)UnmanagedMethods.HRESULT.S_OK); return unchecked((int)UnmanagedMethods.HRESULT.S_OK);
@ -344,7 +393,7 @@ namespace Avalonia.Win32
} }
} }
private int WriteStringToHGlobal(ref IntPtr hGlobal, string data) private uint WriteStringToHGlobal(ref IntPtr hGlobal, string data)
{ {
int required = (data.Length + 1) * sizeof(char); int required = (data.Length + 1) * sizeof(char);
if (hGlobal == IntPtr.Zero) if (hGlobal == IntPtr.Zero)
@ -367,6 +416,18 @@ namespace Avalonia.Win32
} }
} }
public void Dispose()
{
}
public void OnReferencedFromNative()
{
}
public void OnUnreferencedFromNative()
{
}
#endregion #endregion
} }
} }

17
src/Windows/Avalonia.Win32/DragSource.cs

@ -8,17 +8,22 @@ namespace Avalonia.Win32
{ {
class DragSource : IPlatformDragSource class DragSource : IPlatformDragSource
{ {
public Task<DragDropEffects> DoDragDrop(PointerEventArgs triggerEvent, public unsafe Task<DragDropEffects> DoDragDrop(PointerEventArgs triggerEvent,
IDataObject data, DragDropEffects allowedEffects) IDataObject data, DragDropEffects allowedEffects)
{ {
Dispatcher.UIThread.VerifyAccess(); Dispatcher.UIThread.VerifyAccess();
triggerEvent.Pointer.Capture(null); triggerEvent.Pointer.Capture(null);
OleDragSource src = new OleDragSource();
DataObject dataObject = new DataObject(data); var dataObject = new DataObject(data);
int allowed = (int)OleDropTarget.ConvertDropEffect(allowedEffects); var src = new OleDragSource();
var allowed = OleDropTarget.ConvertDropEffect(allowedEffects);
var objPtr = MicroCom.MicroComRuntime.GetNativeIntPtr<Win32Com.IDataObject>(dataObject, true);
var srcPtr = MicroCom.MicroComRuntime.GetNativeIntPtr<Win32Com.IDropSource>(src, true);
UnmanagedMethods.DoDragDrop(dataObject, src, allowed, out var finalEffect); UnmanagedMethods.DoDragDrop(objPtr, srcPtr, allowed, out var finalEffect);
return Task.FromResult(OleDropTarget.ConvertDropEffect((DropEffect)finalEffect)); return Task.FromResult(OleDropTarget.ConvertDropEffect(finalEffect));
} }
} }
} }

84
src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs

@ -1277,10 +1277,10 @@ namespace Avalonia.Win32.Interop
public static extern IntPtr SetClipboardData(ClipboardFormat uFormat, IntPtr hMem); public static extern IntPtr SetClipboardData(ClipboardFormat uFormat, IntPtr hMem);
[DllImport("ole32.dll", PreserveSig = false)] [DllImport("ole32.dll", PreserveSig = false)]
public static extern int OleGetClipboard(out IOleDataObject dataObject); public static extern int OleGetClipboard(out IntPtr dataObject);
[DllImport("ole32.dll", PreserveSig = true)] [DllImport("ole32.dll", PreserveSig = true)]
public static extern int OleSetClipboard(IOleDataObject dataObject); public static extern int OleSetClipboard(IntPtr dataObject);
[DllImport("kernel32.dll", ExactSpelling = true)] [DllImport("kernel32.dll", ExactSpelling = true)]
public static extern IntPtr GlobalLock(IntPtr handle); public static extern IntPtr GlobalLock(IntPtr handle);
@ -1424,7 +1424,7 @@ namespace Avalonia.Win32.Interop
public static extern IntPtr CopyMemory(IntPtr dest, IntPtr src, UIntPtr count); public static extern IntPtr CopyMemory(IntPtr dest, IntPtr src, UIntPtr count);
[DllImport("ole32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] [DllImport("ole32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern HRESULT RegisterDragDrop(IntPtr hwnd, IDropTarget target); public static extern HRESULT RegisterDragDrop(IntPtr hwnd, IntPtr target);
[DllImport("ole32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] [DllImport("ole32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern HRESULT RevokeDragDrop(IntPtr hwnd); public static extern HRESULT RevokeDragDrop(IntPtr hwnd);
@ -1448,7 +1448,7 @@ namespace Avalonia.Win32.Interop
public static extern int DragQueryFile(IntPtr hDrop, int iFile, StringBuilder lpszFile, int cch); public static extern int DragQueryFile(IntPtr hDrop, int iFile, StringBuilder lpszFile, int cch);
[DllImport("ole32.dll", CharSet = CharSet.Auto, ExactSpelling = true, PreserveSig = false)] [DllImport("ole32.dll", CharSet = CharSet.Auto, ExactSpelling = true, PreserveSig = false)]
internal static extern void DoDragDrop(IOleDataObject dataObject, IDropSource dropSource, int allowedEffects, out int finalEffect); internal static extern void DoDragDrop(IntPtr dataObject, IntPtr dropSource, DropEffect allowedEffects, [Out] out DropEffect finalEffect);
[DllImport("dwmapi.dll")] [DllImport("dwmapi.dll")]
public static extern int DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS margins); public static extern int DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS margins);
@ -2064,64 +2064,6 @@ namespace Avalonia.Win32.Interop
} }
} }
[Flags]
internal enum DropEffect : int
{
None = 0,
Copy = 1,
Move = 2,
Link = 4,
Scroll = -2147483648,
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("00000122-0000-0000-C000-000000000046")]
internal interface IDropTarget
{
[PreserveSig]
UnmanagedMethods.HRESULT DragEnter([MarshalAs(UnmanagedType.Interface)] [In] IOleDataObject pDataObj, [MarshalAs(UnmanagedType.U4)] [In] int grfKeyState, [MarshalAs(UnmanagedType.U8)] [In] long pt, [In] [Out] ref DropEffect pdwEffect);
[PreserveSig]
UnmanagedMethods.HRESULT DragOver([MarshalAs(UnmanagedType.U4)] [In] int grfKeyState, [MarshalAs(UnmanagedType.U8)] [In] long pt, [In] [Out] ref DropEffect pdwEffect);
[PreserveSig]
UnmanagedMethods.HRESULT DragLeave();
[PreserveSig]
UnmanagedMethods.HRESULT Drop([MarshalAs(UnmanagedType.Interface)] [In] IOleDataObject pDataObj, [MarshalAs(UnmanagedType.U4)] [In] int grfKeyState, [MarshalAs(UnmanagedType.U8)] [In] long pt, [In] [Out] ref DropEffect pdwEffect);
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("00000121-0000-0000-C000-000000000046")]
internal interface IDropSource
{
[PreserveSig]
int QueryContinueDrag(int fEscapePressed, [MarshalAs(UnmanagedType.U4)] [In] int grfKeyState);
[PreserveSig]
int GiveFeedback([MarshalAs(UnmanagedType.U4)] [In] int dwEffect);
}
[ComImport]
[Guid("0000010E-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IOleDataObject
{
void GetData([In] ref FORMATETC format, out STGMEDIUM medium);
void GetDataHere([In] ref FORMATETC format, ref STGMEDIUM medium);
[PreserveSig]
int QueryGetData([In] ref FORMATETC format);
[PreserveSig]
int GetCanonicalFormatEtc([In] ref FORMATETC formatIn, out FORMATETC formatOut);
void SetData([In] ref FORMATETC formatIn, [In] ref STGMEDIUM medium, [MarshalAs(UnmanagedType.Bool)] bool release);
IEnumFORMATETC EnumFormatEtc(DATADIR direction);
[PreserveSig]
int DAdvise([In] ref FORMATETC pFormatetc, ADVF advf, IAdviseSink adviseSink, out int connection);
void DUnadvise(int connection);
[PreserveSig]
int EnumDAdvise(out IEnumSTATDATA enumAdvise);
}
[StructLayoutAttribute(LayoutKind.Sequential)] [StructLayoutAttribute(LayoutKind.Sequential)]
internal struct _DROPFILES internal struct _DROPFILES
{ {
@ -2132,6 +2074,24 @@ namespace Avalonia.Win32.Interop
public bool fWide; public bool fWide;
} }
[StructLayoutAttribute(LayoutKind.Sequential)]
internal struct STGMEDIUM
{
public TYMED tymed;
public IntPtr unionmember;
public IntPtr pUnkForRelease;
}
[StructLayoutAttribute(LayoutKind.Sequential)]
internal struct FORMATETC
{
public ushort cfFormat;
public IntPtr ptd;
public DVASPECT dwAspect;
public int lindex;
public TYMED tymed;
}
[Flags] [Flags]
internal enum PixelFormatDescriptorFlags : uint internal enum PixelFormatDescriptorFlags : uint
{ {

4
src/Windows/Avalonia.Win32/OleContext.cs

@ -4,6 +4,7 @@ using System.Threading;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Threading; using Avalonia.Threading;
using Avalonia.Win32.Interop; using Avalonia.Win32.Interop;
using Avalonia.Win32.Win32Com;
namespace Avalonia.Win32 namespace Avalonia.Win32
{ {
@ -46,7 +47,8 @@ namespace Avalonia.Win32
return false; return false;
} }
return UnmanagedMethods.RegisterDragDrop(hwnd.Handle, target) == UnmanagedMethods.HRESULT.S_OK; var trgPtr = MicroCom.MicroComRuntime.GetNativeIntPtr(target, false);
return UnmanagedMethods.RegisterDragDrop(hwnd.Handle, trgPtr) == UnmanagedMethods.HRESULT.S_OK;
} }
internal bool UnregisterDragDrop(IPlatformHandle hwnd) internal bool UnregisterDragDrop(IPlatformHandle hwnd)

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

@ -1,7 +1,6 @@
using System; using System;
using System.Buffers; using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -13,11 +12,11 @@ using Avalonia.Win32.Interop;
namespace Avalonia.Win32 namespace Avalonia.Win32
{ {
class OleDataObject : Avalonia.Input.IDataObject internal class OleDataObject : Avalonia.Input.IDataObject
{ {
private IOleDataObject _wrapped; private readonly Win32Com.IDataObject _wrapped;
public OleDataObject(IOleDataObject wrapped) public OleDataObject(Win32Com.IDataObject wrapped)
{ {
_wrapped = wrapped; _wrapped = wrapped;
} }
@ -34,12 +33,12 @@ namespace Avalonia.Win32
public string GetText() public string GetText()
{ {
return GetDataFromOleHGLOBAL(DataFormats.Text, DVASPECT.DVASPECT_CONTENT) as string; return (string)GetDataFromOleHGLOBAL(DataFormats.Text, DVASPECT.DVASPECT_CONTENT);
} }
public IEnumerable<string> GetFileNames() public IEnumerable<string> GetFileNames()
{ {
return GetDataFromOleHGLOBAL(DataFormats.FileNames, DVASPECT.DVASPECT_CONTENT) as IEnumerable<string>; return (IEnumerable<string>)GetDataFromOleHGLOBAL(DataFormats.FileNames, DVASPECT.DVASPECT_CONTENT);
} }
public object Get(string dataFormat) public object Get(string dataFormat)
@ -47,16 +46,17 @@ namespace Avalonia.Win32
return GetDataFromOleHGLOBAL(dataFormat, DVASPECT.DVASPECT_CONTENT); return GetDataFromOleHGLOBAL(dataFormat, DVASPECT.DVASPECT_CONTENT);
} }
private object GetDataFromOleHGLOBAL(string format, DVASPECT aspect) private unsafe object GetDataFromOleHGLOBAL(string format, DVASPECT aspect)
{ {
FORMATETC formatEtc = new FORMATETC(); var formatEtc = new Interop.FORMATETC();
formatEtc.cfFormat = ClipboardFormats.GetFormat(format); formatEtc.cfFormat = ClipboardFormats.GetFormat(format);
formatEtc.dwAspect = aspect; formatEtc.dwAspect = aspect;
formatEtc.lindex = -1; formatEtc.lindex = -1;
formatEtc.tymed = TYMED.TYMED_HGLOBAL; formatEtc.tymed = TYMED.TYMED_HGLOBAL;
if (_wrapped.QueryGetData(ref formatEtc) == 0) if (_wrapped.QueryGetData(&formatEtc) == 0)
{ {
_wrapped.GetData(ref formatEtc, out STGMEDIUM medium); Interop.STGMEDIUM medium = default;
_ = _wrapped.GetData(&formatEtc, &medium);
try try
{ {
if (medium.unionmember != IntPtr.Zero && medium.tymed == TYMED.TYMED_HGLOBAL) if (medium.unionmember != IntPtr.Zero && medium.tymed == TYMED.TYMED_HGLOBAL)
@ -140,38 +140,48 @@ namespace Avalonia.Win32
} }
} }
private IEnumerable<string> GetDataFormatsCore() private unsafe IEnumerable<string> GetDataFormatsCore()
{ {
var enumFormat = _wrapped.EnumFormatEtc(DATADIR.DATADIR_GET); var formatsList = new List<string>();
var enumFormat = _wrapped.EnumFormatEtc((int)DATADIR.DATADIR_GET);
if (enumFormat != null) if (enumFormat != null)
{ {
enumFormat.Reset(); enumFormat.Reset();
var formats = ArrayPool<FORMATETC>.Shared.Rent(1); var formats = ArrayPool<Interop.FORMATETC>.Shared.Rent(1);
var fetched = ArrayPool<int>.Shared.Rent(1);
try try
{ {
uint fetched = 0;
do do
{ {
fetched[0] = 0; fixed (Interop.FORMATETC* formatsPtr = formats)
if (enumFormat.Next(1, formats, fetched) == 0 && fetched[0] > 0) {
// Read one item at a time.
// When "celt" parameter is 1, "pceltFetched" is ignored.
var res = enumFormat.Next(1, formatsPtr, &fetched);
if (res != 0)
{
break;
}
}
if (fetched > 0)
{ {
if (formats[0].ptd != IntPtr.Zero) if (formats[0].ptd != IntPtr.Zero)
Marshal.FreeCoTaskMem(formats[0].ptd); Marshal.FreeCoTaskMem(formats[0].ptd);
yield return ClipboardFormats.GetFormat(formats[0].cfFormat); formatsList.Add(ClipboardFormats.GetFormat(formats[0].cfFormat));
} }
} }
while (fetched[0] > 0); while (fetched > 0);
} }
finally finally
{ {
ArrayPool<FORMATETC>.Shared.Return(formats); ArrayPool<Interop.FORMATETC>.Shared.Return(formats);
ArrayPool<int>.Shared.Return(fetched);
} }
} }
return formatsList;
} }
} }
} }

21
src/Windows/Avalonia.Win32/OleDragSource.cs

@ -1,9 +1,12 @@
using System.Linq; using System.Linq;
using Avalonia.MicroCom;
using Avalonia.Win32.Interop; using Avalonia.Win32.Interop;
using Avalonia.Win32.Win32Com;
namespace Avalonia.Win32 namespace Avalonia.Win32
{ {
class OleDragSource : IDropSource internal class OleDragSource : IDropSource, IMicroComShadowContainer
{ {
private const int DRAGDROP_S_USEDEFAULTCURSORS = 0x00040102; private const int DRAGDROP_S_USEDEFAULTCURSORS = 0x00040102;
private const int DRAGDROP_S_DROP = 0x00040100; private const int DRAGDROP_S_DROP = 0x00040100;
@ -15,6 +18,8 @@ namespace Avalonia.Win32
(int)UnmanagedMethods.ModifierKeys.MK_RBUTTON (int)UnmanagedMethods.ModifierKeys.MK_RBUTTON
}; };
public MicroComShadow Shadow { get; set; }
public int QueryContinueDrag(int fEscapePressed, int grfKeyState) public int QueryContinueDrag(int fEscapePressed, int grfKeyState)
{ {
if (fEscapePressed != 0) if (fEscapePressed != 0)
@ -30,9 +35,21 @@ namespace Avalonia.Win32
return unchecked((int)UnmanagedMethods.HRESULT.S_OK); return unchecked((int)UnmanagedMethods.HRESULT.S_OK);
} }
public int GiveFeedback(int dwEffect) public int GiveFeedback(DropEffect dwEffect)
{ {
return DRAGDROP_S_USEDEFAULTCURSORS; return DRAGDROP_S_USEDEFAULTCURSORS;
} }
public void Dispose()
{
}
public void OnReferencedFromNative()
{
}
public void OnUnreferencedFromNative()
{
}
} }
} }

88
src/Windows/Avalonia.Win32/OleDropTarget.cs

@ -1,12 +1,14 @@
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Input.Raw; using Avalonia.Input.Raw;
using Avalonia.MicroCom;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Win32.Interop; using Avalonia.Win32.Interop;
using IDataObject = Avalonia.Input.IDataObject; using IDataObject = Avalonia.Input.IDataObject;
using DropEffect = Avalonia.Win32.Win32Com.DropEffect;
namespace Avalonia.Win32 namespace Avalonia.Win32
{ {
internal class OleDropTarget : IDropTarget internal class OleDropTarget : Win32Com.IDropTarget, IMicroComShadowContainer
{ {
private readonly IInputRoot _target; private readonly IInputRoot _target;
private readonly ITopLevelImpl _tl; private readonly ITopLevelImpl _tl;
@ -14,6 +16,8 @@ namespace Avalonia.Win32
private IDataObject _currentDrag = null; private IDataObject _currentDrag = null;
public MicroComShadow Shadow { get; set; }
public OleDropTarget(ITopLevelImpl tl, IInputRoot target) public OleDropTarget(ITopLevelImpl tl, IInputRoot target)
{ {
_dragDevice = AvaloniaLocator.Current.GetService<IDragDropDevice>(); _dragDevice = AvaloniaLocator.Current.GetService<IDragDropDevice>();
@ -65,58 +69,51 @@ namespace Avalonia.Win32
return modifiers; return modifiers;
} }
UnmanagedMethods.HRESULT IDropTarget.DragEnter(IOleDataObject pDataObj, int grfKeyState, long pt, ref DropEffect pdwEffect) unsafe void Win32Com.IDropTarget.DragEnter(Win32Com.IDataObject pDataObj, int grfKeyState, UnmanagedMethods.POINT pt, DropEffect* pdwEffect)
{ {
var dispatch = _tl?.Input; var dispatch = _tl?.Input;
if (dispatch == null) if (dispatch == null)
{ {
pdwEffect = DropEffect.None; *pdwEffect= (int)DropEffect.None;
return UnmanagedMethods.HRESULT.S_OK;
} }
_currentDrag = pDataObj as IDataObject;
if (_currentDrag == null) _currentDrag = pDataObj.GetAvaloniaObject();
_currentDrag = new OleDataObject(pDataObj);
var args = new RawDragEvent( var args = new RawDragEvent(
_dragDevice, _dragDevice,
RawDragEventType.DragEnter, RawDragEventType.DragEnter,
_target, _target,
GetDragLocation(pt), GetDragLocation(pt),
_currentDrag, _currentDrag,
ConvertDropEffect(pdwEffect), ConvertDropEffect((*pdwEffect)),
ConvertKeyState(grfKeyState) ConvertKeyState(grfKeyState)
); );
dispatch(args); dispatch(args);
pdwEffect = ConvertDropEffect(args.Effects); *pdwEffect = ConvertDropEffect(args.Effects);
return UnmanagedMethods.HRESULT.S_OK;
} }
UnmanagedMethods.HRESULT IDropTarget.DragOver(int grfKeyState, long pt, ref DropEffect pdwEffect) unsafe void Win32Com.IDropTarget.DragOver(int grfKeyState, UnmanagedMethods.POINT pt, DropEffect* pdwEffect)
{ {
var dispatch = _tl?.Input; var dispatch = _tl?.Input;
if (dispatch == null) if (dispatch == null)
{ {
pdwEffect = DropEffect.None; *pdwEffect = (int)DropEffect.None;
return UnmanagedMethods.HRESULT.S_OK;
} }
var args = new RawDragEvent( var args = new RawDragEvent(
_dragDevice, _dragDevice,
RawDragEventType.DragOver, RawDragEventType.DragOver,
_target, _target,
GetDragLocation(pt), GetDragLocation(pt),
_currentDrag, _currentDrag,
ConvertDropEffect(pdwEffect), ConvertDropEffect(*pdwEffect),
ConvertKeyState(grfKeyState) ConvertKeyState(grfKeyState)
); );
dispatch(args); dispatch(args);
pdwEffect = ConvertDropEffect(args.Effects); *pdwEffect = ConvertDropEffect(args.Effects);
return UnmanagedMethods.HRESULT.S_OK;
} }
UnmanagedMethods.HRESULT IDropTarget.DragLeave() void Win32Com.IDropTarget.DragLeave()
{ {
try try
{ {
@ -129,7 +126,6 @@ namespace Avalonia.Win32
DragDropEffects.None, DragDropEffects.None,
RawInputModifiers.None RawInputModifiers.None
)); ));
return UnmanagedMethods.HRESULT.S_OK;
} }
finally finally
{ {
@ -137,34 +133,29 @@ namespace Avalonia.Win32
} }
} }
UnmanagedMethods.HRESULT IDropTarget.Drop(IOleDataObject pDataObj, int grfKeyState, long pt, ref DropEffect pdwEffect) unsafe void Win32Com.IDropTarget.Drop(Win32Com.IDataObject pDataObj, int grfKeyState, UnmanagedMethods.POINT pt, DropEffect* pdwEffect)
{ {
try try
{ {
var dispatch = _tl?.Input; var dispatch = _tl?.Input;
if (dispatch == null) if (dispatch == null)
{ {
pdwEffect = DropEffect.None; *pdwEffect = (int)DropEffect.None;
return UnmanagedMethods.HRESULT.S_OK;
} }
_currentDrag = pDataObj as IDataObject; _currentDrag = pDataObj.GetAvaloniaObject();
if (_currentDrag == null)
_currentDrag= new OleDataObject(pDataObj);
var args = new RawDragEvent( var args = new RawDragEvent(
_dragDevice, _dragDevice,
RawDragEventType.Drop, RawDragEventType.Drop,
_target, _target,
GetDragLocation(pt), GetDragLocation(pt),
_currentDrag, _currentDrag,
ConvertDropEffect(pdwEffect), ConvertDropEffect(*pdwEffect),
ConvertKeyState(grfKeyState) ConvertKeyState(grfKeyState)
); );
dispatch(args); dispatch(args);
pdwEffect = ConvertDropEffect(args.Effects); *pdwEffect = ConvertDropEffect(args.Effects);
return UnmanagedMethods.HRESULT.S_OK;
} }
finally finally
{ {
@ -172,13 +163,22 @@ namespace Avalonia.Win32
} }
} }
private Point GetDragLocation(long dragPoint) private Point GetDragLocation(UnmanagedMethods.POINT dragPoint)
{ {
int x = (int)dragPoint; var screenPt = new PixelPoint(dragPoint.X, dragPoint.Y);
int y = (int)(dragPoint >> 32);
var screenPt = new PixelPoint(x, y);
return _target.PointToClient(screenPt); return _target.PointToClient(screenPt);
} }
public void Dispose()
{
}
public void OnReferencedFromNative()
{
}
public void OnUnreferencedFromNative()
{
}
} }
} }

128
src/Windows/Avalonia.Win32/Win32Com/win32.idl

@ -27,6 +27,8 @@
@clr-map REFGUID System.Guid* @clr-map REFGUID System.Guid*
@clr-map REFIID System.Guid* @clr-map REFIID System.Guid*
@clr-map WCHAR System.Char @clr-map WCHAR System.Char
@clr-map STGMEDIUM Avalonia.Win32.Interop.STGMEDIUM
@clr-map FORMATETC Avalonia.Win32.Interop.FORMATETC
[flags] [flags]
enum FILEOPENDIALOGOPTIONS enum FILEOPENDIALOGOPTIONS
@ -53,6 +55,16 @@ enum FILEOPENDIALOGOPTIONS
FOS_DEFAULTNOMINIMODE = 0x20000000 FOS_DEFAULTNOMINIMODE = 0x20000000
} }
[flags]
enum DropEffect
{
None = 0,
Copy = 1,
Move = 2,
Link = 4,
Scroll = -2147483648,
}
[ [
object, object,
uuid(43826d1e-e718-42ee-bc55-a1e261c37bfe), uuid(43826d1e-e718-42ee-bc55-a1e261c37bfe),
@ -189,3 +201,119 @@ interface IFileOpenDialog : IFileDialog
HRESULT GetSelectedItems( HRESULT GetSelectedItems(
[out] IShellItemArray** ppsai); [out] IShellItemArray** ppsai);
} }
[
object,
uuid(00000103-0000-0000-C000-000000000046),
pointer_default(unique)
]
interface IEnumFORMATETC : IUnknown
{
UINT32 Next(
[in] ULONG celt,
[out] FORMATETC* rgelt,
ULONG* pceltFetched);
UINT32 Skip(
[in] ULONG celt);
HRESULT Reset();
HRESULT Clone(
[out] IEnumFORMATETC** ppenum);
}
[
object,
uuid(0000010e-0000-0000-C000-000000000046),
pointer_default(unique)
]
interface IDataObject : IUnknown
{
UINT32 GetData(
[in, unique] FORMATETC* pformatetcIn,
[out] STGMEDIUM* pmedium);
UINT32 GetDataHere(
[in, unique] FORMATETC* pformatetc,
[in] STGMEDIUM* pmedium);
UINT32 QueryGetData(
[in, unique] FORMATETC* pformatetc);
HRESULT GetCanonicalFormatEtc(
[in, unique] FORMATETC* pformatectIn,
[out] FORMATETC* pformatetcOut);
UINT32 SetData(
[in, unique] FORMATETC* pformatetc,
[in, unique] STGMEDIUM* pmedium,
[in] BOOL fRelease);
HRESULT EnumFormatEtc(
[in] DWORD dwDirection,
[out] IEnumFORMATETC** ppenumFormatEtc);
HRESULT DAdvise(
[in] FORMATETC* pformatetc,
[in] DWORD advf,
[in, unique] void* pAdvSink,
[out] DWORD* pdwConnection);
HRESULT DUnadvise(
[in] DWORD dwConnection);
HRESULT EnumDAdvise(
[out] void** ppenumAdvise);
}
[uuid(3d74307e-12be-460a-b098-4dd320eec7d5)]
interface IAvnDataObject : IDataObject
{
}
[
local,
object,
uuid(00000121-0000-0000-C000-000000000046)
]
interface IDropSource : IUnknown
{
INT32 QueryContinueDrag([in] BOOL fEscapePressed, [in] DWORD grfKeyState);
INT32 GiveFeedback([in] DropEffect dwEffect);
}
[
object,
uuid(00000122-0000-0000-C000-000000000046),
pointer_default(unique)
]
interface IDropTarget : IUnknown
{
HRESULT DragEnter
(
[in, unique] IDataObject* pDataObj,
[in] DWORD grfKeyState,
[in] POINT pt,
[in] DropEffect* pdwEffect
);
HRESULT DragOver
(
[in] DWORD grfKeyState,
[in] POINT pt,
[in] DropEffect* pdwEffect
);
HRESULT DragLeave();
HRESULT Drop
(
[in, unique] IDataObject* pDataObj,
[in] DWORD grfKeyState,
[in] POINT pt,
[in] DropEffect* pdwEffect
);
}

Loading…
Cancel
Save