logo
Contato | Sobre...        
rebarba rebarba

Rodrigo Strauss :: Blog

follow us in feedly

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 | e-mail | 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 | e-mail | 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 | e-mail | 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...
Algo a dizer?
Nome:


Site:


E-mail:


Escreva o número vinte e seis:


 Não mostre meu e-mail no site, não serve pra nada mesmo...

Comentário





Os comentários devem ser sobre assuntos relativos ao post, eu provavelmente apagarei comentários totalmente offtopic. Se quiser me enviar uma mensagem, use o formulário de contato. E não esqueça: isso é um site pessoal e eu me reservo o direito de apagar qualquer comentário ofensivo ou inapropriado.
rebarba rebarba
  ::::