PowershellやC#からクリップボード転送時にExternalExceptionが頻発する原因と対策
Windows 10でPowershellやC#でクリップボードにテキストを転送すると、要求されたクリップボード操作に成功しませんでした。
例外が発生することがあります。
例外は発生するもののテキストはクリップボードに転送されています。
この現象はどのような要因が発生原因と考えられるでしょうか。また、原因調査はどのように行うべきでしょうか。
(空のcatchによる例外スキップ以外で)コーディングや設定による解決方法はあるでしょうか。
例外発生のトリガーになりそうな要因は不明です。
クリップボードを占有するアプリケーションや、クリップボード履歴ソフトなどは使用していないはずです。
PCを立ち上げて作業を続けていると突然発生することが多いです。
1度例外が発生すると、それ以降は再起動するまで上記の例外が頻発します。
長時間Excelを立ち上げていると発生率が高くなる気がしますが、統計は取っていません。
本家SOの類似質問の回答を参考に、クリップボードを使用しているプロセス名を調べたところ、Idle
と表示されました。
Powershellサンプルコードと実行時出力
PS C:\> "hoge" | Set-Clipboard
Set-Clipboard : 要求されたクリップボード操作に成功しませんでした。
発生場所 行:1 文字:10
+ "hoge" | Set-Clipboard
+ ~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Set-Clipboard], ExternalException
+ FullyQualifiedErrorId : System.Runtime.InteropServices.ExternalException,Microsoft.PowerShell.Commands.SetClipboardCommand
C#サンプルコード
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace ConsoleApplication7
{
class Program
{
[STAThread]
static void Main(string[] args)
{
var p = GetProcessLockingClipboard();
if (p != null)
{
Console.WriteLine(p.ProcessName); // "Idle"が出力される
}
try
{
Clipboard.SetText("fuga");
}catch(ExternalException e)
{
Console.WriteLine(e);
}
}
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr GetOpenClipboardWindow();
[DllImport("user32.dll", SetLastError = true)]
static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
private static Process GetProcessLockingClipboard()
{
int processId;
GetWindowThreadProcessId(GetOpenClipboardWindow(), out processId);
return Process.GetProcessById(processId);
}
}
}
C#実行時出力
Idle
System.Runtime.InteropServices.ExternalException (0x800401D0): 要求されたクリップボード操作に成功しませ んでした。
場所 System.Windows.Forms.Clipboard.ThrowIfFailed(Int32 hr)
場所 System.Windows.Forms.Clipboard.SetDataObject(Object data, Boolean copy, Int32 retryTimes, Int32 retryDelay)
場所 System.Windows.Forms.Clipboard.SetText(String text, TextDataFormat format)
場所 System.Windows.Forms.Clipboard.SetText(String text)
場所 ConsoleApplication7.Program.Main(String[] args) 場所 c:\users\payaneco\documents\visual studio 2015\Projects\ConsoleApplication7\ConsoleApplication7\Program.cs:行 20