Como posso corrigir “Não é possível prancheta aberta: Acesso negado” erros?
-
13-09-2019 - |
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?
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:
- 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.
- 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!