.NET からクリップボードを設定すると CLIPBRD_E_CANT_OPEN エラーが発生する
質問
次のコードにより、内容が「CLIPBRD_E_CANT_OPEN」の例外が発生する場合があるのはなぜですか:
Clipboard.SetText(str);
これは通常、アプリケーションでクリップボードが初めて使用されるときに発生し、それ以降は発生しません。
解決
実はこれだと思うのですが、 Win32 API の障害.
クリップボードにデータを設定するには、次のことを行う必要があります。 それを開く 初め。クリップボードを開くことができるのは、一度に 1 つのプロセスだけです。したがって、別のプロセスがクリップボードを開いているかどうかを確認するときに、 何らかの理由で, 、開こうとしても失敗します。
たまたま、ターミナル サービスがクリップボードを追跡しているため、古いバージョンの Windows (Vista 以前) では、中身を確認するにはクリップボードを開かなければなりません...それはあなたをブロックすることになります。唯一の解決策は、ターミナル サービスがクリップボードを閉じるまで待って、再試行することです。
ただし、これはターミナル サービスに固有のものではないことを認識することが重要です。それは何にでも起こり得ることです。Win32 でクリップボードを操作すると、大きな競合状態が発生します。ただし、設計上、ユーザー入力に応じてクリップボードを操作することのみが想定されているため、通常はこれで問題は発生しません。
他のヒント
これは、ターミナル サービスのクリップボード (およびその他の可能性のあるもの) のバグ/機能と、クリップボードの .NET 実装が原因で発生します。クリップボードを開くのが遅れるとエラーが発生しますが、通常は数ミリ秒以内に解決します。
解決策は、ループ内で複数回試行し、その間にスリープすることです。
for (int i = 0; i < 10; i++)
{
try
{
Clipboard.SetText(str);
return;
}
catch { }
System.Threading.Thread.Sleep(10);
}
この質問が古いことは承知していますが、問題はまだ存在します。前述したように、この例外はシステム クリップボードが別のプロセスによってブロックされている場合に発生します。残念ながら、Windows のクリップボードをブロックする可能性のある切り取りツール、スクリーンショット用のプログラム、ファイル コピー ツールが多数あります。したがって、使用しようとするたびに例外が発生します Clipboard.SetText(str)
そのようなツールが PC にインストールされている場合。
解決:
決して使用しないでください
Clipboard.SetText(str);
代わりに使用してください
Clipboard.SetDataObject(str);
実際には別の問題が存在する可能性があります。フレームワーク呼び出し (WPF と winform フレーバーの両方) は次のようなものを呼び出します (コードはリフレクターからのものです)。
private static void SetDataInternal(string format, object data)
{
bool flag;
if (IsDataFormatAutoConvert(format))
{
flag = true;
}
else
{
flag = false;
}
IDataObject obj2 = new DataObject();
obj2.SetData(format, data, flag);
SetDataObject(obj2, true);
}
この場合、SetDataObject は常に true で呼び出されることに注意してください。
これにより、内部的には win32 API への 2 つの呼び出しがトリガーされます。1 つはデータを設定し、もう 1 つはアプリからデータをフラッシュして、アプリが閉じた後に使用できるようにします。
クリップボード イベントをリッスンするアプリ (いくつかの Chrome プラグインやダウンロード マネージャー) をいくつか見てきました。最初の呼び出しがヒットするとすぐに、アプリはクリップボードを開いてデータを調べますが、2 番目のフラッシュ呼び出しは失敗します。
直接 win32 API を使用する独自のクリップボード クラスを作成するか、アプリ終了後にデータを保持するために false を指定して setDataObject を直接呼び出すこと以外に、良い解決策が見つかりませんでした。
私はネイティブの Win32 関数を使用して自分のアプリでこの問題を解決しました。OpenClipboard()、CloseClipboard()、および SetClipboardData()。
以下は私が作成したラッパークラスです。誰でもできますか お願いします それを見直して、 それが正しいかどうか教えてください. 。特にマネージ コードが x64 アプリとして実行されている場合 (プロジェクト オプションで Any CPU を使用しています)。 x64 アプリから x86 ライブラリにリンクするとどうなりますか?
ありがとう!
コードは次のとおりです。
public static class ClipboardNative
{
[DllImport("user32.dll")]
private static extern bool OpenClipboard(IntPtr hWndNewOwner);
[DllImport("user32.dll")]
private static extern bool CloseClipboard();
[DllImport("user32.dll")]
private static extern bool SetClipboardData(uint uFormat, IntPtr data);
private const uint CF_UNICODETEXT = 13;
public static bool CopyTextToClipboard(string text)
{
if (!OpenClipboard(IntPtr.Zero)){
return false;
}
var global = Marshal.StringToHGlobalUni(text);
SetClipboardData(CF_UNICODETEXT, global);
CloseClipboard();
//-------------------------------------------
// Not sure, but it looks like we do not need
// to free HGLOBAL because Clipboard is now
// responsible for the copied data. (?)
//
// Otherwise the second call will crash
// the app with a Win32 exception
// inside OpenClipboard() function
//-------------------------------------------
// Marshal.FreeHGlobal(global);
return true;
}
}
これは私の WPF アプリケーションで発生しました。OpenClipboard が失敗しました (HRESULT からの例外:0x800401D0 (CLIPBRD_E_CANT_OPEN))。
私が使う
ApplicationCommands.Copy.Execute(null, myDataGrid);
解決策は、まずクリップボードをクリアすることです
Clipboard.Clear();
ApplicationCommands.Copy.Execute(null, myDataGrid);