Descobrindo o DWM (Desktop Window Manager)

Murilo Maciel Curti, Microsoft Corporation

Publicado em: 6 de setembro de 2006
*

Introdução

DWM é a abreviação de Desktop Window Manager, o gerenciador do novo modelo de janelas do Windows Vista. O DWM é construído sobre o núcleo da camada gráfica do WPF (Windows Presentation Foundation) e também é de responsabilidade da equipe de desenvolvimento do WPF.

Um dos recursos mais interessantes e atraentes do Windows Vista é a apresentação do tema Aero, que proporciona um novo nível de interface entre o usuário e o Windows. Integrado por diversos efeitos de transparência e brilho o Aero, deixa a experiência de janelas mais fluente e animada, dando um passo além dos simples efeitos de esmaecimento presentes até o Windows XP.

O Aero é composto de três partes principais que são nitidamente visíveis ao usuário:

Aero Glass - Efeito de semi-transparência para a borda das janelas onde o usuário consegue enxergar de maneira ofuscada o conteúdo que existe atrás da janela que está com o foco. A semi-transparência foi cuidadosamente escolhida ao invés de uma transparência comum, o que faria com que o usuário acabasse perdendo o foco da tarefa atual devido ao conteúdo de outras janelas que seria exibido simultâneamente, assim ele percebe o conteúdo paralelo e não perde o foco no conteúdo principal.

Live Thumbnails - São os thumbnails exibidos ao usuário passar o mouse sobre as tarefas condicionadas na barra de tarefas. O grande detalhe deste recurso é que ele mostra uma miniatura do conteúdo acontecendo na janela original. Literalmente o thumbnail é vivo.

Windows Flip e Windows Flip 3D - Existe muita semelhança entre estes dois novos recusos com o Live Thumbnails e isto não é por acaso como veremos mais adiante no artigo.

O Windows Flip, que é ativado ao usuário pressionar ALT+Tab, exibe miniaturas animadas das aplicações que estão em execução.

O Windows Flip 3D, que é ativado ao pressionar-se as teclas Windows Key+Tab, exibe as aplicações de maneira tridimensional e permite que o usuário escolha qual delas receberá o foco e também com o recurso de miniaturas animadas.

Este recurso de visualização animada das aplicações em execução é possível devido ao novo modelo de janelas do Windows Vista, que passa a ser um Desktop composto e gerenciado pelo DWM.

Início da páginaInício da página

Composição do Desktop

A partir de agora toda a interface gráfica da janelas são gerenciadas pelo DWM. Isto se deve à nova maneira de obtenção e exibição de pixels que o as janelas utilizam no Windows Vista.

Até o Windows XP as aplicações renderizavam as regiões visíveis de suas janelas diretamente no buffer que é enviado para o video (front buffer). Agora as aplicações renderizam sua superfície em um buffer secundário (back buffer), que recebe as imagens das janelas e as diponibiliza para o DWM para que ele componha o Desktop e o exiba no front buffer enquanto o back buffer está novamente sendo preenchido pelas aplicações.

Este modelo com dois buffers é o mesmo utilizado por aplicações baseadas em DirectX e vem apresentando inúmeras vantagens em desempenho e escalabilidade gráfica há algum tempo. Simplificando todo o processo, o desktop do Windows Vista é uma aplicação DirectX que é iniciada e gerenciada pelo DWM.

Com este novo modelo de composição do desktop alguns objetivos antes impossíveis podem ser facilmente alacançados:

Acesso livre ao conteúdo das janelas - Agora como as janelas tem seu conteúdo renderizado em um back buffer, o conteúdo do buffer pode ser utilizado em diversos lugares e de maneiras diferentes sem que haja perda de performance. Este é o recurso que permite os Live Thumbnails e Flips de janelas exibirem a visão real do conteúdo das aplicações em execução.

Aplicações independentes - Até o Windows XP, quando movimentava-se uma janela sobre a superfície de outra, a janela de background não repintava sua região visível de forma satisfatória, provocando uma duplicação de janelas, por causa a mensagem WM_PAINT que a janela recebe para renderizar sua superfície. No vista isto não mais acontece. A mensagem wm_paint não é mais enviada às janelas, e basta que elas estejam disponíveis para o DWM através do back buffer para que ele componha o desktop de maneira satisfatória.

Início da páginaInício da página

Preparando um Winform para suportar os recursos do DWM

Quando desenvolvemos uma aplicação do tipo Windows Application para a Plataforma .Net e a executamos no Windows Vista, apesar de ela suportar os recursos padrões que o DWM oferece para todas as janelas como o contorno translúcido simples, esta aplicação não suporta personalizações mais avançadas nativamente, é necessário que se prepare a classe para que interopere com a API do DWM.

Será apresentado neste artigo a preparação inicial para que um Winform possa ser personalizado com diversos recurso do DWM a fim de caracterizar ainda mais a aplicação como parte do Windows Vista e oferecer uma experiência mais rica ao usuário.

Início da páginaInício da página

A Classe AeroForm

A Classe AeroForm herda as funcionalidades da Classe System.Windows.Forms.Form e recebe todo código necessário para a interoperabilidade com a API do DWM.

Namespaces

Alguns Namespaces são necessários para preparar a classe AeroForm para o DWM:

using System;
using System.Drawing;
using System.Windows.Forms;
using System.ComponentModel;
using System.Runtime.InteropServices;
	

O Namespace mais importante para a interoperabilidades é o System.Runtime.InteropServices, que possibilita a utilização dos métodos da API do Windows para serem efetuadas modificação no comportamento do Winform. Os outros Namespaces serão utilizados para algumas operação em Tempo de Design no Visual Studio.

Início da páginaInício da página

API do DWM

Através do Atributo DllImport, sobre um método marcado como extern é possível acessar funções da dwmapi.dll, que contém todas as funcionalidades necessárias para integração e personalização dos recursos do DWM.

[DllImport("dwmapi.dll")]
 public static extern void DwmIsCompositionEnabled(ref bool IsIt);

[DllImport("dwmapi.dll")]
 public static extern int DwmExtendFrameIntoClientArea(
               IntPtr hWnd,
               ref MARGINS pMarInset
            );
	

As funções necessárias para a preparação do Winform para os recursos do DWM são DwmIsCompositionEnabled e DwmExtendedFrameIntoClientArea.

DwmIsCompositionEnabled

Esta função verifica se a Composição do Desktop está habilitada, abrindo assim o caminho para a utilização dos recursos do DWM. Se a máquina na qual o Windows Vista está instalado não der suporte aos recursos do DWM ou ainda, os mesmos apresentarem-se desabilitados, exceções serão lançadas ao forçar a sua utilização.

DwmExtentedFrameIntoClientArea

Esta função determina a espessura da margem que o DWM deve desenhar no Winform que o está invocando, proporcionando um dos efeitos mais simples que o DWM pode oferecer.

A estrutura MARGINS

Esta estrutura é passada como parâmetro para a função DwmExtendedFrameIntoClientArea com os valores da espessura de cada margem que o Winform receberá.

[StructLayout(LayoutKind.Sequential)]
 public struct MARGINS
 {
    public int Left, Right, Top, Bottom;
 }
	
Início da páginaInício da página

Verificando se a composição está habilitada

Para que se possa utilizar os recursos do DWM é necessário que a composição do desktop esteja habilitada. Para isso no evento Load do AeroForm deve ser invocada a função DwmIsCompositionEnabled da Api do DWM. Para que esta verificação seja sempre efetuada no evento Load é necessário que no construtor da classe exista uma referência para um novo método que responderá automaticamente em qualquer aplicação que herdar o comportamento do AeroForm.

public AeroForm()
{
    this.Load += new EventHandler(AeroForm_Load);
}
	

E dentro do método AeroForm_Load é feita a verificação antes do início da utilização dos recursos do DWM. Caso a composição de desktop esteja desabilitada a aplicação pode exibir um aviso ao usuário e continuar normalmente o seu curso.

Um detalhe importante é que os recursos devem ser utilizados somente em tempo de execução, pois do contrário interferem no Designer do Visual Studio, impossibilitando a visualização em tempo de design do winform que está sendo desenvolvido.

Para resolver este problema é utilizada a propriedade DesignMode da classe Form para verificar em que modo o formulário está sendo utilizado.

void AeroForm_Load(object sender, EventArgs e)
{
    if (!DesignMode)
    {
        IntPtr hWnd = this.Handle;
        bool compositionEnabled = new bool();
        DwmIsCompositionEnabled(ref compositionEnabled);

        if (compositionEnabled)
        {
           //Chamada ao DWM
        }
        else
            MessageBox.Show("A composição do Desktop não está habilitada");
    }
}
	
Início da páginaInício da página

Invocando os recursos do DWM

Com a composição de desktop habilitada e em funcionamento já é possível utilizar os recursos do DWM para extender a apresentação do winform.

if (compositionEnabled)
{
   //Chamada ao DWM
   int result = DwmExtendFrameIntoClientArea(hWnd, ref margins);
}
	

A função DwmExtendFrameIntoClientArea utiliza os valores da estrutura MARGINS para determinar quais serão as espessuras das margens do Aero no AeroForm, caracterizando uma extensão da apresentação do winform ao usuário.

Uma primeira sugestão para o compartilhamento da estrutura com os forms que herdarem o comportamento do AeroForm é disponibilizar uma propriedade do tipo System.Windows.Forms.Padding para que seja possível a especificação das margens em tempo de design.

public Padding Margins
{
    get 
    {
        return new Padding(margins.Left, margins.Top, margins.Right, margins.Bottom);            
    }
    set
    {
        margins.Top = value.Top;
        margins.Right = value.Right;
        margins.Bottom = value.Bottom;
        margins.Left = value.Left;
        if (DesignMode)
            Invalidate();
    }
}
	

Esta propriedade faz a troca de valores entre a estrutura e o formulário que herdou o AeroForm e caso esteja em modo design o form é forçado a processar suas mensagens de design através do método Invalidate para que o recurso de visualização das margens, que será apresentado adiante seja visualizado corretamente no designer do Visual Studio.

Início da páginaInício da página

Tornando as margens visíveis

Com as personalizações atuais o DWM está pronto para na visualização do winform exibir as bordas, porém por padrão o winform não consegue exibí-las.

Isto se deve ao método OnPaint no Windows Vista pintar a área reservada para os controles do usuário com um fundo branco, sobrepondo as margens extendidas do DWM. Para isto é necessário sobrecrever este método atribuindo à região dos controles um fundo especial com a cor preta, que é a cor utlizada pelo tema Aero para o efeito translúcido.

No novo método OnPaint é invocado o mesmo método da classe base para que ele faça todas as operação de desenho necessárias para o winform ser visualizado corretamente e em tempo de execução é pintado um retângulo de cor preta sobre a região que contém os controles, fazendo assim que as bordas que se extendem sobre esta região torne-se visível, pois tudo que for preto sobre a região do Aero torna-se translúcido.

Este problema poderia ser resolvido com a utilização da propriedade TransparencyKey sendo setada para a cor do Background do winform, porém isto ocasionaria em uma janela com funcionamento inadequado, sendo que o mouse clicaria através das regiões translúcidas, pois quando a propriedade TransparencyKey é ativada o winform deixa de receber a mensagem WM_NCHITTEST e qualquer outra mensagem de ação do mouse para as regiões onde a cor transparente for aplicada.

protected override void OnPaint(PaintEventArgs pea)
{ 
    base.OnPaint(pea);

    if (!DesignMode)
        pea.Graphics.FillRectangle(Brushes.Black, this.ClientRectangle);
    else
    {
        //topo
        pea.Graphics.DrawLine(new Pen(new SolidBrush(SystemColors.GradientActiveCaption), margins.Top+2), 0, margins.Top / 2, ClientSize.Width, margins.Top / 2);
        //rodapé
        pea.Graphics.DrawLine(new Pen(new SolidBrush(SystemColors.GradientActiveCaption), margins.Bottom + 2), 0, ClientSize.Height - (margins.Bottom / 2), ClientSize.Width, ClientSize.Height - (margins.Bottom / 2));
        //esquerda
        pea.Graphics.DrawLine(new Pen(new SolidBrush(SystemColors.GradientActiveCaption), margins.Left + 2), margins.Left / 2, 0, margins.Left / 2, ClientSize.Height);
        //direita
        pea.Graphics.DrawLine(new Pen(new SolidBrush(SystemColors.GradientActiveCaption), margins.Right + 2), ClientSize.Width - (margins.Right / 2), 0, ClientSize.Width - (margins.Right / 2), ClientSize.Height);

            }
        }
	

Em modo de design são desenhadas pseudo-margens no winform para que enquanto esteja desenhando o Winform o desenvolvedor consiga visualizar onde as margens extendidas se posicionarão em tempo de execução.

Com a classe AeroForm pronta, para herdar seu comportamento basta inserir um novo winform no projeto e alterar a sua herança de System.Windows.Forms.Form para AeroForm.

public partial class Form1 : AeroForm
	

O resultado em modo design com as margens extendidas será o seguinte:

E em tempo de execução:

É perceptível o quanto a equipe do Windows Vista trabalha para proporcionar recursos cada vez mais extensíveis para e de fácil utilização para as o usuário e o DWM é uma prova disto, sendo que é uma API que ainda tem muito a crescer e recursos a oferecer. Ainda não é suportado, mas devido à sua abordagem e nova maneira de compor o desktop, em um futuro não tão distante é possível que diversos recursos antes imagináveis somente em jogos sejam possíveis no ambiente de janelas de acordo com as necessidades do usuário.

A partir deste artigo, diversos outros recursos podem ser implementados, a documentação da API do DWM é bastante clara e objetiva e pode ser encontrada em http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/programmersguide/dwm/dwm_overview.asp


Início da páginaInício da página