Browse Source

Changes after review

pull/7506/head
Max Katz 5 years ago
parent
commit
5e5b8f6ae7
  1. 16
      src/Avalonia.MicroCom/MicroComProxyBase.cs
  2. 10
      src/Windows/Avalonia.Win32/ClipboardImpl.cs
  3. 44
      src/Windows/Avalonia.Win32/DataObject.cs
  4. 8
      src/Windows/Avalonia.Win32/DragSource.cs
  5. 2
      src/Windows/Avalonia.Win32/OleContext.cs
  6. 10
      src/Windows/Avalonia.Win32/OleDataObject.cs
  7. 22
      src/Windows/Avalonia.Win32/OleDropTarget.cs
  8. 1
      src/Windows/Avalonia.Win32/WindowImpl.cs

16
src/Avalonia.MicroCom/MicroComProxyBase.cs

@ -61,6 +61,22 @@ namespace Avalonia.MicroCom
throw new COMException("QueryInterface failed", rv); throw new COMException("QueryInterface failed", rv);
} }
public bool TryQueryInterface<T>(out T result) where T : IUnknown
{
var guid = MicroComRuntime.GetGuidFor(typeof(T));
var rv = QueryInterface(guid, out var ppv);
if (rv == 0)
{
result = (T)MicroComRuntime.CreateProxyFor(typeof(T), ppv, true);
return true;
}
else
{
result = default;
return false;
}
}
public bool IsDisposed => _nativePointer == IntPtr.Zero; public bool IsDisposed => _nativePointer == IntPtr.Zero;
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)

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

@ -83,7 +83,7 @@ namespace Avalonia.Win32
while (true) while (true)
{ {
var ptr = MicroCom.MicroComRuntime.GetNativeIntPtr<Win32Com.IDataObject>(wrapper, true); var ptr = MicroCom.MicroComRuntime.GetNativeIntPtr<Win32Com.IDataObject>(wrapper);
var hr = UnmanagedMethods.OleSetClipboard(ptr); var hr = UnmanagedMethods.OleSetClipboard(ptr);
if (hr == 0) if (hr == 0)
@ -107,8 +107,8 @@ namespace Avalonia.Win32
if (hr == 0) if (hr == 0)
{ {
using var proxy = MicroCom.MicroComRuntime.CreateProxyFor<Win32Com.IDataObject>(dataObject, false); using var proxy = MicroCom.MicroComRuntime.CreateProxyFor<Win32Com.IDataObject>(dataObject, true);
var wrapper = new OleDataObject(proxy); using var wrapper = new OleDataObject(proxy);
var formats = wrapper.GetDataFormats().ToArray(); var formats = wrapper.GetDataFormats().ToArray();
return formats; return formats;
} }
@ -131,8 +131,8 @@ namespace Avalonia.Win32
if (hr == 0) if (hr == 0)
{ {
using var proxy = MicroCom.MicroComRuntime.CreateProxyFor<Win32Com.IDataObject>(dataObject, false); using var proxy = MicroCom.MicroComRuntime.CreateProxyFor<Win32Com.IDataObject>(dataObject, true);
var wrapper = new OleDataObject(proxy); using var wrapper = new OleDataObject(proxy);
var rv = wrapper.Get(format); var rv = wrapper.Get(format);
return rv; return rv;
} }

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

@ -16,33 +16,43 @@ using IDataObject = Avalonia.Input.IDataObject;
namespace Avalonia.Win32 namespace Avalonia.Win32
{ {
public interface IDisposableDataObject : IDataObject, IDisposable { }
internal static class DataObjectEx internal static class DataObjectEx
{ {
public static unsafe IDataObject GetAvaloniaObject(this Win32Com.IDataObject pDataObj) public static unsafe IDisposableDataObject GetAvaloniaObjectFromCOM(this Win32Com.IDataObject pDataObj)
{ {
switch (pDataObj) if (pDataObj is null)
{
throw new ArgumentNullException(nameof(pDataObj));
}
if (pDataObj is IDisposableDataObject disposableDataObject)
{
return disposableDataObject;
}
// If DataObject was created on the our side (drag'n'drop initiated by Avalonia),
// then pDataObj will implement IAvnDataObject interface as well. So we can safely case it back to DataObject.
if (((MicroComProxyBase)pDataObj).TryQueryInterface<Win32Com.IAvnDataObject>(out var avnInterface))
{
using (avnInterface)
{
var ppv = MicroComRuntime.GetNativeIntPtr(avnInterface);
return MicroComRuntime.GetObjectFromCcw(ppv) as DataObject;
}
}
// Otherwise wrap pDataObj into OleDataObject.
else
{ {
case null: return new OleDataObject(pDataObj);
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 internal class DataObject : IDisposableDataObject, 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 : Win32Com.IEnumFORMATETC, IMicroComShadowContainer class FormatEnumerator : Win32Com.IEnumFORMATETC, IMicroComShadowContainer
{ {
@ -143,7 +153,7 @@ namespace Avalonia.Win32
public DataObject(IDataObject wrapped) public DataObject(IDataObject wrapped)
{ {
if (_wrapped is DataObject) if (_wrapped is DataObject || _wrapped is OleDataObject)
{ {
throw new InvalidOperationException(); throw new InvalidOperationException();
} }

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

@ -15,12 +15,12 @@ namespace Avalonia.Win32
triggerEvent.Pointer.Capture(null); triggerEvent.Pointer.Capture(null);
var dataObject = new DataObject(data); using var dataObject = new DataObject(data);
var src = new OleDragSource(); using var src = new OleDragSource();
var allowed = OleDropTarget.ConvertDropEffect(allowedEffects); var allowed = OleDropTarget.ConvertDropEffect(allowedEffects);
var objPtr = MicroCom.MicroComRuntime.GetNativeIntPtr<Win32Com.IDataObject>(dataObject, true); var objPtr = MicroCom.MicroComRuntime.GetNativeIntPtr<Win32Com.IDataObject>(dataObject);
var srcPtr = MicroCom.MicroComRuntime.GetNativeIntPtr<Win32Com.IDropSource>(src, true); var srcPtr = MicroCom.MicroComRuntime.GetNativeIntPtr<Win32Com.IDropSource>(src);
UnmanagedMethods.DoDragDrop(objPtr, srcPtr, (int)allowed, out var finalEffect); UnmanagedMethods.DoDragDrop(objPtr, srcPtr, (int)allowed, out var finalEffect);
return Task.FromResult(OleDropTarget.ConvertDropEffect((Win32Com.DropEffect)finalEffect)); return Task.FromResult(OleDropTarget.ConvertDropEffect((Win32Com.DropEffect)finalEffect));

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

@ -47,7 +47,7 @@ namespace Avalonia.Win32
return false; return false;
} }
var trgPtr = MicroCom.MicroComRuntime.GetNativeIntPtr(target, false); var trgPtr = MicroCom.MicroComRuntime.GetNativeIntPtr(target);
return UnmanagedMethods.RegisterDragDrop(hwnd.Handle, trgPtr) == UnmanagedMethods.HRESULT.S_OK; return UnmanagedMethods.RegisterDragDrop(hwnd.Handle, trgPtr) == UnmanagedMethods.HRESULT.S_OK;
} }

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

@ -8,17 +8,18 @@ using System.Runtime.InteropServices.ComTypes;
using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Serialization.Formatters.Binary;
using System.Text; using System.Text;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.MicroCom;
using Avalonia.Win32.Interop; using Avalonia.Win32.Interop;
namespace Avalonia.Win32 namespace Avalonia.Win32
{ {
internal class OleDataObject : Avalonia.Input.IDataObject internal class OleDataObject : IDisposableDataObject
{ {
private readonly Win32Com.IDataObject _wrapped; private readonly Win32Com.IDataObject _wrapped;
public OleDataObject(Win32Com.IDataObject wrapped) public OleDataObject(Win32Com.IDataObject wrapped)
{ {
_wrapped = wrapped; _wrapped = wrapped.CloneReference();
} }
public bool Contains(string dataFormat) public bool Contains(string dataFormat)
@ -183,5 +184,10 @@ namespace Avalonia.Win32
} }
return formatsList; return formatsList;
} }
public void Dispose()
{
_wrapped.Dispose();
}
} }
} }

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

@ -3,7 +3,6 @@ using Avalonia.Input.Raw;
using Avalonia.MicroCom; using Avalonia.MicroCom;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Win32.Interop; using Avalonia.Win32.Interop;
using IDataObject = Avalonia.Input.IDataObject;
using DropEffect = Avalonia.Win32.Win32Com.DropEffect; using DropEffect = Avalonia.Win32.Win32Com.DropEffect;
namespace Avalonia.Win32 namespace Avalonia.Win32
@ -14,7 +13,7 @@ namespace Avalonia.Win32
private readonly ITopLevelImpl _tl; private readonly ITopLevelImpl _tl;
private readonly IDragDropDevice _dragDevice; private readonly IDragDropDevice _dragDevice;
private IDataObject _currentDrag = null; private IDisposableDataObject _currentDrag = null;
public MicroComShadow Shadow { get; set; } public MicroComShadow Shadow { get; set; }
@ -77,7 +76,12 @@ namespace Avalonia.Win32
*pdwEffect= (int)DropEffect.None; *pdwEffect= (int)DropEffect.None;
} }
_currentDrag = pDataObj.GetAvaloniaObject(); var newDrag = pDataObj.GetAvaloniaObjectFromCOM();
if (_currentDrag != newDrag)
{
_currentDrag?.Dispose();
_currentDrag = newDrag;
}
var args = new RawDragEvent( var args = new RawDragEvent(
_dragDevice, _dragDevice,
@ -85,7 +89,7 @@ namespace Avalonia.Win32
_target, _target,
GetDragLocation(pt), GetDragLocation(pt),
_currentDrag, _currentDrag,
ConvertDropEffect((*pdwEffect)), ConvertDropEffect(*pdwEffect),
ConvertKeyState(grfKeyState) ConvertKeyState(grfKeyState)
); );
dispatch(args); dispatch(args);
@ -129,6 +133,7 @@ namespace Avalonia.Win32
} }
finally finally
{ {
_currentDrag?.Dispose();
_currentDrag = null; _currentDrag = null;
} }
} }
@ -143,7 +148,12 @@ namespace Avalonia.Win32
*pdwEffect = (int)DropEffect.None; *pdwEffect = (int)DropEffect.None;
} }
_currentDrag = pDataObj.GetAvaloniaObject(); var newDrag = pDataObj.GetAvaloniaObjectFromCOM();
if (_currentDrag != newDrag)
{
_currentDrag?.Dispose();
_currentDrag = newDrag;
}
var args = new RawDragEvent( var args = new RawDragEvent(
_dragDevice, _dragDevice,
@ -159,6 +169,7 @@ namespace Avalonia.Win32
} }
finally finally
{ {
_currentDrag?.Dispose();
_currentDrag = null; _currentDrag = null;
} }
} }
@ -171,6 +182,7 @@ namespace Avalonia.Win32
public void Dispose() public void Dispose()
{ {
_currentDrag?.Dispose();
} }
public void OnReferencedFromNative() public void OnReferencedFromNative()

1
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -529,6 +529,7 @@ namespace Avalonia.Win32
if (_dropTarget != null) if (_dropTarget != null)
{ {
OleContext.Current?.UnregisterDragDrop(Handle); OleContext.Current?.UnregisterDragDrop(Handle);
_dropTarget.Dispose();
_dropTarget = null; _dropTarget = null;
} }

Loading…
Cancel
Save