Rodrigo Strauss :: Blog
C++ com sanidade: usando ATL em aplicações
Muita gente costuma dizer que em C++ programa-se muito para pouco resultado. Todo mundo assume que esse "resultado" roda bem mais rápido, mas já é outra coisa... Eu acredito que é possível manter a sanidade e a vida social programando em C++, só é preciso ter um pouco mais de conhecimento e um pouco mais de cuidado. Pretendo escrever bastante sobre isso se eu tiver tempo.
A lenda sobre o fato de programar em C++ ser trabalhoso, vem principalmente do fato de que as pessoas usam C++ como um C melhorado. Conheço vários programadores C++ que não usam STL e que ainda ficam manipulando char* a toda hora, em pleno ano de 2005 (eu fazia isso até o ano passado). Apesar do C++ ser um superset da linguagem C, ele tem dezenas de melhorias que permitem escrever um código mais organizado, simples e conciso.
Eu tenho estudado muito sobre qualidade de código, incluindo sobre como escrever um código claro e com menos bugs. Quanto mais eu estudo, mais eu vejo como isso é possível, e como C++ é uma ferramenta maravilhosa para esse fim. C++ segue o conceito usado para aproximar uma linguagem do nível ideal: fazer as coisas simples serem simples, e as coisas complexas serem possíveis. Muitas linguagens de alto nível que existem fazem o simples ser simples, mas fazem o complexo ser complicado demais e cheio de gambiarras e interops.
A API Win32 não é lá muito sã. Para criar uma janela em Win32 puro (como Petzold), é necessário uma centena de linhas de código. E tudo que você ganha é uma janela branca e muito feia. Mas não podemos esquecer que a API Win32 ainda herda da API do Windows 1.0, que foi feita para linguagem C, usando os conceitos de programação da época. O mais engraçado é que ainda usam esse conceito hoje em dia... Alguém já tentou enviar uma mensagem para o MSMQ usando a API para C? É coisa para quem não tem mais o que fazer. Apesar de gostar bastante de Win32, eu assumo que é um pouco por masoquismo e por orgulho de ter conseguido aprender isso... :-)
Escolhi ATL para começar esse assunto porque, além de ser uma biblioteca que eu gosto muito, ela ajuda a trazer um pouco de sanidade à programação Win32. E ao contrário da MFC, não é um framework que você é obrigado a seguir. MFC é bom e tem seu espaço, mas vou explorar a ATL porque ela permite o uso "avulso" e por ser menos usada em Win32.
ATL (Active Templte Library) é basicamente uma biblioteca de templates usada para facilitar o desenvolvimento de componentes COM. Além de cumprir de modo soberbo esse papel, ela também tem diversas classes (muitas delas desconhecidas) para facilitar a programação Win32, tornando nossa vida muito mais fácil. A ATL, ao contrário do MFC, não cria dependência de nenhuma DLL. É só incluir os headers e sair usando. Se você fizer um disassembly de um executável RELEASE que usa ATL, verá que ela é um "thin layer", e que muito da ATL "desaparece" (vira inline) depois da otimização.
Hoje vamos ver um exemplo de uso da ATL para leitura de arquivos e para buffers:
#define UNICODE
#define _UNICODE
#include <atlbase.h>
#include <atlstr.h>
#include <atlfile.h>
#include <atlmem.h>
int wmain(int argc, WCHAR* argv[])
{
HRESULT hr;
ATL::CAtlFile hFile;
ATL::CString strFileName;
ATL::CHeapPtr<char> pBuffer;
unsigned __int64 iSize;
strFileName = L"c:\\boot.ini";
//
// abrindo o arquivo. Bem parecido com o ::CreateFile, mas com parâmetros defaults
//
hr = hFile.Create(strFileName, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING);
if(FAILED(hr))
{
MessageBox(NULL, ATL::CString("Erro ao abrir ") + strFileName, L"Erro", MB_ICONERROR);
return hr;
}
hFile.GetSize(iSize);
//
// usando o CHeapPtr como buffer. Vamos alocar, e ele desaloca no destrutor
//
pBuffer.Allocate(iSize + 1);
//
// vamos ler o conteúdo do arquivo, usando o CHeapBuffer
// Como ele sobrecarrega os operadores de conversão, podemos usá-lo
// como se fosse mesmo um ponteiro para um buffer
//
hFile.Read(pBuffer, iSize);
//
// Vamos colocar um \0 no final para fechar a string
//
pBuffer[iSize] = '\0';
//
// vamos usar MessageBoxA (ANSI) pq nosso programa é UNICODE
// Não se esqueça que os arquivos texto geralmente são ANSI
//
MessageBoxA(NULL, pBuffer, "Conteúdo do arquivo", MB_OK);
//
// Não precisamos desalocar o buffer
// não precisamos fechar o handle do arquivo
//
return 0;
}
Note que o código usa UNICODE, já que não temos necessidade de suportar Windows 9x nesse exemplo. Note que esse código é mais claro do que o código que usa Win32 diretamente, e com mais facilidades. Não precisamos fechar o HANDLE para o arquivo e não precisamos desalocar o buffer usado. Eu costumo usar o "ATL::" para ser notório quais objetos são da ATL. Isso evita confusão com o objetos parecidos que existem na MFC.
Em 24/03/2005 03:50, por Rodrigo Strauss




