Bruno Sonnino (sonnino@netmogi.com.br) é consultor e desenvolvedor de sistemas. Tem cinco livros de Delphi publicados pela editora Pearson Brasil e desenvolve utilitários para a revista PCMagazine americana.

Este artigo discute Este artigo usa as seguintes tecnologias
  • Usando a área de transferência do Windows em aplicações .NET;
  • Copiando e colando texto via código;
  • Copiando e colando dados personalizados;
  • Copiando dados em mútiplos formatos;
  • Criando um monitor para a área de transferência.
  • Visual Studio 2005, Windows Forms, C#.

Ao trabalharmos com o Windows, estamos constantemente interagindo com a área de transferência e, muitas vezes, nem percebemos isso: CTRL+C, CTRL+V, CTRL+X, PRTSCR são teclas indispensáveis para o trabalho do dia a dia. Estamos constantemente copiando, cortando e colando texto ou imagens entre aplicações.

Algumas vezes, precisamos implementar esse suporte em nossas próprias aplicações: colar texto ou imagens provenientes de outros programas em nossas janelas. Esse artigo mostrará como manipular a área de transferência do Windows, permitindo transferir textos ou imagens entre o programa e a área de transferência.

Ao final, será mostrado como fazer um programa que monitora a área de transferência, avisando toda vez que houver alguma alteração.

Copiando e colando texto

Para manipular a área de transferência, o .NET Framework possui a classe Clipboard, que tem métodos para troca de dados entre o programa e a área de transferência. Para copiar algum texto para o clipboard, usamos o método SetText, que recebe como parâmetro o texto a ser copiado.

Colar o texto da área de transferência para nossa aplicação é tão simples como copiar: devemos verificar se há texto disponível, com o método ContainsText, e se houver, usamos o GetText para obtê-lo. Para exemplificar esse processo, criaremos um pequeno projeto que cola texto da área de transferência em um TextBox e copia o texto selecionado no controle, de volta para a área de transferência.

No Visual Studio 2005, crie uma aplicação C# para Windows, dando o nome de “TransfTexto”. Na janela principal, inclua um TextBox, alterando sua propriedade Multiline para True. Inclua dois botões, alterando suas propriedades Text para “Copiar” e “Colar”. No evento Click do botão Copiar, inclua o seguinte código:


if (textBox1.SelectedText != "")
{
	Clipboard.SetText(textBox1.SelectedText);
}

Verificamos a existência de texto selecionado, onde se houver, o copiamos para a área de transferência. Para colar o texto existente na área de transferência, usamos o seguinte código no evento Click do botão Colar:


if (Clipboard.ContainsText())
{
     textBox1.Text = Clipboard.GetText();
}

Para copiar ou colar uma imagem, usamos os métodos SetImage, GetImage e ContainsImage, da mesma maneira que trabalhamos até agora.

Copiando e colando dados personalizados

Os métodos para copiar e colar textos e imagens, são suficientes para a maioria das aplicações, porém pode não ser quando precisamos trocar dados especiais. Quando queremos transferir dados que não são padronizados, devemos usar os métodos GetData, SetData e ContainsData, que recebem um parâmetro do tipo string com um nome, que deve ser único.

Por exemplo, transferiremos os dados de uma classe chamada Cliente, que tem três propriedades: Codigo, Nome e Endereco. Crie um novo projeto, chamando-o de “TransfCliente”. Devemos também criar um arquivo para colocar nossa classe. Selecione a opção de menu File>New>File, escolhendo o item Visual C# Class (Figura 1).

Criando uma classe para o projeto

Figura 1: Criando uma classe para o projeto

A classe a ser criada deve ter o atributo Serializable. Adicione o código da Listagem 1 na classe.

Listagem 1: Código da classe Cliente


[Serializable]
public class Cliente
{
	private int cod;
	private string nom;
	private string end;

	public Cliente()
	{
	}

	public Cliente(int ACod, string ANom, string AEnd)
	{
		cod = ACod;
		nom = ANom;
		end = AEnd;
	}

	public int Codigo
	{	
		get { return cod; }
		set { cod = value; }

	}

	public string Nome
	{
		get { return nom; }	
		set { nom = value; }
	}

	public string Endereco
	{
		get { return end; }
		set { end = value; }
	}
}

Salve o arquivo como “Cliente.cs” e adicione-o ao projeto (menu Project>Add Existing Item). Na janela principal, adicione três Labels, três TextBoxes e dois botões, alterando suas propriedades Text para “Copiar” e “Colar”. Você deverá obter algo como a Figura 2.

Janela da aplicação de transferência personalizada

Figura 2: Janela da aplicação de transferência personalizada

Agora, para copiar e colar dados do tipo Cliente, tudo que temos que fazer é usar os métodos GetData e SetData. No manipulador do evento Click do Copiar, adicione o seguinte código:


Clipboard.SetData("FormatoCliente", new Cliente(
Convert.ToInt32(textBox1.Text), textBox2.Text, textBox3.Text));

Estamos enviando os dados de um objeto do tipo Cliente para a área de transferência. Para isso, usamos a string FormatoCliente para referenciá-lo. Quando quisermos colar esses dados, devemos usar a mesma string. Adicione o seguinte código no botão Colar:


if (Clipboard.ContainsData("FormatoCliente"))
{
	Cliente Cli = (Cliente)Clipboard.GetData("FormatoCliente");
	textBox1.Text = Cli.Codigo.ToString();
	textBox2.Text = Cli.Nome;
	textBox3.Text = Cli.Endereco;
}

O código verifica se há algum dado no formato chamado de FormatoCliente com o método ContainsData. Se houver, obtém os dados com o GetData e os copia para os TextBoxes correspondentes.

Copiando dados em múltiplos formatos

Algumas vezes, é necessário fazer a transferência dos dados em mais de um formato, para que fiquem acessíveis a vários tipos de aplicação. Por exemplo, no caso da classe Cliente, podemos deixar também uma cópia dos dados no formato texto, para que possa ser colado no Bloco de Notas, por exemplo.

Para copiar dados de múltiplos formatos, usamos o método SetDataObject, que recebe como parâmetro um objeto de tipo DataObject. Esse objeto tem o método SetData, que permite adicionar dados ao objeto. Para adicionar os dois tipos de dados, devemos chamar o SetData duas vezes e, então, chamar o SetDataObject de Clipboard.

Adicione um novo botão à janela, alterando sua propriedade Text para “Copiar Mult”. Coloque o código da Listagem 2 no evento Click.

Listagem 2: Colando múltiplos formatos


DataObject DataObj = new DataObject();
DataObj.SetData("FormatoCliente",
		new Cliente(Convert.ToInt32(textBox1.Text), textBox2.Text, textBox3.Text));
DataObj.SetData(textBox1.Text + (Char)10 +
textBox2.Text + (Char)10 + textBox3.Text);
Clipboard.SetDataObject(DataObj);

Inicialmente, criamos um objeto do tipo DataObject. Em seguida, adicionamos os dados no formato personalizado e no formato de string, chamando o SetDataObject. Agora, os dados podem ser colados tanto no nosso programa (que recebe os dados personalizados) quanto no Bloco de Notas (que recebe textos).

Criando um monitor da área de transferência

Até aqui, toda manipulação da área de transferência é feita sob demanda, isso é, precisamos clicar em um botão para obter os dados. Há casos em que queremos ser avisados quando há algo disponível na área de transferência, como em programas que guardam os dados que foram colocados lá, para que não se percam.

Uma maneira, é colocar um timer na aplicação e, periodicamente, ler os dados. Isso é ineficiente, pois as mudanças não são tão constantes, permitindo a perda de informações, como no caso de colarmos mais de um dado entre duas leituras. O ideal é criar um monitor da área de transferência, que é avisado quando há uma mudança.

Para que isso aconteça, o programa deve registrar-se como um visualizador da área de transferência, com a função da API do Windows SetClipboardViewer. Essa função coloca a aplicação na lista de visualizadores da área de transferência e retorna o manipulador da janela que vem a seguir na lista de visualizadores. A partir daí, ele passa a receber a mensagem WM_DRAWCLIPBOARD a cada vez que a área de transferência é alterada. Processando essa mensagem, podemos receber os dados à medida que eles são inseridos.

Criaremos um programa que mostra todos os dados em formato texto copiados para a área de transferência em um ListBox. Crie um novo projeto C# Windows, chamando-o de “ClipMonitor”. Inclua no formulário um ListBox, ajustando sua propriedade Dock para Fill.

Coloque o código da Listagem 3 no evento Load do formulário.

Listagem 3: Monitorando a área de transferência


[DllImport("User32.dll")]
public static extern IntPtr SetClipboardViewer(IntPtr hwnd);

private IntPtr proxjanela;

...

private void Form1_Load(object sender, EventArgs e)
{
	proxjanela = SetClipboardViewer(this.Handle);
}

Inicialmente, importamos a função SetClipboardViewer, onde devemos também usar o namespace System.Runtime.InteropServices. No Load, chamamos a função, passando como parâmetro o manipulador da janela atual e guardamos o resultado (a janela seguinte na lista) na variável proxjanela.

Ao final da execução, devemos restaurar a lista de visualização, removendo nossa janela dela. Isso é feito com a função ChangeClipboardChain, que recebe dois parâmetros: a janela que se deseja remover (a janela do programa) e a próxima janela na lista (aquela que é retornada por SetClipboardViewer). Coloque o código da Listagem 4 no evento FormClosing do formulário.

Listagem 4: Restaurando a lista de visualização


[DllImport("user32.dll")]
public static extern bool ChangeClipboardChain(
  IntPtr hwndRemove, IntPtr hwndNext);

private void Form1_FormClosing(object sender,
  FormClosingEventArgs e)
{
	ChangeClipboardChain(this.Handle, proxjanela);
}

O passo seguinte é processar a mensagem WM_DRAWCLIPBOARD. Para fazer isso, devemos sobrecarregar o método WndProc, tratando essa mensagem. Quando ela for enviada, devemos verificar se foi inserido algum texto na área de transferência.

Se positivo, devemos incluir um novo item no ListBox contendo as informações copiadas. Inclua o código da Listagem 5 no formulário.

Listagem 5: Verifica se tem texto na área de transferência e adiciona no ListBox


const int WM_DRAWCLIPBOARD = 0x308;

[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hwnd,
  int wMsg, IntPtr wParam, IntPtr lParam);

protected override void WndProc(ref Message m)
{
	switch (m.Msg)
	{
		case WM_DRAWCLIPBOARD:
			if (Clipboard.ContainsText())
			listBox1.Items.Add(Clipboard.GetText());
			SendMessage(proxjanela, WM_DRAWCLIPBOARD, m.WParam, m.LParam);
		break;

		default:
			base.WndProc(ref m);
		break;
	}
}

Ao receber uma mensagem de mudança da área de trabalho, verificamos se ela contém texto. Se contiver, adicionamos um novo item no Listbox. Em seguida, repassamos a mnsagem para a próxima janela na lista, usando a função SendMessage.

Resta apenas uma alteração a ser feita: quando uma janela desliga-se da lista, o Windows manda a mensagem WM_CHANGECBCHAIN. Devemos processar a mesma em WndProc, alterando a janela seguinte da lista de visualização, se a janela seguinte tiver sido removida.

Se não, devemos passar a mensagem adiante para que a janela seguinte faça a mesma verificação. O código final de WndProc está na Listagem 6. Veja a aplicação em execução na Figura 3.

Listagem 6: Removendo a janela da lista, com um case no switch


const int WM_CHANGECBCHAIN = 0x030D;

protected override void WndProc(ref Message m)
{
	switch (m.Msg)
	{
		case WM_DRAWCLIPBOARD:
		...
		//código a ser adicionado

		case WM_CHANGECBCHAIN:
			if (m.WParam == proxjanela)
			{
				proxjanela = m.LParam;
			}
			else
			{
				SendMessage(proxjanela, WM_DRAWCLIPBOARD,
					    m.WParam, m.LParam);
			}
		break;
		
		default:
			...
	}
}
Visualizador da área de transferência em execução

Figura 3: Visualizador da área de transferência em execução

Conclusão

A classe Clipboard do .NET Framework 2.0 tem métodos que facilitam muito a transferência de dados, tanto padronizados (textos, imagens), como personalizados. Vimos neste artigo como fazer a transferência de dados entre as aplicações, nos formatos padrões, personalizados ou mesmo colocando dados de múltiplos formatos na área de transferência. Ao final, criamos uma aplicação que permite monitorar alterações na área de transferência do Windows.