Browse Source

Prevent hangs on win32 in case of clipboard errors.

pull/5103/head
Steven Kirk 6 years ago
parent
commit
286ca73fdd
  1. 37
      src/Windows/Avalonia.Win32/ClipboardImpl.cs

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

@ -12,6 +12,9 @@ namespace Avalonia.Win32
{ {
internal class ClipboardImpl : IClipboard internal class ClipboardImpl : IClipboard
{ {
private const int OleRetryCount = 10;
private const int OleRetryDelay = 100;
private async Task<IDisposable> OpenClipboard() private async Task<IDisposable> OpenClipboard()
{ {
while (!UnmanagedMethods.OpenClipboard(IntPtr.Zero)) while (!UnmanagedMethods.OpenClipboard(IntPtr.Zero))
@ -72,20 +75,32 @@ namespace Avalonia.Win32
{ {
Dispatcher.UIThread.VerifyAccess(); Dispatcher.UIThread.VerifyAccess();
var wrapper = new DataObject(data); var wrapper = new DataObject(data);
var i = OleRetryCount;
while (true) while (true)
{ {
if (UnmanagedMethods.OleSetClipboard(wrapper) == 0) var hr = UnmanagedMethods.OleSetClipboard(wrapper);
if (hr == 0)
break; break;
await Task.Delay(100);
if (--i == 0)
Marshal.ThrowExceptionForHR(hr);
await Task.Delay(OleRetryDelay);
} }
} }
public async Task<string[]> GetFormatsAsync() public async Task<string[]> GetFormatsAsync()
{ {
Dispatcher.UIThread.VerifyAccess(); Dispatcher.UIThread.VerifyAccess();
var i = OleRetryCount;
while (true) while (true)
{ {
if (UnmanagedMethods.OleGetClipboard(out var dataObject) == 0) var hr = UnmanagedMethods.OleGetClipboard(out var dataObject);
if (hr == 0)
{ {
var wrapper = new OleDataObject(dataObject); var wrapper = new OleDataObject(dataObject);
var formats = wrapper.GetDataFormats().ToArray(); var formats = wrapper.GetDataFormats().ToArray();
@ -93,16 +108,23 @@ namespace Avalonia.Win32
return formats; return formats;
} }
await Task.Delay(100); if (--i == 0)
Marshal.ThrowExceptionForHR(hr);
await Task.Delay(OleRetryDelay);
} }
} }
public async Task<object> GetDataAsync(string format) public async Task<object> GetDataAsync(string format)
{ {
Dispatcher.UIThread.VerifyAccess(); Dispatcher.UIThread.VerifyAccess();
var i = OleRetryCount;
while (true) while (true)
{ {
if (UnmanagedMethods.OleGetClipboard(out var dataObject) == 0) var hr = UnmanagedMethods.OleGetClipboard(out var dataObject);
if (hr == 0)
{ {
var wrapper = new OleDataObject(dataObject); var wrapper = new OleDataObject(dataObject);
var rv = wrapper.Get(format); var rv = wrapper.Get(format);
@ -110,7 +132,10 @@ namespace Avalonia.Win32
return rv; return rv;
} }
await Task.Delay(100); if (--i == 0)
Marshal.ThrowExceptionForHR(hr);
await Task.Delay(OleRetryDelay);
} }
} }
} }

Loading…
Cancel
Save