Desenvolvimento - C#

Uso do par de ícones associado ao tipo de arquivo no Sistema Operacional em C#

Neste artigo, exibirei como acessar os ícones associados ao tipo de arquivo no sistema operacional, bem como executar um processo a partir do C#.

por Paulo Henrique dos Santos Monteiro



Como sabemos, o Windows mantém internamente no registry uma associação entre o tipo de arquivo e os aplicativos que são capacitados a editá-lo. Quando associado a um aplicativo, o arquivo normalmente ganha um par de ícones para representá-lo no Explorer, e ao clicar com o mouse ou abri-lo diretamente, o aplicativo é invocado.

Se não associado a nenhum aplicativo, ainda assim o arquivo terá um par de ícones básico, e ao tentar abri-lo o usuário será perguntado de qual aplicativo utilizar para o feito.

Solução

Diante da ocorrência de dois ou mais posts no fórum C# do MSDN, perguntando sobre como utilizar os ícones padrão do sistema operacional para exibir em listboxes ou treeviews, e ainda como disparar um programa a partir do C#, construí um programa que atende aos dois propósitos. Ao selecionar um arquivo, carrega-se internamente em dois imagelists os ícones grande (32x32) e pequeno (16x16), exibindo o arquivo numa listbox (já com o ícone do SO).

Ao executar um duplo clique no item da listbox, o arquivo é aberto com o programa associado ao mesmo no SO.

Parte I - Ler o ícone do S.O.

Para a leitura do ícone associado ao tipo de arquivo no S.O, fazemos uso da API SHGetFileInfo, da Shell32.DLL. Já utilizei outras APIs da Shell32.DLL, como no exemplo de usercontrol para abrir a common dialog de seleção de pastas, no meu artigo sobre UserControls que consta também no SharePedia.

A DLL SHGetFileInfo é uma API é poderosa, e destina-se a obter informações sobre pastas, diretórios, e drives. A API utiliza como valor para input/output uma instancia de SHFILEINFO, uma struct que iremos declarar mais adiante.

DWORD_PTR SHGetFileInfo(      
    LPCTSTR pszPath,
    DWORD dwFileAttributes,
    SHFILEINFO *psfi,
    UINT cbFileInfo,
    UINT uFlags
);

Em sendo a API poderosa, e destinada a obter uma série de detalhes sobre o objeto, de acordo com a combinação de flags no último parâmetro (uiFlags), irei focar apenas no problema que diz respeito ao artigo, e abordar as demais combinações em outros futuros artigos.

A declaração C# para a nossa API fica da seguinte maneira:

// Wrapper para a chamada a SHGetFileInfo.
// Também se podia ter usado a API ExtractAssociatedIcon.
[DllImport("shell32.dll")]
public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, 
uint cbSizeFileInfo, uint uFlags);

Nossa estrutura SHFILEINFO é declarada da seguinte maneira:

	[StructLayout(LayoutKind.Sequential)]
			public struct SHFILEINFO 
		{
			public IntPtr hIcon;
			public IntPtr iIcon;
			public uint dwAttributes;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
			public string szDisplayName;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
			public string szTypeName;
		};

Explicando a declaração, a necessidade de utilizar LayoutKind.Sequential é explicada para poder manter exatamente a ordem física dos atributos no marshalling com a API. Observe [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]. A estrutura original é declarada como:

typedef struct _SHFILEINFO {
    HICON hIcon;
    int iIcon;
    DWORD dwAttributes;
    TCHAR szDisplayName[MAX_PATH];
    TCHAR szTypeName[80];
} SHFILEINFO;

Observe que temos as duas strings com tamanho fixo. É por isso que usamos SizeConst.

As constantes utilizadas para a leitura são respectivamente, SHGFI_ICON, SHGFI_LARGEICON e SHGFI_SMALLICON. A declaração dos seus valores pode ser obtida a partir do include windows.h do C++, mas segue a declaração C# para as mesmas.

	public const uint SHGFI_ICON = 0x100;
	public const uint SHGFI_LARGEICON = 0x0; // "Large icon
	public const uint SHGFI_SMALLICON = 0x1; // "Small icon

A combinação necessária para fazer a leitura dos ícones via SHGetFileInfo é:

	SHGFI_ICON | SHGFI_SMALLICON - para ler o ícone pequeno.
	SHGFI_ICON | SHGFI_LARGEICON - para ler o ícone grande.

Após a leitura, a API carrega o ícone em memória, e disponibiliza o handle para o mesmo no campo hIcon da SHFILEINFO.

Tendo o handle em mãos, podemos simplesmente criar o ícone a partir do método estático Icon.FromHandle.

Na solução, criei uma classe chamada IconInformations, que tem internamente duas imagelists, uma para ícones grandes e outra para ícones pequenos, para aproveitar a facilidade do .NET em manter ImageLists atualizáveis em runtime.

Mantenho também internamente uma Hashtable com as extensões lidas, juntamente com o índice da imagem associada nos imagelists.

O usuário manda para o método AddIcone o caminho completo do arquivo. O método separa a extensão do arquivo, e chama internamente o método GetIcone, que obtém o item da Hashtable interna (se existir) . Se não existir, o método executa a chamada interna ao método estático ObtemIconeArquivo, que se encarrega de fazer a chamada da API SHGetFileInfo, e retorna o ícone lido. Após lidas, as imagens são carregadas nas imagelists internas.

A partir deste momento, podemos utilizar as imagelists em nosso programa, associando respectivamente a LargeImageList e SmallImageList na listview.

Parte II - Executar um arquivo a partir do C#

Executar um outro programa significa executar um novo processo.

Traduzindo para C#, significa disparar (start) um novo processo (process). Esta funcionalidade é provida pelo método estático System.Diagnostics.Process.Start.

Como estamos abordando abrir o arquivo da listview a partir do programa associado a extensão no Sistema Operacional, basta chamar o método passando o nome do arquivo como parâmetro. Para executar um programa, basta colocar o path/nome do programa + extensão.

Conclusão

Neste artigo, exibi como acessar os ícones associados ao tipo de arquivo no sistema operacional, bem como executar um processo a partir do C#.

A API SHGetFileInfo é poderosa, e destina-se a obter diversas informações a respeito de um objeto (drive, pasta, arquivo, diretório). As combinações para leitura da informação são muitas, e abordamos apenas a obtenção de ícones neste artigo. Consulte o MSDN (msdn.microsoft.com) para maiores informações, ou aguarde o meu próximo artigo.

Faça o download do código, clique aqui.

Paulo Henrique dos Santos Monteiro

Paulo Henrique dos Santos Monteiro - Tecnólogo formado pela Faculdade de Tecnologia da Baixada Santista FATEC/BS, com 20 anos de experiência comprovada na área, tendo atuado em praticamente todas as áreas, desde saúde, epidemiologia, até automação bancária, software básico, comércio, indústria, backoffice bancário, jogos, segurança, prestação de serviços e consultoria. Também ministrei aulas de programação, análise e tópicos avançados de programação em escolas de 2º. Grau técnico e cursos particulares.
Iniciou com Basic, Clipper, Assembly e C, passando pelo C++ (em Unix, OS/2, Windows e DOS), e depois desenvolvendo sistemas com Delphi, Visual Basic (conheço desde a obscura versão DOS, e atuo com VB desde o Beta da versão 1), Prolog, Pascal, ASP, Javascript, Java, e com .NET e ASP.Net desde o Beta da primeira versão.
Atua também como DBA, e é grande entusiasta da programação armazenada, em Sybase, Sql Server e Oracle.
Publica dicas e códigos no seu blog,
http://taotecnologia.blogspot.com.