質問: 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 ```
回答: System.Windows.Forms.Clipboard のソースコードを確認してみると、 OleSetClipboardとOleFlushClipboardというOle32.dllのWin32 APIを実行していることがわかります。 これらの関数で戻り値0x800401D0は、CLIPBRD_E_CANT_OPENが対応しています。 これは内部でOpenClipboardの実行に失敗したことを意味します。 この関数が失敗するパターンは、他の誰かがクリップボードを開いているときです。 おそらく他のアプリケーションで、 ちょうどクリップボードの確認をするような処理が発生したのだと思います。 これは意外と頻繁に発生します。 そこで System.Windows.Forms.Clipboard では、 裏でこっそりリトライしています。 SetText()なら100ms間隔で10回リトライしています。 直接 SetDataObject() を呼び出せば、このリトライ回数を調整することができます。 例えばリトライ回数を15回に増やすのであれば、 ``` Clipboard.SetDataObject("fuga", true, 15, 100); ``` というような書き方が可能です。 環境に合わせて色々と調整してみてはいかがでしょうか。