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





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