Как я могу исправить “Не удается открыть буфер обмена:Ошибки ”Отказано в доступе"?

StackOverflow https://stackoverflow.com/questions/1859102

Вопрос

Я использую следующий код для копирования текста в буфер обмена:

  Clipboard.Open;
  try
    Clipboard.AsText := GenerateClipboardText;
  finally
    Clipboard.Close;
  end;

Казалось бы, наугад я получаю "Не удается открыть буфер обмена:Ошибки "Отказано в доступе".Я предполагаю, что эти ошибки вызваны блокировкой буфера обмена другим приложением, но, похоже, я никогда ничего не делаю с другими приложениями, которые должны вызывать блокировки.

Странно, но мои пользователи, похоже, сообщают о большем количестве ошибок в Vista и Windows 7, чем в XP.

Есть ли способ проверить, заблокирован ли буфер обмена, прежде чем пытаться получить к нему доступ?

Это было полезно?

Решение

Это не проблема Delphi.Поскольку буфер обмена может быть заблокирован в любой момент, даже если вы проверите, не заблокирован ли буфер обмена в данный момент, он может быть заблокирован сразу после проверки.

Здесь у вас есть две возможности:

  1. Не используйте класс буфера обмена Delphi.Вместо этого используйте необработанные функции API, где у вас есть немного более детальный контроль над возможными ситуациями с ошибками.
  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;

Другие советы

Как ни странно, мои пользователи, похоже, сообщают о большем количестве ошибок с Vista и Windows 7, чем с XP

Возможно, это связано с тем, как Vista / Win7 обрабатывает уведомления о просмотре буфера обмена.Хотя они по-прежнему поддерживают XP "цепочку просмотра буфера обмена", которая отправляет одно уведомление, которое должно быть повторно отправлено каждому слушателю по очереди (и если одному приложению не удается этого сделать, другие приложения не уведомляются).Начиная с Vista, приложения получают уведомления напрямую.И нет ничего, что удерживало бы их от попыток получить доступ ко всему буферу обмена одновременно.

Аналогия:У меня 3 ребенка.У меня есть торт.Согласно правилам XP, я говорю старшему ребенку съесть немного торта, затем говорю следующему по старшинству ребенку взять кусочек.Она получает свой кусочек, говорит своему брату, он получает свой, и говорит своему брату, который получает свой, и все идет своим чередом.
Проблема:Средний ребенок уносит торт в свою комнату, не говорит об этом младшему, и младший пропускает.

В Vista / Windows7 эта система все еще существует.Но более новые приложения могут запросить немедленное уведомление от меня, как только торт будет доставлен на кухню.Я кричу "торт готов!", и все они появляются одновременно и пытаются урвать немного.Но есть только один сервировочный нож, поэтому им приходится постоянно тянуться к ножу, не имея возможности достать его и ожидая следующей возможности.

Нет способа проверить что-то, а затем, в зависимости от результата, выполнить что-то еще с ожиданием, что это не приведет к сбою, потому что, если проверка и действие не являются одной атомарной операцией, всегда есть вероятность, что другой процесс или поток сделает то же самое параллельно.

Это выполняется независимо от того, пытаетесь ли вы открыть буфер обмена, открыть файл, создать или удалить каталог - вам следует просто попытаться сделать это, возможно, несколько раз за цикл, и корректно обработать ошибки.

Попробуйте проверить GetClipboardOwner , если это не значение null и не ваше приложение.Дескриптор, вы не можете открыть, чтобы изменить его содержимое.
И даже если кажется, что идти хорошо, этого может уже не быть, когда вы на самом деле это сделаете.
Поэтому добавляйте попытку, за исключением цикла, до тех пор, пока вы не получите ее или не откажетесь от нее красиво (например, уведомив пользователя).

Прежде всего, пожалуйста, обратите внимание, что это, вероятно, не является проблемой в вашем приложении.Другие приложения заблокировали буфер обмена или перепутали цепочку уведомлений, и теперь вашему приложению не удается получить к нему доступ.Когда у меня действительно возникают подобные проблемы, я перезагружаю компьютер, и они волшебным образом исчезают...что ж...по крайней мере, до тех пор, пока я снова не запущу приложение, которое создает проблему.

Этот код (не проверенный в Delphi) может вам помочь.Это не решит проблему в том, что цепочка уведомлений нарушена (ничто, кроме перезагрузки КОМПЬЮТЕРА, никогда не исправит это), но это устранит проблему, если приложение на некоторое время блокирует буфер обмена.Увеличьте максимальное количество попыток, если это надоедливое приложение удерживает буфер обмена заблокированным в течение ДЕЙСТВИТЕЛЬНО ДЛИТЕЛЬНОГО времени (секунд):

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.');

Я предполагаю, что вы запускаете свое приложение на Win 8 или выше.

Просто щелкните правой кнопкой мыши на вашем файле App .exe, перейдите на вкладку Совместимость и измените режим совместимости в Windows XP или более низких версиях.Это сработает, гарантирую!

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top