次のコードを使用して、テキストをクリップボードにコピーしています。
Clipboard.Open;
try
Clipboard.AsText := GenerateClipboardText;
finally
Clipboard.Close;
end;
一見ランダムに「クリップボードを開けません:アクセスが拒否されました」というエラーが表示されます。これらのエラーは、クリップボードをロックしている他のアプリケーションが原因であると推測していますが、ロックを引き起こすはずの他のアプリケーションで何もしていないようです。
不思議なことに、私のユーザーはXPよりもVistaとWindows7でより多くのエラーを報告しているようです。
クリップボードにアクセスする前に、クリップボードがロックされているかどうかを確認する方法はありますか?
これはDelphiの問題ではありません。クリップボードはいつでもロックできるため、チェックしても、現在ロックされていない場合は、チェック直後にロックされる場合があります。
ここには2つの可能性があります。
2番目のソリューションをお勧めします。これは、よりDelphiに似たアプローチであり、最終的にはよりクリーンなコードになるためです。
while not Success do
try
//Set the clipboard
Success := True;
except
on Exception do
begin
Inc(RetryCount);
if RetryCount < 3 then
Sleep(RetryCount * 100)
else
raise MyException.Create('Cannot set clipboard');
end;
end;
不思議なことに、私のユーザーはXPよりもVistaとWindows7でより多くのエラーを報告しているようです
これは、Vista/Win7がクリップボードビューアの通知を処理する方法に関係している可能性があります。 XP "クリップボードビューアチェーン"を引き続きサポートします。これは、各リスナーに順番に再送信する必要がある1つの通知メッセージを送信します(1つのアプリがこれを実行できない場合、他のアプリはVista以降、アプリは直接通知されます。また、アプリがクリップボードに一度にアクセスしようとするのを妨げるものは何もありません。
アナロジー:私には3人の子供がいます。私はケーキを持っています。 XPのルールで、私は一番上の子供にケーキを持って、次に一番上の子供にスライスを持ってもらうように言います。彼女はスライスを手に入れ、兄に言い、彼は彼を手に入れ、そして彼に言います彼を手に入れる兄弟、そしてすべてが整然と進んでいます。
問題:真ん中の子供がケーキを自分の部屋に持って行き、末っ子に言わず、末っ子は逃します。
Vista/Windows7では、そのシステムはまだ存在しています。ただし、新しいアプリでは、ケーキがキッチンに到着したらすぐに通知をリクエストできます。 「ケーキの準備ができました!」と叫びます。そしてそれらはすべて同時に現れ、いくつかをつかもうとします。しかし、サービングナイフは1つしかないため、ナイフを手に入れず、次の機会を待つ必要があります。
GetClipboardOwnerを確認してみてください。nullでもApplication.Handleでもない場合は、開くことでコンテンツを変更することはできません。
そして、行っても良さそうだとしても、実際にやってみるともうそうではないかもしれません。
[。
まず第一に、これはおそらくあなたのアプリケーションでは問題ではないことに注意してください。他のアプリケーションがクリップボードをロックしたか、通知チェーンを台無しにしたため、アプリケーションがクリップボードにアクセスできなくなりました。このような問題が発生した場合は、コンピューターを再起動すると、魔法のように消えてしまいます...まあ...少なくとも、問題を引き起こしているアプリケーションを再度実行するまでは。
このコード(Delphiではチェックされていません)が役立つ場合があります。通知チェーンが壊れているという問題は修正されませんが(PCを再起動する以外は修正されません)、アプリケーションがクリップボードをしばらくロックしている場合は問題が修正されます。その厄介なアプリケーションがクリップボードを本当に長い時間(秒)ロックしたままにする場合は、MaxRetriesを増やします。
procedure Str2Clipboard(CONST Str: string; iDelayMs: integer);
CONST
MaxRetries= 5;
VAR RetryCount: Integer;
begin
RetryCount:= 0;
for RetryCount:= 1 to MaxRetries DO
TRY
inc(RetryCount);
Clipboard.AsText:= Str;
Break;
EXCEPT
on Exception DO
if RetryCount = MaxRetries
then RAISE Exception.Create('Cannot set clipboard')
else Sleep(iDelayMs)
END;
end;
また、「raise」を削除して関数に変換し、次のように使用することをお勧めします。
if not Str2Clipboard
then Log.AddMsg('Dear user, other applications are blocking the clipboard. We have tried. We really did. But it didn''t work. Try again in a few seconds.');
チェックとアクションが1つのアトミック操作でない限り、別のプロセスまたはスレッドが同じことを行う可能性が常にあるため、何かをチェックして、結果に応じて失敗しないことを期待して他のことを行う方法はありません。並行して。
これは、クリップボードを開こうとしても、ファイルを開こうとしても、ディレクトリを作成または削除しようとしても当てはまります。ループ内で数回実行して、エラーを適切に処理する必要があります。
Win8以降でアプリを実行していると思います。
App .exeファイルを右クリックし、[互換性]タブに移動して、Windows XP以下のバージョンで互換モードを変更します。動作することは保証されています!