|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Composition;
using System.Runtime.InteropServices;
// Use of System.Windows.Forms over System.Windows is intentional here. S.W.F has logic in its clipboard impl to help
// with common errors.
using System.Windows.Forms;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.CodeAnalysis.Host.Mef;
namespace Microsoft.CodeAnalysis.Editor.StringCopyPaste
{
[ExportWorkspaceService(typeof(IStringCopyPasteService), ServiceLayer.Host), Shared]
internal class WpfStringCopyPasteService : IStringCopyPasteService
{
private const string RoslynFormat = nameof(RoslynFormat);
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public WpfStringCopyPasteService()
{
}
private static string GetFormat(string key)
=> $"{RoslynFormat}-{key}";
public bool TrySetClipboardData(string key, string data)
{
const uint CLIPBRD_E_CANT_OPEN = 0x800401D0;
try
{
var dataObject = Clipboard.GetDataObject();
var copy = new DataObject();
foreach (var format in dataObject.GetFormats())
{
if (dataObject.GetDataPresent(format))
copy.SetData(format, dataObject.GetData(format));
}
copy.SetData(GetFormat(key), data);
// Similar to what WinForms does, except that instead of blocking for up to 1s, we only block for up to 250ms.
// https://github.com/dotnet/winforms/blob/0f76e65878b1a0958175f17c4360b8198f8b36ba/src/System.Windows.Forms/src/System/Windows/Forms/Clipboard.cs#L31
Clipboard.SetDataObject(copy, copy: false, retryTimes: 5, retryDelay: 50);
return true;
}
catch (ExternalException ex) when ((uint)ex.ErrorCode == CLIPBRD_E_CANT_OPEN)
{
// Expected exception. The clipboard is a shared windows resource that can be locked by any other
// process. If we weren't able to acquire it, then just bail out gracefully.
}
catch (Exception ex) when (FatalError.ReportAndCatch(ex, ErrorSeverity.Critical))
{
}
return false;
}
public string? TryGetClipboardData(string key)
{
try
{
var dataObject = Clipboard.GetDataObject();
var format = GetFormat(key);
if (dataObject.GetDataPresent(format))
{
return dataObject.GetData(format) as string;
}
}
catch (Exception ex) when (FatalError.ReportAndCatch(ex, ErrorSeverity.Critical))
{
}
return null;
}
}
}
|