começando a programar em c

24
Começando a programar em C++ Todas as semanas eu recebo a mesma pergunta pelo formulário de contato: "Quero começar a programar em C++ mas não sei como". Eu não fico aborrecido com isso, pelo contrário, fico bastante feliz. É muito bom saber que uma quantidade considerável de pessoas quer evoluir e passar para o lado poderoso da força. :-) Eu pretendo montar, com vários posts, algo que possa ser agrupado em um FAQ para ajudar essas pessoas a se converterem. Quero que esse movimento se transforme numa conversão em massa dos programadores para C++, mostrando a luz às pessoas que estão limitadas dentro de uma vida onde não se pode gerenciar sua própria memória. E assim, mudar meu país para melhor! (Se você costuma ler o que eu escrevo já sabe que não pode me levar muito a sério. Mas, como diz o Alfred , o mais fácil é fazer como a Globo: explique tudo detalhadamente e não deixe nada nas entrelinhas, alguém pode não entender. Então, lá vai: Isso foi uma brincadeira.) Quero me converter para o lado poderoso da força, mas essa história de C e C++ me confunde. O que é o que? A linguagem C foi criada no início dos anos 70 para ser usada na programação do UNIX. Cansados de fazer tudo em Assembly, os programadores resolveram criar uma linguagem que fosse estruturada e que permitisse programação low-level ao mesmo tempo. Assim nasceu a linguagem C. /* Isso está em C */ #include <stdio.h> int main() { int a = 15; int b = 20; char buffer[128]; /* uma string é um array (ou vetor) de bytes terminado por ASCII zero */ strcpy(buffer, "A variável [a] é "); if(a > b) strcat(buffer, "maior"); else strcat(buffer, "igual ou menor "); strcat(buffer, " que a variável [b]\r\n"); printf(buffer);

Upload: assishp

Post on 26-Jun-2015

250 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: Começando a programar em C

Começando a programar em C++

Todas as semanas eu recebo a mesma pergunta pelo formulário de contato: "Quero começar a programar em C++ mas não sei como". Eu não fico aborrecido com isso, pelo contrário, fico bastante feliz. É muito bom saber que uma quantidade considerável de pessoas quer evoluir e passar para o lado poderoso da força. :-)

Eu pretendo montar, com vários posts, algo que possa ser agrupado em um FAQ para ajudar essas pessoas a se converterem. Quero que esse movimento se transforme numa conversão em massa dos programadores para C++, mostrando a luz às pessoas que estão limitadas dentro de uma vida onde não se pode gerenciar sua própria memória. E assim, mudar meu país para melhor!

(Se você costuma ler o que eu escrevo já sabe que não pode me levar muito a sério. Mas, como diz o Alfred, o mais fácil é fazer como a Globo: explique tudo detalhadamente e não deixe nada nas entrelinhas, alguém pode não entender. Então, lá vai: Isso foi uma brincadeira.)

Quero me converter para o lado poderoso da força, mas essa história de C e C++ me confunde. O que é o que?A linguagem C foi criada no início dos anos 70 para ser usada na programação do UNIX. Cansados de fazer tudo em Assembly, os programadores resolveram criar uma linguagem que fosse estruturada e que permitisse programação low-level ao mesmo tempo. Assim nasceu a linguagem C.

/* Isso está em C*/

#include <stdio.h>

int main(){ int a = 15; int b = 20; char buffer[128]; /* uma string é um array (ou vetor) de bytes terminado por ASCII zero */

strcpy(buffer, "A variável [a] é ");

if(a > b) strcat(buffer, "maior"); else strcat(buffer, "igual ou menor ");

strcat(buffer, " que a variável [b]\r\n"); printf(buffer);

return 0;}

O C++ é uma evolução da linguagem C, e foi criada por Bjarne Stroustrup. Nessa evolução foi adicionado à linguagem C o conceito de orientação à objetos, que virou moda naquela época (começo dos anos 80) e é muito usado hoje em dia. Além disso, o próprio C++ foi evoluindo no decorrer da década de 80 e 90, com a adição de recursos como templates e a STL (que veremos depois). O C++ tem tudo que a linguagem C tem (99,8% de compatibilidade) e mais toda a evolução. Todo compilador C++ que eu conheço compila código C sem problemas.

//// Isso está em C++//

#include <iostream>

Page 2: Começando a programar em C

using namespace std;

int main(){ int a = 15; int b = 20; string buffer; // string é um objeto

buffer = "A variável [a] é ";

if(a > b) buffer += "maior"; else buffer += "igual ou menor ";

buffer += " que a variável [b]\r\n"; cout << buffer;

return 0;}

O exemplo feito em C, é compilado sem problemas por qualquer compilador C++, já que ele é também um código C++ válido.

Preciso aprender C antes de aprender C++?Não, não e não. Eu recomendo que você aprenda C++ direto, sem passar pelo C, já que hoje em dia o C++ é mais usado. Se algum dia você precisar fazer algo em C, é só estudar as limitações do C em relação ao C++. As estruturas básicas de controle (if, while, switch...) são as mesmas, o que muda é que a linguagem C não suporta todos os recursos do C++, com suporte à programação orientada a objetos, bibliotecas, templates, etc. Mesmo assim, em C++ você pode usar as bibliotecas do C sem problemas.

Você pode me recomendar algum livro para aprender C++?O único livro para iniciantes que eu conheço e achei bom é o Beginning Visual C++ Programming. Se você é iniciante, qualquer material pode te ajudar, desde um livro de C até um tutorial de Internet. Depois que você já estiver com alguma prática em C++, leia o The C++ Programming Languagedo Stroustrup, que é o guia definitivo sobre o assunto, e que eu recomendo até para os programdores C++ experientes. Eu prentendo recomendar mais livros a medida que o FAQ for avançando.

Todo mundo diz que C++ é muito complicado. Isso é verdade?Você é um homem ou um rato? C++ requer mais estudo por ser uma linguagem completa e poderosa, mas não é nada que um ser humano normal não consiga aprender. Tem gente que acha que usar o Microsoft Word é complicado. Esqueça o que os outros dizem e estude aquilo que você tem vontade.

A moda agora é .NET e Java, será que vale a pena estudar C++?Vale. Como as pessoas estão indo para as linguagens mais fáceis, os profissionais de C++ são mais valorizados. Afinal, quando se precisa de algo 10 vezes mais rápido, alguém precisa fazer. Não se esqueça que praticamente todos os softwares comerciais que existem são feitos em C ou C++ (Windows, Office, SQL Server, Oracle, Photoshop, CorelDRAW, Linux, Visual Studio, o próprio .NET e todas as VMs Java, etc, etc, etc).

Eu já ouvi falar que o Java e o C# são versões melhoradas do C++. Isso é verdade?Se você acha que uma versão mais limitada de alguma coisa é uma melhoria... O Java e o C# são baseadas na linguagem C++, tirando muitos recursos que, apesar de poderosos, causavam confusão ou dificuldade. Foi feita uma simplificação e um nivelamento por baixo (ok, pelo meio) para atender às necessidades mais comuns. Por serem mais simples, essas duas linguagens são indicadas para aplicativos tecnicamente mais simples, como os que manipulam bancos de dados, controlam regras de negócios e fazem entradas de dados. As duas runtimes (JVM e .NET) têm algumas vantagens sobre o C++, como gerenciamento automático de memória, independência relativa de arquitetura e mais facilidade para leitura dos metadados (enumerar as

Page 3: Começando a programar em C

classes de um DLL, por exemplo). Mas têm a desvantagem de consumirem bem mais memória, serem mais lentas (isso pode melhorar com o tempo) e terem limitações técnicas que as impedem de desenvolver certos tipos de software (como device drivers).

Programação Win32 em C/C++

Continuando o meu projeto de projeto de FAQ C++, vou falar hoje sobre Win32.

O que é Win32 e para que serve?Já expliquei isso em outro post.

Ouvi falar que Win32 é complicado, isso é verdade?Isso tem lá seu fundo de verdade, alguns assuntos são extremamente complicados, os mais usuais nem tanto. De qualquer forma, essa complicação tem motivo: como a Win32 API é o acesso mais baixo nível que se pode ter ao sistema (considerando user-mode), ela deve possibilitar que você a use para fazer tudo que é possível no Windows. Por isso, muitas vezes, você chama uma função de 8 parâmetros mais só passa 2. Esses outros 6 parâmetros são usados em situações não muito comuns, mas que devem ser cobertas pela API. Além disso, como essa API é C (e não C++), não é possível fazer overload das funções com versões mais simples para os usos mais simples, como é feito muitas vezes nas classes do .NET Framework e em bibliotecas C++.

Vou exemplificar isso usando a famosa função CreateProcess como exemplo. Essa função pede 10 parâmetros, mas em 99% dos casos você só usa o LPTSTR lpCommandLine. Além dos parâmetros que você passa como NULL, existem alguns que você é obrigado a preencher, como o LPSTARTUPINFO lpStartupInfo, e o LPPROCESS_INFORMATION lpProcessInformation. Veja um exemplo adaptado da MSDN:

#include <windows.h>#include <stdio.h>

void main(){ STARTUPINFO si; PROCESS_INFORMATION p;

// // dica: muitas estruturas no Windows têm uma variável membro chamada // cb ou cbSize. Esse membro deve ser preenchido com o sizeof() // da estrutura ANTES de chamar a função. Se você não fizer isso a função // retornará um erro. Esse é um erro comum de iniciantes (eu apanhei muito...) // ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si);

ZeroMemory(&p, sizeof(p));

// // Abrindo o Bloco de Notas // if( !CreateProcess( NULL, // Sem módulo "C:WINDOWS\\notepad.exe", // linha de comando para o executável NULL, NULL, FALSE, // O processo criado não herdará os handles 0, NULL, NULL, &si, // Ponteiro para STARTUPINFO &p ) // Ponteiro para PROCESS_INFORMATION ) { printf( "Erro em CreateProcess: 0x%X", GetLastError() );

Page 4: Começando a programar em C

return; }

// // O CreateProcess preencheu as estruturas e colocou handles nelas // como não vamos usar os handles, precisamos fechá-los... // CloseHandle(p.hProcess); CloseHandle(p.hThread);}

O que eu preciso saber antes de estudar Win32?Você precisa ter prática em programação C/C++. A API Win32 é exportada como funções C, mas é usada a partir do C++ sem problemas.

Quais livros de Win32 você recomenda?Primeiramente: eu indico que você leia os livros que vou indicar :-) Eu acho muito mais difícil estudar Win32 com tutoriais e lendo a MSDN. Não acho que exista muito matérial para iniciantes na Internet, e, como eu já disse, vale muito mais a pena comprar um livro e ler do que ficar procurando na Internet.

O primeiro livro que você deve ler é o Programming Windows do Charles Petzold, considerado a Bíblia definitiva sobre o assunto. Ele já está na quinta edição, e é essencial para que você entenda como a GDI do Windows funciona. Ele é hardcore do meio pra frente (eu não tive paciência para ler a parte de toolbar), se você não tiver paciência leia até o capítulo 11 (página 566). Isso já será suficiente para entender como as coisas funcionam no Windows, e será muito útil MESMO QUE VOCÊ USE Windows Forms (afinal, WinForms nada mais é do que uma camada .NET sobre a GDI).

Nossa, Win32 é complicado mesmo... 100 linhas para fazer uma janelinha branca e feia? Existe algo mais fácil?Existe. Hoje em dia, quase ninguém mais usa API diretamente ("à la Petzold" como é conhecido). A GDI é complexa pelo mesmo motivo que eu já expliquei, ela é muito flexível e é um dos motivos do sucesso do Windows. Poder e flexibilidade sempre têm um custo, que geralmente é a complexibilidade.

Para resolver isso, foram criadas, por diversas empresas, bibliotecas que encapsulam a Win32 API para facilitar o seu uso (o .NET Framework é uma delas). A biblioteca provida pelo Microsoft Visual C++ é a MFC (Microsoft Foundation Classes), que encapsula uma boa parte da Win32 API em objetos C++. Além disso, a IDE do Visual C++ possui diversos wizards que geram classes e código e facilitam muito a programação. Usar dialogs (forms) em MFC é quase tão fácil quanto VB6. Existem outras bibliotecas, como a VCL/CLX do Delphi e do C++ Builder e o WTL da Microsoft (que é a que eu mais gosto).

Leia algo sobre MFC depois de ler o Petzold. Pode ser qualquer livro, entendendo como funciona o Win32 e a GDI MFC não será um problema.

O livro do Petzold cobre extensivamente a GDI (gráficos). E o resto?Depois de ler o Petzold e algo sobre MFC, leia o Advanced Windows do Jeffrey Richter, outro clássico. Pronto. Isso já é suficiente para você ser um programador Win32. Só 3 livros :-)

Meus amigos dizem que a API Win32 está ultrapassada e não vale a pena estudar isso. É verdade?Não, não é. Você anda convivendo demais com Piranhas.NET. Explique para os seus amigos que TODOS os aplicativos para Windows hoje são feitos em Win32, já que ela é o Windows. No Windows Longhorn (previsto para 2006/2007) ALGUMAS NOVAS APIs serão disponibilidas como classes .NET. O Windows vai ficar cada vez mais .NET, mas isso deve levar no mínimo uns 5 anos. Não se esqueça que o .NET foi lançado em 2001 e a maioria dos aplicativos comerciais ainda são feitos em C e C++, usando a API Win32 (que por enquanto é a API do Windows)

Meus amigos disseram que existe mais material de estudos e livros falando de .NET do que de Win32. É verdade?

Page 5: Começando a programar em C

Não é verdade que existem mais livros sobre .NET. A API Win32 existe desde de 1993, e uma procura por livros na Amazon retornará vários livros. Procure "MFC" na Amazon, depois procure "Windows Forms" e veja a diferença. Além disso, no Code Project tem muito mais coisa útil em MFC do que em .NET.

Você me deixou em dúvida. Se o .NET é tão ruim assim, então eu devo abandoná-lo e fazer tudo em C++?Primeiro: Eu nunca disse que o .NET é ruim. Na verdade eu acho ele muito bom para resolver os problemas que ele se propõe. Mas, tem seus problemas como qualquer API/Framework/Arquitetura. O grande problema é que no Brasil as pessoas acreditam no pessoal de marketing da Microsoft sem pensar se isso resolve o problema, e acham que .NET resolve todos os problemas. Nada resolve todos os problemas.

Como eu já disse, hoje tudo é C++ e Win32 e vai levar anos (talvez mais de uma década) para que o .NET seja realmente a plataforma de programação do Windows. Você acha mesmo que a Microsoft, Adobe/Macromedia e outros vão refazer todos os aplicativos em C#? Além disso, C++ ainda é a coisa mais portável que existe (em termos de código fonte), e esse é o motivo dele ter sido usado pela Mozilla Foundation (Firefox, Thunderbird, etc), pela Adobe (Photoshop), etc. E se isso conta, em Linux quase tudo é C e C++, o kernel (C), Gnome (C), KDE, (C++), etc. O fator multiplataforma do .NET ainda é incerto, e depende de implementações de terceiros (como o Mono).

Eu já escrevi um artigo sobre perspectivas para o NET a quase 1 ano atrás, e acho que ela continua a mesma. As duas arquiteturas são importantes, não troque o .NET pelo Win32, aprenda os dois e use o que for melhor para cada caso. Só não fique sentado esperando o .NET virar a plataforma oficial do Windows, você vai perder vários anos de mercado e da sua vida.

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.

Page 6: Começando a programar em C

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!");

Page 7: Começando a programar em C

    //    // 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);

Page 8: Começando a programar em C

  _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".

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

Outros posts dessa mesma série:   Win32     COM     MFC

ATL - Active Template Library - é uma biblioteca de templates C++ criada pela Microsoft para simplificar a programação de objetos COM/OLE/ActiveX em C++. Ela foi criada inicialmente pela equipe do Visual Basic para simplificar o desenvolvimento interno, já que o VB até a versão 6 é todo baseado em COM. Hoje em dia ela é distribuída junto com todas as versões do Visual C++. É uma biblioteca pouco intrusiva, implementada em camadas e que tem um overhead muito pequeno, por ser baseada em templates. É usada pela Microsoft internamente em seus produtos, como o Windows Explorer, Windows Movie Maker, MMC e vários outros (ao contrário da MFC, que é pouco usada dentro da Microsoft).

O desenvolvimento COM em C++, apesar de não ser muito complicado, é trabalhoso. Muitas interfaces que precisam ser implementadas contém muitas funções cujo código de implementação é o mesmo para todos os componentes, o que torna o trabalho chato e repetitivo. A implementação da interface IUnknown, por exemplo, é sempre a mesma: controle de referência e solicitação das interfaces suportadas.

Além de suportar a implementação de objetos COM, a ATL é uma biblioteca com diversas classes e templates que facilitam muito a programação Windows, como classes para acesso ao registro, comunicação HTTP e SMTP, criptografia, BASE64, acesso à arquivos, ACLs, listas e hashmaps, etc.

Como um trecho de código vale muito mais do que 186.112.794 palavras, veja como é implementado um objeto COM e seu Class Factory em C++ puro:

//// interface do nosso objeto COM//__interface __declspec(uuid("977BF132-B6B6-4d70-88BD-C427A2724B48"))ITest : IUnknown{ HRESULT WINAPI Method1(BSTR str, ULONG ul);};

//// Objeto que implementa a class ITest//class CTest : public ITest{ DWORD m_ref;public: CTest() { m_ref = 0;

Page 9: Começando a programar em C

}

// // implementação de IUnknown // STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject) { if(InlineIsEqualUnknown(riid)) { AddRef(); *ppvObject = static_cast<IUnknown*>(this); return S_OK; } else if(InlineIsEqualGUID(riid, __uuidof(ITest))) { AddRef(); *ppvObject = static_cast<ITest*>(this); return S_OK; } return E_NOINTERFACE; }

STDMETHOD_(ULONG,AddRef)() { return ++m_ref; }

STDMETHOD_(ULONG,Release)() { DWORD ref = --m_ref;

if(ref == 0) delete this;

return ref; }

// // implementação de ITest // STDMETHOD(Method1)(BSTR str, ULONG ul) { MessageBoxW(NULL, str, L"", MB_ICONEXCLAMATION); return S_OK; }};//// Class Factory para o nosso obejto//class CTestClassFactory : public IClassFactory{ DWORD m_ref;public: CTestClassFactory() { m_ref = 0; }

// // quando o objeto é registrado, a runtime do Microsoft COM // chama a função GetClassObject exportada pela DLL do objeto. // como vamos fazer tudo na mão agora, vamos criar esse helper // static HRESULT CreateClassFactory(REFIID riid, void **ppv) { HRESULT hr;

Page 10: Começando a programar em C

IUnknown* p;

try { p = new CTestClassFactory(); } catch(...) { return E_OUTOFMEMORY; }

p->AddRef();

hr = p->QueryInterface(riid, ppv);

p->Release();

return hr; }

// // implementação do IClassFactory // STDMETHOD(CreateInstance)(IUnknown *pUnkOuter, REFIID riid, void **ppvObject) { HRESULT hr; IUnknown* pUnk;

if(pUnkOuter) return CLASS_E_NOAGGREGATION;

try { // // pelo padrão C++, se o new falha uma exceção é disparada // pUnk = new CTest(); } catch(...) { return E_OUTOFMEMORY; } pUnk->AddRef();

hr = pUnk->QueryInterface(riid, ppvObject);

pUnk->Release();

return hr; } STDMETHOD(LockServer)(BOOL fLock) { return S_OK; }

// // implementação de IUnknown // STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject) { if(InlineIsEqualUnknown(riid)) { AddRef(); *ppvObject = this; return S_OK;

Page 11: Começando a programar em C

} else if(InlineIsEqualGUID(riid, IID_IClassFactory)) { AddRef(); *ppvObject = static_cast<IClassFactory*>(this); return S_OK; }

return E_NOINTERFACE; }

STDMETHOD_(ULONG,AddRef)() { return ++m_ref; }

STDMETHOD_(ULONG,Release)() { DWORD ref = --m_ref;

if(ref == 0) delete this;

return ref; }};

//// E no sétimo dia Deus disse: "int main"//int main(){ HRESULT hr; BSTR bstr; IClassFactory* pClassFactory; ITest* pTest;

// // criando o class factory // hr = CTestClassFactory::CreateClassFactory(IID_IClassFactory, (void**)&pClassFactory); if(FAILED(hr)) return hr;

// // solicitando gentilmente para que ele crie um objeto daquele tipo // hr = pClassFactory->CreateInstance(NULL, __uuidof(ITest), (void**)&pTest); if(FAILED(hr)) { pClassFactory->Release(); return hr; }

// // usando o objeto // bstr = SysAllocString(L"Uma string bem legal"); hr = pTest->Method1(bstr, 20); SysFreeString(bstr);

if(FAILED(hr)) { pClassFactory->Release();

Page 12: Começando a programar em C

pTest->Release(); return hr; }

// // liberar as interfaces // pClassFactory->Release(); pTest->Release();

return S_OK;}

Lembre-se, a única coisa realmente útil para nós nesse código é a implementação de ITest::Method1. O resto é tudo suporte ao contador de referências que todo objeto COM deve ter. Com ATL, nossa implementação seria assim:

class ATL_NO_VTABLE CTest1 :   public CComObjectRootEx<CComSingleThreadModel>,  public CComCoClass<CTest1, &CLSID_Test1>,  public ITest1{public:

DECLARE_REGISTRY_RESOURCEID(IDR_TEST1)

BEGIN_COM_MAP(CTest1) COM_INTERFACE_ENTRY(ITest1) END_COM_MAP()

public:

STDMETHOD(Method1)(BSTR p1, DWORD p2) { MessageBoxW(NULL, str, L"", MB_ICONEXCLAMATION); return S_OK; }};

int main(){ HRESULT hr; CComPtr<ITest1> pTest; hr = CTest1::CreateInstance(NULL, &pTest); if(FAILED(hr)) return hr;

hr = pTest->Method1(CComBSTR(L"Uma string muuuuito mais legal"), 150); if(FAILED(hr)) return hr;

// // "olhe mamãe, eu sei coletar meu próprio lixo" //

return S_OK;}

Explicação: STDMETHOD nada mais é do que uma macro que coloca o retorno da função com HRESULT (padrão de retorno de erros COM) e coloca o calling convention como __stdcall, o mesmo das APIs do Windows.

Page 13: Começando a programar em C

Salvamos algumas dezenas de linhas de código usando ATL, já que ele tem uma implementação para IUnknown (single threaded e multi threaded, a nossa é só single) e um Class Factory, além de toda a implementação para que o nosso objeto seja registrado e usado por qualquer cliente COM, seja VB6, .NET, Delphi, etc. Se estivessemos fazendo um servidor OLE, a quantidade de código boilerplate que deixaríamos de escrever seria da ordem de centenas de linhas. E com a elegância e leveza que só o ATL tem :-)

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

Outros posts dessa mesma série:   Win32     ATL     MFC

COM - sigla para Component Object Model - é um padrão binário de componentes que foi criado para facilitar o uso de objetos entre as diversas linguagens de programação. Sendo uma das tecnologias mais importantes desenvolvidas pela Microsoft, ela é usada em praticamente todas as partes do Windows e em quase todos os produtos da Microsoft.

Os pilares básicos desse tecnologia são o acesso aos objetos a partir de interfaces, uma interface padrão (IUnknown) para controle de referência e acesso às outras interfaces (da qual todas as interfaces criadas devem herdar), e o padrão binário da vtable (tabela com os ponteiros para as funções da interface) para que os objetos feitos em diversas linguagens possam se comunicar entre si. Para um objeto ser chamado de objeto COM, ele só precisa seguir essas premissas. Quando a implementação é em C++, isso que dizer que o objeto deve herdar de IUnknown e implementar seu três métodos:

interface IUnknown{ HRESULT QueryInterface(REFIID riid,[out]void **ppvObject); ULONG AddRef(); ULONG Release();};

No seu uso mais comum, além das premissas que eu já enumerei, é necessário registrar o objeto e o objeto que sabe criá-lo (objeto que implementa a interface IClassFactory). Entre as linguagem compatíveis com COM estão: C, C++, Delphi, VBScript, JScript, Visual Basic 4/5/6, todas as linguagens .NET (C#, VB, etc), PHP, Python, Perl e outras.

O COM serve de base para diversas outras tecnologias criadas pela Microsoft, que veremos mais a frente. As tecnologias baseadas em COM são geralmente nada mais são do que uma lista de interfaces COM que determinam a comunicação entre os diversos componentes (de um modo geral, não necessariamente componentes COM). Para ser um COM, um objeto só precisa implementar a interface IUnknown. Para ser um controle ActiveX (ActiveX é uma das tecnologias baseadas em COM), um objeto precisa implementar IUnknown e mais as interfaces específicas da tecnologia ActiveX. Veja algumas tecnologias que usam COM como base:

ActiveX: Usada para criar controles (ActiveX control) que tem interação com o usuário. Seu uso é muito comum no Visual Basic 6 e anteriores.O próprio Internet Explorer nada mais é do que um programa que hospeda o controle ActiveX de renderização de HTML da Microsoft (mshtml.dll).

OLE: Object Linking and Embedding é a tecnologia de troca de dados entre aplicativos que sucedeu o DDE. Quando você copia um desenho no CorelDRAW! e cola no Microsoft Word, toda a comunicação entre eles para que isso seja possível é feita usado OLE. Nesse exemplo específico, o Microsoft Word chama um objeto COM/OLE do CorelDRAW! solicitando que ele desenhe o objeto para que o Word possa exibí-lo.

Structured Storage: Parte do OLE, permite que um arquivo possa guardar informações de vários programas. Voltando ao nosso exemplo anterior, quando o usuário salva um documento Microsoft Word que contém um gráfico do CorelDRAW!, o Word faz uma chamada para um objeto COM/OLE do CorelDRAW!, que salva o seu desenho dentro do arquivo DOC do Word. Quando o documento é carregado, ocorre o inverso.

Page 14: Começando a programar em C

MMC: O Microsoft Management Console é uma iniciativa da Microsoft de padronização da aparência e funcionamento das ferramentas de gerenciamento do Windows. O Snapins do MMC nada mais são do que objetos COM que implementam as interfaces específicas para se comunicar com o MMC. Para entender melhor, vá em "Start Menu" >> "Run" ("Menu Iniciar" >> "Executar" para alguns), digite "compmgmt.msc". Tudo que você vê aí é implementado em COM.

Windows Shell: A API para usar os recursos do Windows Shell (basicamente Windows Explorer) é exportada como objetos COM. Já mostrei antes um exemplo de como mudar a imagem de fundo do desktop usando o objeto COM do ActiveDesktop.

Shell Extensions: Quando você instala o WinZip ou WinRAR, eles adicionam ao menu de contexto do Windows Explorer opções para manipulação de arquivos ZIP ou RAR e para compactar arquivos comuns. Quem controla isso são objetos COM chamados pelo Explorer e registrados pelos respectivos aplicativos.

Internet Explorer: Todas as barras de ferramentas personalizadas do Internet Explorer (como as feitas pelo Yahoo! e Google) são objetos COM. Na realidade, todas as extensões feitas ao Internet Explorer são objetos COM, seja barra de ferramentas, um Pane (se você usa IE, use o CTRL+H para descobrir o que é um Pane), seja um Browser Helper Objects.

Automation: É a possibilidade de controlar um aplicativo usando objetos COM exportados por ele. Entre os aplicativos que suportam automation estão todos do pacote Office (Word, Excel, etc). As extensões para aplicativos feitas em VBA nada mais são do que programas VB(A) que usam esses objetos Automation para controlá-los. Hoje em dia é possível fazer em .NET o que se fazia com o VBA, mas os objetos .NET nada mais fazem do que repassar as chamadas para os objetos COM.

DirectX: O DirectX é 100% implementado como objetos COM. Microsoft Office Addins, Extensions: Todos os Addins e extensões para o Office são feitos em

COM, inclusive exemplos conhecidos como a intergração do Google Desktop Search e do MSN Desktop Search com o Outlook. Hoje é possível fazê-los em .NET, já que a Microsoft provê objetos .NET que encapsulam os objetos COM do Office (ou seja, no final das contas, é tudo COM).

Além dessas tecnologias que eu detalhei, existem várias outras, como WMI, Scripting, ASP, Windows Media Player e outros.

Eu tinha preparado uma lista de programas Microsoft ou módulos do Windows que usam COM (Windows Explorer, Internet Explorer, Office, Exchange, SQL Server, ISA, Visual Studio, etc, etc, etc). Depois cheguei a conclusão que é mais fácil listar os módulos que não usam COM: o kernel do Windows (que é feito em C, não em C++), o Bloco de Notas e a Calculadora. Alguém conhece mais algum que não use nada de COM?

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

Outros posts dessa mesma série:   Win32     COM     ATL

MFC: A Microsoft Foundation Classes é um framework e uma biblioteca de classes C++ que encapsula grande parte da API Win32. Ela foi criada pela Microsoft para facilitar a programação em Win32 usando C++, já que a API Win32 é exportada como funções C. Ela é um framework no sentido de que todos os aplicativos MFC devem "se encaixar" nesse framework de alguma forma, seguindo certos requisitos. Ela não foi feita para ser incluída em um projeto só para usar algumas classes, como é o caso do WTL (eu falarei de WTL em outro post).

Como um trecho de código vale mais do que 2 + 2 palavras, vamos à ele:

#include <afxwin.h>

//// Minha janela principal//class CMyWindow : public CFrameWnd{private:

Page 15: Começando a programar em C

  CButton m_btnTest;

  DECLARE_MESSAGE_MAP();

public:  //  // essa função não é da MFC, eu a criei para inicializar meus   // controles daqui  //  BOOL InitializeControls()  {    m_btnTest.Create("blah",BS_PUSHBUTTON , CRect(10,10,100,60),this, 1);    m_btnTest.ShowWindow(SW_SHOW);

    return TRUE;  }

  //  // função que trata o evento de clique do botão  //  LRESULT OnButtonTestClick()  {    AfxMessageBox("button click!");    return 0;  }

  //  // evento de duplo click  //  LRESULT OnLButtonDblClk(UINT, CPoint)  {    AfxMessageBox("dbl click!");    return 0;  }

  //  // evento de resize  //  LRESULT OnSize(UINT nType, int cx, int cy)  {    CString str;

    //    // vamos colocar a nova altura e largura como título    // da janela    //    str.Format("largura: %d, altura:%d", cx, cy);

    SetWindowText(str);

    return 0;  }};

//// mapa de mensagens da classe CMyWindow// aqui colocamos de modo declarativo qual evento será// tratado por qual função//BEGIN_MESSAGE_MAP(CMyWindow, CFrameWnd)  ON_BN_CLICKED(1, OnButtonTestClick)  ON_WM_LBUTTONDBLCLK()  ON_WM_SIZE()END_MESSAGE_MAP( )

//// classe que representa a aplicação em si,

Page 16: Começando a programar em C

// herda de CWinApp//class CMyApp : public CWinApp{  //  // Função chamada pela MFC assim que o aplicativo é  // inicializado. Coloque aqui o que seria colocado  // no WinMain  //  BOOL InitInstance()  {    CMyWindow* pMyWindow = new CMyWindow;

    //    // vamos criar nossa janela e mostrá-la    //    pMyWindow->Create(NULL, "www.1bit.com.br");

    pMyWindow->InitializeControls();    pMyWindow->ShowWindow(SW_SHOW);    pMyWindow->UpdateWindow();

    m_pMainWnd = pMyWindow;

    return TRUE;  }};

CMyApp theApp;

A MFC é a principal biblioteca de classes para C++ da Microsoft. Ela vem junto com o Visual C++, e a IDE tem total suporte para ela, facilitando a nossa vida com wizards e "clique com o botão direito e...". Fazer um "Dialog Application" usando MFC e o Visual C++ é quase tão fácil quanto fazer um programa em VB (meus alunos de C++ disseram isso). Como no VB, você desenha um botão visualmente, dá um duplo clique no botão criado e a MFC cria um handler para o evento de clique do botão. Além disso, a MFC contém diversas macros e funções para associar variáveis com controles Win32. Esse recurso é chamado de DDX, e é muito útil para formulários cheios de CheckBoxes e TextBoxes. Eu acho esse um dos recursos mais úteis da MFC, e reduz bastante o tempo de desenvolvimento de programas com essas características.

A MFC também tem suporte à bancos de dados ODBC ou OLEDB. No caso de OLEDB, um wizard cria classes com propriedades (variáveis membro) equivalentes aos campos do banco de dados. Mas o grande destaque da MFC é "Document/View Model", que provê um framework para aplicativos que usam o conceito de documento (como o Word, CorelDRAW!, etc). Junto com o suporte a serialização, fica bem mais fácil fazer um aplicativo de edição de documentos com open/save, área de transferência e várias views de um mesmo documento.

A MFC é bastante criticada por não usar recursos modernos do C++ e não ser totalmente type-safe. Apesar das melhorias no quesito type-safe a partir da MFC 7, as críticas ainda persistem. Apesar de tudo isso, a MFC ainda é muito usada, e é possível achar muita informação sobre ela na Internet. A literatura é vasta e existem diversos sites com seções especializadas em MFC (como o Code Project e o Code Guru). Muitas empresas (inclusive brasileiras) desenvolvem aplicativos em MFC, e a finada certificação "Developing Desktop Applications Using Microsoft Visual C++" era toda sobre MFC.

Usando a MFC você tem a opção de fazer um link estático com a MFC ou usar a MFC em uma DLL (de aproximadamente 1 MB). No exemplo de código acima, o link estático fez o executável ficar com 100kb a mais, mas eu já vi casos onde o executável fica 300kb maior - o que em muitas situações é desprezível.

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

Outros posts dessa mesma série:   ATL     COM     MFC

Page 17: Começando a programar em C

Win32 API: API (Application Programming Interface) das versões do Windows que são 32 bits (95, 98, 98SE, Millenium, NT, 2000, XP, 2003, Longhorn, etc). Nada mais é do que as funções que o sistema operacional exporta para serem usadas pelas aplicações. Cada sistema operacional tem a sua API, e a runtime do C e C++ é implementada em cada plataforma usando essa API. Por exemplo, o malloc da linguagem C acaba chamando HeapAlloc ou VirtualAlloc da API. Para mais detalhes, veja a documentação na MSDN. Código fonte sempre vale mais do que h palavras:

#define UNICODE#define _UNICODE#define WIN32#define _WINDOWS#define WIN32_LEAN_AND_MEAN

#include <windows.h>

//// programa Win32 tem como entry point (função inicial) a função WinMain//int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,int nCmdShow){ WCHAR* wzBuffer; HANDLE hHeap; hHeap = GetProcessHeap();

// // usando a função HeapAlloc da API para alocar memória // wzBuffer = (WCHAR*) HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 256);

// // wsprintf também é da API // wsprintf(wzBuffer, L"TickCount: %d", GetTickCount());

MessageBox(NULL, wzBuffer, L"Mensagem", MB_OK);

// // se eu usasse ATL eu não precisava fazer isso... // HeapFree(hHeap, NULL, wzBuffer);

return 0;}

Para mais informações sobre Win32, veja o meu post "FAQ: Programação Win32 em C/C++"

Se você não tiver o Visual C++, você pode fazer download do Microsoft Visual C++ Toolkit Compiler e do Microsoft Platform SDK. A compilação em linha de comando fica assim:

C:Temp>cl win.cpp /link user32.libMicrosoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86Copyright (C) Microsoft Corp 1984-1998. All rights reserved.

win.cppMicrosoft (R) Incremental Linker Version 6.00.8447Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

/out:win.exeuser32.libwin.obj

Depois ainda teremos COM, ATL, WTL e MFC. Alguém tem mais alguma sugestão?

Page 18: Começando a programar em C

Como fazer debug remoto com o Visual C++ 7.1

Primeiro é necessário habilitar o servidor de debug na máquina remota:

Reze um pouco... Compartilhe a pasta "C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\

Packages\Debugger" que está na sua máquina. Nesse exemplo, vou chamar a pasta compartilhada de vc7debug.

Baixe o PsExec do site do SysInternals. Esse aplicativo permite que você execute um programa em outra máquina pela rede, mesmo sem ter acesso via Terminal Sevices - contanto que você tenha permissões na máquina remota, é claro.

Execute o msvcmon.exe na máquina remota, usando o psexec. Rode a seguinte linha de comando NA SUA MÁQUINA:psexec \\MAQUINA_REMOTA -u DOMINIO\SEU_USUARIO \\SUA_MAQUINA\vc7debug\msvcmon.exe -tcpip -anyuser -timeout -1

O psexec vai pedir sua senha de rede, digite-a.

Uma das formas de se fazer debug é dar um attach em um processo que já está rodando. Essa é a forma mais simples, e funciona assim:

No Visual Studio, menu Tools >> Debug Processes... Em Transport coloque TCP/IP, e em Name coloque o nome da máquina remota. Clique em Refresh e a lista de processos da máquina remota deve aparecer. Pronto. Agora é só selecionar um e clicar em Attach.

A outra forma - a mais complicada - é configurar o Visual Studio para que toda vez que você fizer o debug normal (F5, F10) ele conecte na máquina remota e execute o programa lá. Faça assim:

Antes de começar configurar o Visual Studio, compartilhe a pasta onde fica o executável na sua máquina (pasta Debug geralmente). Nesse exemplo vou compartilhar como bin_debug.

Abra as propriedades do projeto No TreeView da esquerda escolha Debugging. Em Working Directory configure o diretório de trabalho da máquina remota. Em Remote Settings >> Connection escolha Remote via TCP/IP. Em Remote Settings >> Remote Machine coloque o nome da máquina remota. Em Remote Settings >> Remote Command, coloque \\SUA_MAQUINA\bin_debug\

SEU_EXECUTAVEL.exe. Clique em OK, e reze um pouco. Depois disso aperte F5 ou F10 e veja se o debug começa.

O problema mais comum nesse tipo de configuração é relativo a permissões. Se o Visual Studio reclamar que não consegue abrir o executável, rode o filemon NA MÁQUINA REMOTA e veja qual o motivo da falha.

Com essas configurações que eu passei, o msvcmon (servidor de debug) aceitará conexão de qualquer usuário, e isso pode ser um problema. Se precisar de mais segurança, veja os parâmetros do msvcmon (rode msvcmon /?) e configure a conexão via Named Pipes ao invés de TCP/IP.

ACHO que para o Visual C++ 8 os passos são os mesmos...