Opções de Área de Transferência

Uma janela deve usar a área de transferência ao cortar, copiar ou colar dados. Uma janela posiciona dados na área de transferência em operações para recortar e copiar e recupera dados da área de transferência em operações para colar. As seções a seguir descrevem essas operações e os problemas relacionados.

Para posicionar dados na área de transferência ou recuperá-los dela, uma janela deve abrir primeiro a área de transferência usando a função OpenClipboard. Apenas uma janela pode ter a área de transferência aberta por vez. Para descobrir qual janela tem a área de transferência aberta, chame a função GetOpenClipboardWindow. Quando terminar, a janela deverá fechar a área de transferência chamando a função CloseClipboard.

Os tópicos a seguir são discutidos nesta seção.

Operações para recortar e copiar

Para posicionar informações na área de transferência, uma janela limpa primeiro qualquer conteúdo anterior da área de transferência usando a função EmptyClipboard. Essa função envia a mensagem WM_DESTROYCLIPBOARD para o proprietário anterior da área de transferência, libera recursos associados a dados na área de transferência e atribui a propriedade da área de transferência à janela que tem a área de transferência aberta. Para descobrir qual janela tem a área de transferência, chame a função GetClipboardOwner.

Depois de esvaziar a área de transferência, a janela posiciona os dados na área de transferência no maior número possível de formatos de área de transferência, ordenados do formato mais descritivo para o menos descritivo. Para cada formato, a janela chama a função SetClipboardData, especificando o identificador de formato e um identificador de memória global. O identificador de memória pode ser NULL, indicando que a janela renderiza os dados sob solicitação. Para obter mais informações, confira Renderização atrasada.

Operações para colar

Para recuperar informações de colagem da área de transferência, uma janela determina primeiro o formato da área de transferência a ser recuperado. Normalmente, uma janela enumera os formatos de área de transferência disponíveis usando a função EnumClipboardFormats e usa o primeiro formato que ela reconhece. Esse método seleciona o melhor formato disponível de acordo com a prioridade definida quando os dados foram posicionados na área de transferência.

Como alternativa, uma janela pode usar a função GetPriorityClipboardFormat. Essa função identifica o melhor formato de área de transferência disponível de acordo com uma prioridade especificada. Uma janela que reconhece apenas um formato da área de transferência pode simplesmente determinar se esse formato está disponível usando a função IsClipboardFormatAvailable.

Depois de determinar o formato da área de transferência a ser usado, uma janela chama a função GetClipboardData. Essa função retorna o identificador para um objeto de memória global que contém dados no formato especificado. Uma janela pode bloquear brevemente o objeto de memória para examinar ou copiar os dados. No entanto, uma janela não deve liberar o objeto ou deixá-lo bloqueado por um longo período de tempo.

Propriedade da área de transferência

O proprietário da área de transferência é a janela associada às informações na área de transferência. Uma janela se torna o proprietário da área de transferência quando posiciona dados na área de transferência, especificamente, quando chama a função EmptyClipboard. A janela permanece como proprietária da área de transferência até que seja fechada ou outra janela esvazie a área de transferência.

Quando a área de transferência é esvaziada, o proprietário da área de transferência recebe uma mensagem WM_DESTROYCLIPBOARD. A seguir, estão algumas razões pelas quais uma janela pode processar essa mensagem:

  • A janela atrasou a renderização de um ou mais formatos da área de transferência. Em resposta à mensagem WM_DESTROYCLIPBOARD, a janela pode liberar recursos alocados para renderizar dados mediante solicitação. Para obter mais informações sobre a renderização de dados, consulte Renderização atrasada.
  • A janela posicionou dados na área de transferência em um formato de área de transferência privada. Os dados para formatos privados de área de transferência não são liberados pelo sistema quando a área de transferência é esvaziada. Portanto, o proprietário da área de transferência deve liberar os dados ao receber a mensagem WM_DESTROYCLIPBOARD. Para obter mais informações sobre formatos privados de área de transferência, consulte Formatos da área de transferência.
  • A janela posicionou dados na área de transferência usando o formato de área de transferência CF_OWNERDISPLAY. Em resposta à mensagem WM_DESTROYCLIPBOARD, a janela pode liberar recursos usados para exibir informações na janela do visualizador da área de transferência. Para obter mais informações sobre esse formato alternativo, consulte Formato de exibição do proprietário.

Renderização atrasada

Ao posicionar um formato de área de transferência na área de transferência, uma janela pode atrasar a renderização dos dados nesse formato até que os dados sejam necessários. Para fazer isso, um aplicativo pode especificar NULL para o parâmetro hData da função SetClipboardData. Isso é útil se o aplicativo oferece suporte a vários formatos de área de transferência, sendo que alguns ou todos têm atraso na renderização. Ao passar um identificador NULL, uma janela renderizará formatos complexos de área de transferência somente quando e se forem necessários.

Se uma janela atrasar a renderização de um formato de área de transferência, ela deverá estar preparada para renderizar o formato mediante solicitação enquanto for a proprietária da área de transferência. O sistema envia ao proprietário da área de transferência uma mensagem WM_RENDERFORMAT quando uma solicitação é recebida para um formato específico que não foi renderizado. Ao receber essa mensagem, a janela deve chamar a função SetClipboardData para posicionar um identificador de memória global na área de transferência no formato solicitado.

Um aplicativo não deve abrir a área de transferência antes de chamar SetClipboardData em resposta à mensagem WM_RENDERFORMAT. Não é necessário abrir a área de transferência, e qualquer tentativa de abertura falhará porque a área de transferência está sendo mantida aberta pelo aplicativo que solicitou o formato a ser renderizado.

Se o proprietário da área de transferência estiver prestes a ser destruído e tiver atrasado a renderização de alguns ou todos os formatos da área de transferência, ele receberá a mensagem WM_RENDERALLFORMATS. Ao receber essa mensagem, a janela deve abrir a área de transferência, verificar se ainda é a proprietária da área de transferência com a função GetClipboardOwner e, em seguida, posicionar identificadores de memória válidos na área de transferência para todos os formatos que ela fornece. Isso garante que esses formatos permaneçam disponíveis depois que o proprietário da área de transferência for destruído.

Ao contrário de WM_RENDERFORMAT, um aplicativo que responde a WM_RENDERALLFORMATS deve abrir a área de transferência antes de chamar SetClipboardData para posicionar quaisquer identificadores de memória global na área de transferência.

Todos os formatos de área de transferência que não são renderizados em resposta à mensagem WM_RENDERALLFORMATS ficam indisponíveis para outros aplicativos e não são mais enumerados pelas funções da área de transferência.

Diretrizes de renderização atrasada

A renderização atrasada é um recurso de desempenho, permitindo que um aplicativo evite renderizar dados da área de transferência em um formato que talvez nunca seja solicitado. No entanto, o uso de renderização atrasada envolve as seguintes compensações que devem ser levadas em consideração:

  • O uso de renderização atrasada adiciona alguma complexidade ao aplicativo, exigindo que ele manipule duas mensagens de janela de renderização, conforme descrito acima.
  • Usar renderização atrasada significa que o aplicativo perde a opção de manter a interface do usuário responsiva caso a renderização dos dados leve tempo suficiente para que seja perceptível para o usuário. Com a renderização atrasada, se os dados forem eventualmente necessários, a janela deverá renderizá-los durante o processamento de uma mensagem de janela de renderização, conforme descrito acima. Como resultado, se há demora na renderização dos dados, o aplicativo pode ficar visivelmente sem resposta (travado) enquanto a renderização ocorre, pois nenhuma outra mensagem de janela pode ser processada enquanto a mensagem da janela de renderização está sendo processada. Um aplicativo que não usa renderização atrasada pode, em vez disso, optar por renderizar dados em um thread em segundo plano para manter a resposta da interface do usuário enquanto a renderização ocorre, talvez fornecendo opções de progresso ou cancelamento, que não estão disponíveis ao usar a renderização atrasada.
  • O uso da renderização atrasada adicionará uma pequena quantidade de sobrecarga se os dados forem eventualmente necessários. Ao usar a renderização atrasada, uma janela chama inicialmente a função SetClipboardData com um identificador NULL e, se os dados forem necessários posteriormente, a janela deverá responder a uma mensagem de janela e chamar a função SetClipboardData uma segunda vez com um identificador para os dados renderizados, conforme descrito acima. Como resultado, se os dados forem eventualmente necessários, o uso da renderização atrasada adicionará o custo para processar uma mensagem de janela e chamar a função SetClipboardData uma segunda vez. Esse custo é pequeno, mas não é zero. Se um aplicativo for compatível apenas com um único formato de área de transferência e se os dados forem sempre solicitados, o uso da renderização atrasada só adicionará essa pequena quantidade de sobrecarga (o custo varia de acordo com o hardware; uma estimativa é entre 10 e 100 microssegundos). No entanto, se os dados forem pequenos, a sobrecarga do uso de renderização atrasada poderá exceder o custo para renderizar os dados, o que pode anular o propósito de usar renderização atrasada para melhorar o desempenho. (No teste, para dados que já estão em seu formato final, a sobrecarga de uso da renderização atrasada excedeu consistentemente o custo para copiar os dados para a área de transferência se os dados tivessem 100 KiB ou menos. Esse teste não inclui o custo para renderizar dados, apenas para copiá-los depois que eles são renderizados.)
  • A renderização atrasada é uma vantagem de desempenho líquida se ela economiza mais tempo do que adiciona em sobrecarga. Para determinar a sobrecarga da renderização atrasada, a medição é melhor, mas 10 a 100 microssegundos é uma estimativa. Para calcular a economia no uso da renderização atrasada para cada formato da área de transferência, meça o custo para renderizar os dados nesse formato e determine com que frequência esse formato é eventualmente solicitado (de acordo com as mensagens de janela descritas acima). Multiplique o custo de renderização dos dados pela porcentagem de tempo em que os dados não são eventualmente solicitados (antes que a área de transferência seja esvaziada ou seu conteúdo seja alterado) para determinar a economia de renderização atrasada para cada formato da área de transferência. A renderização atrasada é uma vantagem de desempenho líquida se a economia excede o custo indireto.
  • Como uma diretriz concreta, para aplicativos que são compatíveis apenas com um único formato de área de transferência, como texto, onde os dados não são significativamente caros de renderizar, considere posicionar os dados diretamente na área de transferência se o tamanho dos dados for de 4 KiB ou menos.

Memória e área de transferência

Um objeto de memória que será posicionado na área de transferência deve ser alocado usando a função GlobalAlloc com o sinalizador GMEM_MOVEABLE.

Depois que um objeto de memória é posicionado na área de transferência, a propriedade desse identificador de memória é transferida para o sistema. Quando a área de transferência é esvaziada e o objeto de memória tem um dos seguintes formatos de área de transferência, o sistema libera o objeto de memória chamando a função especificada:

Função para liberar objeto Formato da área de transferência
DeleteMetaFile
CF_DSPENHMETAFILE
CF_DSPMETAFILEPICT
CF_ENHMETAFILE
CF_METAFILEPICT
DeleteObject
CF_BITMAP
CF_DSPBITMAP
CF_PALETTE
GlobalFree
CF_DIB
CF_DIBV5
CF_DSPTEXT
CF_OEMTEXT
CF_TEXT
CF_UNICODETEXT
nenhum
CF_OWNERDISPLAY
Quando a área de transferência é esvaziada de um objeto CF_OWNERDISPLAY, o próprio aplicativo deve liberar o objeto de memória.