logo
Contato | Sobre...        
rebarba rebarba

Rodrigo Strauss :: Blog


Explicando a sopa de letrinhas da programação C/C++ para Windows: WTL

Outros posts dessa mesma série:   ATL     COM     MFC     Win32

WTL (Windows Template Library) é uma biblioteca de templates C++ que encapsula a parte da Win32 API que lida com interface gráfica (GDI). Ela contém classes para criar janelas, controles Win32 (botões, barras de progresso, etc), dialogs, wizards, etc.

A WTL é uma extensão da ATL, que já contém algumas classes básicas para manipulação de janelas. Essas classes da ATL foram criadas inicialmente para ajudar na confecção de controles ActiveX e seus Property Pages. Sobre esse suporte básico da ATL, um programador da Microsoft chamado Nenad Stefanovic criou diversas outras classes para encapsular o restante da GDI. Esse conjunto de classes acabou se transformando no que conhecemos como WTL.

Por ser uma extensão da ATL, a WTL segue a mesma filosofia: classes template enxutas (inspiradas pela STL), liberdade de uso das classes fora de um framework (ao contrário da MFC) e código simples e rápido. Por ser todo baseado em templates, não é necessário usar uma LIB ou DLL, seu executável fica completamente independente. Além disso - também pelo fato de usar templates - o tamanho do executável fica muito pequeno, sendo possível criar executáveis de 70 kb ou menos sem dependência de DLLs ou runtimes. Compilando seu executável em Release, a WTL não causa nenhum overhead em relação a programas feito em Win32 puro, sem classes. Como o código da WTL é muito enxuto, a maioria das funcões acabam "sumindo" durante a compilação, pois são colocadas inline.

Há algum tempo atrás o projeto WTL foi colocado no SourceForge para que a comunidade C++/Win32 pudesse ajudar o Nenad nas correções e sugestões. Mesmo assim, o Nenad ainda é o coordenador e responsável pelo projeto, garantindo que a filosofia ATL/WTL não suma a medida que milhares de classes sejam adicionadas à biblioteca. Na realidade poucas classes foram adicionadas à WTL depois disso, com destaque para as classes para Wizards.

Muitas classes da WTL reproduzem funcionalidades disponíveis na MFC, como as classes CRect, CString (que a partir do Visual C++ 7.0 faz parte da ATL e não da MFC) e muitas outras. O suporte a janelas também é bem parecido com a MFC, usando mapas de mensagens. Não é difícil para um programador MFC usar WTL, a adaptação é fácil.

Apesar de todas as vantagens que eu citei, existem algumas desvantagens. Apesar dessa biblioteca ter nascido dentro da Microsoft, ela nunca ofereceu suporte para a WTL. Ela chegou a ser disponibilizada junto com o Platform SDK e o download ainda pode ser feito diretamente nos servidores da Microsoft, mas a biblioteca oficial da Microsoft para C++ ainda é a MFC. Mesmo assim existe um comunidade grande voltada para a WTL, e sempre que eu tive problemas uma pergunta ou uma busca na lista de discussão foi suficiente - pelo próprio fato de ser uma biblioteca simples e enxuta.

Outro problema da WTL sempre foi a falta de suporte da IDE para ela. A MFC provê diversos wizard e funcionalidades na IDE para assinatura de eventos e criação de classes, suporte que nunca foi dado à WTL. Esse problema foi resolvido por uma santa alma que disponibilizou no CodeProject o WTLHelper, que chega a ser melhor do que o suporte do Visual Studio para a MFC (ClassWizard ou suporte do Visual Studio 7+). Mesmo assim, não deixa de ser um produto não-oficial e que passa longe do controle de qualidade da Microsoft.

Como um trecho de código vale mais do que 20 palavras, vamos a um programa simples feito em WTL:

#define WINVER      0x0400
#define _WIN32_WINNT  0x0400
#define _WIN32_IE    0x0400
#define UNICODE
#define _UNICODE

#include <atlbase.h>
#include <atlapp.h>
#include <atlmisc.h>
#include <atlstr.h>

extern CAppModule _Module;

#include <atlwin.h>
#include <atlframe.h>
#include <atlctrls.h>
#include <atldlgs.h>
#include <atlctrlw.h>

CAppModule _Module;

class CMainFrame : public CFrameWindowImpl<CMainFrame>
{
public:
  WTL::CButton m_btnTest;
  WTL::CEdit m_edtTest;

  //
  // faz a janela ficar com o fundo cinza de dialog
  // (ao invés de branco padrão)
  //
  DECLARE_FRAME_WND_CLASS_EX(NULL, 0, NULL, COLOR_BTNFACE)

  BEGIN_MSG_MAP(CMainFrame)
    MESSAGE_HANDLER(WM_CREATE, OnCreate)
    COMMAND_HANDLER(1, BN_CLICKED, OnButtonClick)
    CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)
  END_MSG_MAP()

  LRESULT OnCreate(UINT, WPARAM, LPARAM, BOOL&)
  {
    SetWindowText(L"WTL Rules!");

    //
    // cria um botão e um edit
    //
    m_edtTest.Create(m_hWnd, CRect(10,10,200,32), NULL, 
      ES_LEFT | WS_VISIBLE | WS_CHILDWINDOW, WS_EX_CLIENTEDGE , 2);
    m_edtTest.SetWindowText(L"digite algo aqui");
    m_edtTest.SetFocus();
    m_edtTest.SetSel(0, m_edtTest.GetWindowTextLength());

    m_btnTest.Create(m_hWnd, CRect(120,45,200,80), NULL, 
      BS_PUSHBUTTON | WS_VISIBLE | WS_CHILDWINDOW, NULL, 1);
    m_btnTest.SetWindowText(L"Botão");

    //
    // usa o fonte padrão de dialog 
    // (tem que fazer isso porque criamos um janela, não um dialog)
    //
    m_edtTest.SetFont((HFONT)GetStockObject(DEFAULT_GUI_FONT));
    m_btnTest.SetFont((HFONT)GetStockObject(DEFAULT_GUI_FONT));

    return 0;
  }

  LRESULT OnButtonClick(WORD, WORD, HWND, BOOL&)
  {
    ATL::CString str;

    m_edtTest.GetWindowText(str);
    MessageBox(str);;
    return 0;
  }
};

int Run()
{
  CMessageLoop theLoop;
  CMainFrame wndMain;
  
  //
  // no WTL, existe um objeto separado que controla o message loop
  // vamos adicioná-lo ao _Module, que é o objeto global do ATL que
  // controla toda a aplicação
  //
  _Module.AddMessageLoop(&theLoop);

  //
  // agora é só criar a janela e rodar o message loop
  //
  wndMain.CreateEx(NULL, CRect(100,100,320,220),
    WS_CAPTION | WS_SYSMENU | WS_THICKFRAME);
  wndMain.ShowWindow(SW_SHOW);
  wndMain.UpdateWindow();

  int nRet = theLoop.Run();

  _Module.RemoveMessageLoop();

  return nRet;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)
{
  //
  // primeiro inicializamos o COM, ATL e Common Controls
  //
  ::CoInitialize(NULL);
  _Module.Init(NULL, hInstance);
  AtlInitCommonControls(ICC_COOL_CLASSES | ICC_BAR_CLASSES);

  //
  // e agora colocamos o programa para rodar
  //
  int nRet = Run();

  _Module.Term();
  ::CoUninitialize();

  return nRet;
}

Para compilar esse trecho de código é só instalar e configurar a WTL, criar um programa "Win32 Application" e substituir o código gerado pelo Wizard por esse. Além disso, quando você instala o WTL você terá um novo Wizard no Visual Studio para criar um "ATL/WTL Application".

Mais Informações:
WTL no SourceForge
Lista de discussão e suporte WTL
WTLHelper
Seção do CodeProject sobre WTL


Em 19/01/2006 20:32, por Rodrigo Strauss


  
 
 
Comentários
Wanderley Caloni Jr | website | em 19/01/2006 | #
Só esqueceu de citar que agora o ATL está disponível no SDK!! Ou seja, usando Visual C++ 2005 Express Edition + SDK + WTL temos um ambiente de programação de aplicativos enxutos de graça =)

SDK: http://www.codeproject.com/wtl/WTLExpress.asp
Artigo do CodeProject que explica como usar o WTL junto do ATL que vem no SDK: http://www.codeproject.com/article.asp?tag=20899492768138734
Marcelo Santana | em 30/01/2006 | #
Você conhece a biblioteca SmartWin? http://smartwin.sf.net

Também baseada em templates que encapsula Win32 API e que não usa "Macro Magic" como a WTL, muito mais typesafe... Acho ela muito boa.
Rodrigo Pinho | em 26/05/2007 | #
Se o problema da WTL era a falta de integração com IDE, ou falta de Wizards, tem duas ferramentas que ajudam nisto

http://salos.narod.ru/eng/WTLHelper/WTLHelper.html
Muito melhor que o ClassWizard.

http://salos.narod.ru/eng/WtlWiz/WtlWiz.html
Possui wizard para Aplicações com Spliter
Marcelo Blauth | website | em 28/12/2007 | #
Vc é filho de Elias Strauss? Comandante da Varig?
Rodrigo Strauss | website | em 29/12/2007 | #
não
Mounter | website | em 11/06/2008 | #
Olá, muito legal o tutorial, vou tentar mexer mais com a WinAPI no C++.

Até mais.
Cleber Ramos | em 14/08/2008 | #
Olá, gostei muito do tutorial. Parabens. Gostaria de saber WTL pode funcionar no visual studio 2008?

obrigado,
Cleber Ramos
Rodrigo Strauss | website | em 15/08/2008 | #
Funciona sim.
Reginaldo | em 07/09/2010 | #
Parabéns pelo artigo.
Sabe me indicar uma forma instalar WTL em alguma versão Express, 2008 ou 2010?

Obrigado.
Rodrigo Strauss | website | em 08/09/2010 | #
Veja http://stackoverflow.com/questions/71659/how-to-add-wtl-and-...
Cristiano | em 31/03/2011 | #
muinto bom est sit ja tava desistin... bom continuo sem entend muinta koizs mais isto nao importa...axo q vo aprend muint aki vlw pela ajuda :)... no final da tudo serto...
rebarba rebarba
  ::::