Pergunta

Eu estou usando o código a seguir para copiar texto para a área de transferência:

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

aparentemente de forma aleatória eu recebo "Não é possível prancheta aberta: Acesso negado" erros. Eu estou supondo que esses erros são causados ??por outra aplicação trancando a área de transferência, mas eu nunca parecem estar a fazer qualquer coisa com outras aplicações que deve fazer com que os bloqueios.

Estranhamente meus usuários parecem estar relatando mais dos erros com o Vista e Windows 7 do que com o XP.

Existe uma maneira de verificar se a área de transferência está bloqueada antes de tentar acessá-lo?

Foi útil?

Solução

Este não é um problema Delphi. Porque a área de transferência pode ser bloqueado qualquer momento, mesmo se você verificar, se a área de transferência de momento não está bloqueado, ele pode se tornar bloqueado logo após a verificação.

Você tem duas possibilidades aqui:

  1. Não use a classe prancheta Delphi. Em vez disso usar funções da API crus, onde você tem um controle de pouco mais de grão fino sobre possíveis situações de erro.
  2. Espere seu código falhar, adicionando um manipulador de exceção. Em seguida, adicione algum código de repetição, ou seja, de nova tentativa para definir o texto três vezes, talvez com recuo exponencial, antes de lançar o seu próprio erro.

Eu recomendo a segunda solução, porque seria o mais Delphi-como abordagem e no final vai resultar em um código mais limpo.

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;

Outras dicas

Estranhamente meus usuários parecem ser relatórios mais dos erros com Vista e Windows 7 do que com XP

Isso pode ter a ver com o negócio Vista / Win7 com notificação visualizador de clipboard. Enquanto eles ainda apoiar o XP "cadeia visualizador área de transferência", que envia uma mensagem de notificação que deve ser re-enviados para cada ouvinte, por sua vez (e se um aplicativo não consegue fazer isso, os outros aplicativos não são notificados). Começando com o Vista, os aplicativos são notificados diretamente. E não há nada para impedi-los de tentar aceder a área de transferência de uma só vez.

Analogia: Eu tenho 3 filhos. Eu tenho um bolo. Com regras XP, digo o filho mais velho para ter algum bolo, em seguida, dizer a próxima criança mais velha a ter uma fatia. Ela recebe seu fatia, diz seu irmão, ele recebe o seu, e diz seu irmão, que recebe o seu, e tudo acontece de forma ordenada.
Problema: O filho do meio leva o bolo para o seu quarto, não dizer o mais jovem, e os mais jovens perde-se

.

Com Vista / Windows7, esse sistema ainda existe. Mas os aplicativos mais recentes pode pedir para ser notificado imediatamente, por mim, assim que o bolo chega na cozinha. Eu grito "bolo está pronto!" e todos eles aparecem ao mesmo tempo e tentar pegar algumas. Mas há apenas uma faca de servir, então eles têm que manter a chegar para a faca, não para obtê-lo, e esperando a próxima oportunidade.

Não há nenhuma maneira para verificar se há alguma coisa e, em seguida, dependendo do resultado fazer outra coisa com a expectativa de que não poderia falhar, porque a menos que o cheque e a ação é uma operação atômica, há sempre a possibilidade de que outro processo ou thread faz o mesmo em paralelo.

Isto é, se você tentar abrir a área de transferência, abra um arquivo, criar ou excluir um diretório -. Você deve simplesmente tentar fazê-lo, talvez várias vezes em um loop, e graciosamente lidar com erros

Tente verificar GetClipboardOwner, se não é nulo e não o seu Application.Handle, você não pode abrir para modificá-lo do conteúdo.
E mesmo que parece bom para ir, ele pode não ser a mais quando você realmente fazê-lo.
Então adicione uma tentativa exceto em um loop até que você obtê-lo ou dar-se muito bem (notificar o usuário por exemplo).

Antes de tudo aviso por favor, que isso provavelmente não é um problema na sua aplicação. Outras aplicações bloqueado a área de transferência ou desarrumada a cadeia de notificação e agora a sua aplicação deixa de acessá-lo. Quando eu tenho problemas como este que eu reiniciar o computador e podem deixar ir embora ... bem ... pelo menos até que eu corro novamente o aplicativo que cria o problema.

Este código (não marcado em Delphi) pode ajudá-lo. Não vai resolver o problema é a cadeia de notificação está quebrado (nada exceto a reinicialização do PC nunca vai corrigi-lo), mas ele irá corrigir o problema se um aplicativo está trancando a prancheta por um tempo. Aumentar as MaxRetries se que a aplicação traquinas mantém a área de transferência bloqueado por um tempo muito longo (segundos):

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;

Além disso, pode ser uma boa idéia para deixar cair o 'aumento' e convertê-lo em uma função e usá-lo como este:

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

Eu acho que você está executando o seu aplicativo no Win 8 ou superior.

Basta clicar com o botão direito no arquivo .exe sua App, vá para a aba Compatibilidade e modo de compatibilidade mudança no Windows XP ou versões inferiores. Ele vai trabalhar, garantido!

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top