Rodrigo Strauss :: Blog
|
|
|
Talvez você ache interessante ver a lista com todos os posts ou minha lista com os melhores posts.
1, 2, 3 testando
Teste, 1, 2, 3.
Teste de formatação e de edição
"Mais um teste"
Em 21/07/2004 16:07 - Comentários (9)
Curso de Spam no SEBRAE
Esses dias encontrei um amigo que montou uma empresa de consultoria na área de telefonia. Ele veio me mostrar os impressos de divulgação da empresa, e me contou que estava fazendo divulgação via e-mail. Quando eu perguntei como ele conseguia os e-mails, ele falou que um conhecido dele o tinha emprestado um CD com milhões de e-mails e com os programas para enviá-los...
Eu expliquei que isso era spam, que era ilegal, que nenhuma empresa decente faz esse tipo de coisa, que as pessoas ficam irritadas com e-mails não solicitados, etc, etc. Foi quando ele argumentou que o e-mail era o meio mais barato de divulgar a empresa, e que se 0,01% dos milhões de e-mails derem retorno já é uma grande coisa.
No final ele me contou que fez um curso no SEBRAE, e foi lá que ele aprendeu as vantagens da "divulgação por e-mail"..
Em 22/07/2004 04:39 - Comentários (2)
Por isso que eu não compro livro traduzido....
Lançaram o famoso livro sobre "Refactoring" em português. Os caras tiveram a capacidade de traduzir "Refactoring" para refatoração... não é de matar? Por isso que eu compro direto da amazon...
Em 23/07/2004 13:34 - Comentários (0)
Tudo muda, o tempo todo
Eu estava lendo o Programming the Microsoft Windows Driver Model, do Walter Oney para tirar umas dúvidas sobre IRPs, e acabei abrindo o livro na parte que ele explica como funcionam as exceções em kernel mode. Ele também falava sobre o que acontece quando uma exceção é disparada e como usar blocos de __try/__except e __try/__finally para tratar uma exceção.
Nessa parte ele explica que quando uma exceção é disparada, o kernel sai procurando na pilha alguém que a trate. Depois ele fala que isso pode gerar problemas de performance, já que é necessário percorrer toda a pilha atrás de alguma função que lide com essa exceção. Eu também me lembro que muita gente não usa as exceções em C++ por causa de performance (fora os motivos apontados pelo Joel).
Performance, performance, performance. Hoje em dia, muitas dessas pessoas que falavam isso estão usando .NET, que tem um problema de performance muito maior, já que a runtime roda MUITO código além do seu. (Isso me lembra de programadores C reclamando que o compilador C++ gera código que eles não pediram, como o do copy constructor). É engraçado como a noção de prioridade performance/facilidade muda com o tempo. O jeito é não dar muito ouvidos e testar qual metodologia e linguagem que melhor resolve o seu problema.
Em 23/07/2004 23:54 - Comentários (0)
Como escrever um comparativo técnico tendencioso e sem fundamentos
Um sujeito que trabalha para a Oracle, fez um comparativo simplesmente ridículo entre ASP.NET e PHP. Escreveu um monte de abobrinhas malhando o ASP.NET e favorecendo o PHP, sem apontar dados concretos sobre os problemas que ele diz que o ASP.NET tem. Eu acho o PHP realmente muito bom, mas tentar divulgá-lo as custas de um comparativo ridículo desses, já é sacanagem.
E, pelo jeito, eu não fui o único que não gostou muito desse artigo. Olhe no final o rating do artigo, a maioria dos leitores também achou o artigo uma porcaria.... :-)
Em 26/07/2004 12:15 - Comentários (0)
Kernel mode dev lives!
A MSDN está publicando artigos sobre desenvolvimento de drivers com uma certa regularidade. Parece que o pessoal de kernel mode da Microsoft resolveu aparecer... O ultimo é sobre thread context e IRQLs.
Será que isso vai ajudar a reduzir nossa dependência do pessoal da OSR e da PCAUSA?
Em 26/07/2004 12:32 - Comentários (0)
Novos iPAQs
Meu velho 3650 parece uma carroça velha perto dos novos iPAQs. Um deles tem um processador de 624 Mhz, mais do que o meu Pentium III 600 que eu estava usando para desenvolver com Visual Studio.NET / WinDbg / VMWare até uma semana atrás.
Eu acho que não vai demorar muito para que um iPAQ rode uma máquina virtual com um Windows 9x/NT dentro. Eu já li alguma coisa, não me lembro onde, dizendo que estavam portando o bochs para PocketPC.
Em 26/07/2004 12:57 - Comentários (0)
História do Pentium
O pessoal da ArsTechinica publicou um ótimo artigo sobre história do Pentium, sob o ponto de vista técnico e histórico. Bem interesante, principalmente para quem é interessado em arquitetura de computadores e tem curiosidade sobre o funcionamento de processadores.
Em 26/07/2004 13:13 - Comentários (0)
Lembra daquelas histórias de suporte?
Quem nunca juntou os amigos para tirar um sarro lembrando daquelas histórias de suporte e de perguntas estúpidas de usuários? Encontrei um site recheado dessas histórias. Olhe uma:
Cliente: "Eu quero meus CDs de volta."Suporte: "Seu CD está em um drive com defeito?"
Cliente: "Só um que não."
Suporte: "O que?"
Cliente: "Não é uma unidade 4x? Então, eu já coloquei 3 CDs, mas ele não aceita o quarto e nem devolve meus outros 3."
Em 29/07/2004 12:29 - Comentários (0)
10 ferramentas que todo programador .NET deve ter
Na MSDN Magazine desse mês, saiu um artigo sobre as 10 ferramentas que todo programador .NET deve ter. É um artigo bem resumido, mas que é legal para quem precisa somente das referências.
Como um continuação desse artigo, eu recomendo o livro Coder To Developer. É um livro curto (+-350 páginas) que explica um pouco da metotodologia por trás das ferramentas e fala sobre como fazer um software do início ao fim, do projeto ao setup.
Em 29/07/2004 13:08 - Comentários (1)
Por que os administradores de rede não se limitam a administrar a rede?
Era uma vez uma empresa. Era uma vez uma reunião entre os gerentes da área de desenvolvimento e os administradores de rede. Tudo corria bem na reunião, até que um administrador de rede diz a seguinte pérola:
- Estamos pensando em bloquear o MSN Messenger, porque ele acaba com a produtividade das pessoas.
Depois disso, o gerente de desenvolvimento tenta explicar que o MSN Messenger agiliza o trabalho, que ele gerencia pessoas que estão em outras unidades da empresa e que essa é uma forma ágil de comunicação, etc...
Agora, a pergunta: O que um administrador de rede entende de produtividade? Ele é um administrador de rede, um psicólogo ou um profissional de RH? Provavelmente, esse administrador de rede só usa o MSN Messenger para bater papo com os amiguinhos mesmo...
Em 29/07/2004 17:24 - Comentários (52)
"Windows Internals" no forno!
Hoje recebi a newsletter do site Sysinternals, dizendo que o Mark Russinovich e o Dave Solomon estão quase terminando o "Windows Internals", que é a próxima edição melhorada do Inside Windows 2000. Essa nova versão cobrirá as modificações feitas no kernel do Windows XP e 2003, e trará mais capítulos sobre resoluções de problemas e uso de dumps.
Em 30/07/2004 12:59 - Comentários (0)
C++: O esquecido operador vírgula
Um operador que é pouco usado, mas bastante útil em C++, é o operador vírgula. Resumidamente, ele avalia todas as instruções separadas pela vírgula, mas retorna sempre a última. Olhe um exemplo:
int a, b, c; b = 2; c = 3; a = (b,c);
Nesse caso, o valor da variável a será 3.
Uma das particularidades do operador vírgula, é que ele tem a menor precedência entre todos os operadores. Vamos tirar os parênteses:
int a, b, c; b = 2; c = 3; a = b,c;
Agora o valor da variável a será 2, já que pela precedência, a = b é a primeira expressão, e c é a segunda expressão.
Usos realmente úteis
O uso mais comum para o operador vírgula é inicializar mais de uma variável em um loop, como no exemplo abaixo:
int b,c; for(int a = 10, b = 20, c = 30 ; a < 10 ; a += --b, c++) { }
Nesse caso, nós declaramos a variável a e atribuímos o valor 20 à variável b.
Outro ótimo uso do operador vírgula é para fazer validação de casts não seguros. Existem lugares onde, apesar do parâmetro ser do tipo void* ou void**, você sempre deve passar um tipo determinado. Um exemplo clássico, é a função CoCreateInstance, que tem a seguinte assinatura:
STDAPI CoCreateInstance( REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID * ppv );
O último parâmetro, apesar de ser LPVOID* (ou seja, void**), espera um tipo definido. Ele quer um ponteiro para um ponteiro que possa ser convertido para IUnknown*.
Olhe o código a seguir, que tem um dos erros mais comuns em programação COM:
HRESULT hr; IUnknown* pUnk; hr = CoCreateInstance(CLSID_BLA, NULL, CLSCTX_ALL, IID_IUNKNOWN, (void**)pUnk);
Encontrou o erro? Na realidade, &pUnk deveria ser passado, e não somente pUnk como foi passado. Com isso você vai ganhar um belo GPF de presente. Como estamos usando cast C, o compilador não reclama, e nosso código é compilado sem problemas. E aqui não podemos usar static_cast, porque IUnknown** não pode ser convertido para void**.
Vamos agora a uma solução usando o operador vírgula e uma macro:
HRESULT hr; IUnknown* pUnk; // // IC = interface cast // #define IC(ppUnk) (static_cast(*ppUnk),(void**)ppUnk) hr = CoCreateInstance(CLSID_BLA, NULL, CLSCTX_ALL, IID_IUNKNOWN, IC(&pUnk));
O que fizemos aqui foi o seguinte: a macro primeiro checa se o apontado do que foi passado pode ser convertido para IUnknown*, usando static_cast. Essa primeira expressão (static_cast(*ppUnk)) vai verificar a validade do ponteiro em tempo de compilação, mas não surtirá nenhum efeito em tempo de execução. A segunda expressão ((void**)ppUnk) fará então o cast que deve ser feito para a chamada da função. Vamos agora tentar compilar com o mesmo erro do primeiro exemplo:
HRESULT hr; IUnknown* pUnk; #define IC(ppUnk) (static_cast(*ppUnk),(void**)ppUnk) hr = CoCreateInstance(CLSID_BLA, NULL, CLSCTX_ALL, IID_IUNKNOWN, IC(pUnk)); ----------------------------------- error C2440: 'static_cast' : cannot convert from 'IUnknown' to 'IUnknown *' No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
E como todo ponteiro para interface COM pode ser convertido para IUnknown*, resolvemos nosso problema.
Se você quiser mais informações sobre verificações em tempo de compilação e códigos nesse estilo, procure sobre metaprogramming e estude muito, mas muito mesmo sobre templates.
Em 30/07/2004 13:57 - Comentários (0)
Iniciando o desenvolvimento básico de drivers
Pois é, o pessoal da Microsoft resolveu retirar o desenvolvimento de drivers do ostracismo. Republicaram o artigo "How to develop a Windows Driver". Um artigo bem curto, que fala o básico sobre desenvolvimento de drivers: arrumar uma cópia do DDK, usar o checked build, compilar usando o BUILD, e, é claro, certificar seu driver junto à Microsoft.
Em 31/07/2004 21:40 - Comentários (0)
Dicas para particionamento e organização do HD, parte 1
Eu tenho visto por aí muita gente com HDs gigantescos, todos com uma partição só. Apesar de isso não causar problemas no uso diário, um melhor particionamento pode ajudar bastante quem precisa de performance e organização. Por isso eu resolvi escrever alguma coisa sobre isso. Se ficar bom, talvez eu coloque mais água no feijão e transforme isso em um artigo. (Antes eu tenho que terminar o WinDbg parte 3).
Dica 1: nunca crie somente uma partição
A primeira dica é a mais simples. Qual o motivo? Com uma partição só, fica mais difícil organizar suas coisas e mais difícil de fazer backup e seu HD fica mais fragmentado.
Crie no mínimo duas partições, uma para o sistema operacional e para os programas, e outra para os seus dados. Instale o sistema operacional e os programas que você mais usa na primeira partição e desfragmente a partição. Guarde seus dados na outra partição.
Dica 2: Mude as pastas padrão para o "Meus Documentos", "Favoritos", etc
Por padrão, o Windows coloca a pasta "My Documents" em "c:\Documents And Settings\[username]\My Documents". Isso torna infernal o processo de backup, já que se você usar xcopy para fazer backup você terá que digitar esse caminho imenso ou colocá-lo no .BAT.
Resolva o problema: baixe o TweakUI no site da Microsoft, entre em My Computer >> Special Folders e saia mudando. Mude o "My Documents" para algo como "d:\rodrigo" e "My music" para algo como "d:\mp3". Mude também a localização do "Desktop" para dentro de "My Documents", como "d:\rodrigo\desktop". Menos uma pasta separada para você lembrar na hora do backup. E a pasta do desktop é a mais fácil de esquecer na hora do backup.
Use sempre nomes fáceis para as pastas, e as coloque na partição de dados. Assim, você pode programar o backup para copiar todas essas pastas, que são mais fáceis de lembrar. Um dia você vai decidir formatar o HD, e assim ficará mais fácil lembrar o que copiar, e você terá menos medo na hora de escolher a opção "Yes, format my entire HD now!".
Dica 3: Faça backup, faça backup, faça backup, faça backup, faça backup, faça backup, faça backup
Nunca é suficiente dizer. As pessoas geralmente só lembram do backup quando alguma desgraça acontece. O backup não precisa ser em uma fita DAT com um software de milhares de dólares. Um simples arquivo RAR ou ZIP com seus arquivos mais importantes enviado para um disco virtual já resolve o problema. Você pode fazer o backup dos seus documentos uma vez por semana, e das mp3 a cada mês. O importante é que você faça isso regularmente.
Dica 4: Teste o backup!
Já vi o caso de uma empresa que fazia o backup regularmente, mas nunca testou se o backup era restaurado corretamente. Adivinhe o que aconteceu na hora de restaurar o backup? Você pode esquecer de configurar a ferramenta de backup para incluir as subpastas. Erros simples como esse se tornarão catastróficos na hora que você precisar do backup.
Futuramente...
Diferenças entre NTFS e FAT32, qual tipo usar em que caso, usando 3 ou mais partições
Veja também
Dicas para particionamento e organização do HD, parte 2Dicas para particionamento e organização do HD, parte 3
Verdades e mitos sobre NTFS e FAT
Em 03/08/2004 01:14 - Comentários (1)
C++: a linguagem mais poderosa para programação .NET
O artigo C++: The Most Powerful Language for .NET Framework Programming só ajuda a confirmar a minha opinião de que, com as novas managed extensions incluídas no Visual C++ 8.0 (Visual Studio 2005), eu nunca terei que usar outra linguagem para programar em .NET.
Continuarei com os templates, com o pré-processador, com o otimizador, com a possibilidade de usar API Win32 sem precisar usar DllImport (que é o Declare do VB6, nada mais, nada menos), possibilidade de alocar objetos na pilha, etc. Sem contar o gerenciamento de projeto, build steps, opções para configurar compilador e linker, o respeito que a Microsoft tem com programadores Visual C++, etc.
Ah, e é claro, o fato de que a integração de controle de versão (Source Safe, Clear Case) funciona com o Visual C++ e NÃO FUNCIONA com VB.NET.
Em 04/08/2004 12:27 - Comentários (0)
Porque programar drivers (kernel mode) é mais legal do que programar aplicativos (user mode)
- Você está dentro do kernel do sistema.
- Você precisa de um bom conhecimento da arquitetura do kernel do Windows. Isso torna você um melhor programador user mode.
- Programação em kernel mode é algo crítico. O BUILD configura o compilador C para tratar warnings como errors.
- Você não pode errar. Um simples GPF ou divisão por zero é tela azul na hora!
- Em kernel mode você é obrigado a usar seus conhecimentos de ciências da computação: arquitetura de computadores, listas ligadas, etc.
- Os samples do DDK (Driver Development Kit) são mais bem organizados e mais bem comentados do que os samples de user mode. O código também é muito mais bonito. :-)
- A API do kernel do Windows (Native API) é muita mais concisa e bem organizada do que a Win32 e algumas partes do .NET Framework.
- Não existe programação para banco de dados em kernel mode. Nada de VB, nada de ADO.NET, nada de DataAdapter, nada de SQL, nada de fazer procedures. Praticamente o paraíso... :-)
- Em kernel mode, você só pode usar Assembly, C ou C++. E muitos programadores pregam que você use somente C.
- Temos ferramentas como o Driver Verifier e o Windows Checked Build para verificar se estamos fazendo tudo OK. Hoje temos o Application Verifier para user mode, mas isso é novo e quase ninguém conhece. O pessoal que programa em kernel mode (pelo menos os que sabem o que estão fazendo) usa o Driver Verifier sempre.
- Especialização. Poucas pessoas programam em kernel mode.
Em 04/08/2004 23:46 - Comentários (0)
Depois dizem que computação é uma ciência exata
Eu ainda vivo na idade da pedra, e como tal, minha câmera fotográfica não é digital. Tirei umas fotos na semana passada e decidi tirar meu scanner da caixa para enviar algumas fotos para os amigos.
Meu scanner (que eu saiba) não tem driver para Windows XP, somente para Windows 2000. Fácil: pego a VMWare com Windows 2000 que eu uso pra fazer debug dos drivers que eu faço, instalo o scanner, software do scanner e pronto. Isso é o que eu pensava em minha vã inocência.
Subi a VMware e espetei o scanner na USB. O Windows XP reconheceu o "VMWare USB Device" e cinco segundos depois meu micro reinicia. Antes de xingar o scanner ou qualquer outra coisa, eu pensei como eu sou estúpido por não ter configurado o Windows para não reiniciar automaticamente depois de um BugCheck (tela azul) e para fazer o dump completo.
Com o micro reiniciado, configurei tudo, subi a VMware e espetei o scanner. Como esperado, tela azul de novo, e 5 minutos depois eu tinha o dump. Reiniciei o micro novamente e abri o dump no WinDbg para descobrir quem eu deveria xingar: a VMware, a Microsoft ou a Genius, fabricante do scanner.
Esperei uns 20 minutos até o WinDbg baixar os symbols para os drivers da minha máquina. Uma longa espera para alguém que só que encontrar um culpado. Consegui ver que algum driver tentou liberar memória duas vezes e disparou um BAD_POOL_CALLER. Quando vou olhar qual foi o driver que fez a besteira, tive uma infeliz surpresa: foi o firewall (Tiny Personal Firewall)...
Isso siginifica que o driver está fazendo hook do que não deve, até porque o TCPIP.SYS nem estava na pilha. Ou eu arrumo um outro firewall ou termino logo o meu...
Depois que você descobre como são feitas as salsichas, o molho de tomate e os drivers de antivírus com "real time scan", seus hábitos mudam bastante... :-)
Em 05/08/2004 14:06 - Comentários (1)
Visual C++ 2005 Managed Extensions: o início
Hoje eu resolvi fazer minhas primeiras experiências com Managed C++ 2005, para ver se é realmente simples como eu acredito que seja. Minha primeira experiência ridícula, serve para ilustrar como a compilação é quase tão simples como C# ou VB.NET.
Código fonte
int Main() { System::String^ str; str = L"Eu queria estar na praia"; System::Console::WriteLine(str); return 0; }
A compilação
cl mcpp1.cpp /clr:pure /link /entry:"Main" /subsystem:console Microsoft (R) C/C++ Optimizing Compiler Version 14.00.40607.16 for Microsoft (R) .NET Framework version 2.00.40607.16 Copyright (C) Microsoft Corporation. All rights reserved. mcpp1.cpp Microsoft (R) Incremental Linker Version 8.00.40607.16 Copyright (C) Microsoft Corporation. All rights reserved. /out:mcpp1.exe /clrimagetype:pure /entry:Main /subsystem:console mcpp1.obj
O resultado
Eu queria estar na praia
Simples, rápido e fácil. Agora eu tenho um autêntico e legítimo executável 100% managed para ser consumido pelo .NET Framework 2.0 beta 1. Agora é só esperar terminar o download do SDK do framework 2.0, e usar o ildasm para ver se está realmente tudo OK.
Mas, na verdade, eu gostaria de estar na praia.
Em 06/08/2004 17:42 - Comentários (0)
Como usar o Visual C++ 2005 Express para fazer programas SUBSYSTEM:Windows
No artigo sobre WinDbg, eu disse que caso o leitor não tivesse o Visual C++, ele poderia baixar o Visual C++ 2005 Express e o Platform SDK para fazer programas Windows. Agora eu vou explicar os passos necessários para isso.
1. Baixe o Visual C++ Express 2005.
2. Instale o Microsoft Platform SDK via web. Instale somente o [Core SDK >> Build Environment] e o [Internet Development SDK >> Build Environment]. Infelizmente, mas infelizmente mesmo, não é possível usar o Firefox para fazer a instalação, só Internet Explorer mesmo. (igual ao novo site da MSDN brasileira... shame...).
3. Agora vamos configurar o Visual C++. Menu "Tools" >> "Options". No TreeView, "Projects And Solutions" >> "VC++ Directories". Depois, no ComboBox "Show Directories for:" insira Program Files\Microsoft SDK\include em "Include Files" e Program Files\Microsoft SDK\lib em "Library Files".
4. Reinicie o Visual C++ 2005 Express
Para testar, abra o Visual C++ e crie um novo projeto "Win32" >> "Console Application" (é isso mesmo, console application). Quando abrir a tela com as configurações do novo projeto, escolha "Windows Application". Caso você tente compilar o projeto, verá vários erros de linker, já que o projeto não está configurado para fazer link com as libs das dlls Win32.
Agora vamos arrumar o problema do linker: entre nas propriedades do projeto, "Configuration Properties" >> "Linker" >> "Input". Em "Additional Dependencies", coloque "kernel32.lib user32.lib gdi32.lib" (assim mesmo, separadas por espaços). Isso deve ser feito em todos os projetos Win32.
Pronto. Agora divirta-se!
Em 09/08/2004 11:53 - Comentários (0)
Depois da praia, vamos nos purificar
No meu post de sexta-feita, eu usei o parâmetro de linha de comando "/clr:pure" para compilar o meu "Eu gostaria de estar na praia" (convenhamos que é melhor do que Hello World...). Agora que eu terminei de baixar o .NET Framwork SDK 2.0, usei o ildasm para verificar o código gerado. Olha o que temos:

Reconhecemos as seções do executável e várias funções da runtime do C/C++. Isso pode deixar um programador purista triste, já que carregamos algumas coisas que são do velho Visual C++.
Agora vamos mudar o parâmetro para "/clr:safe". Olhe o que temos agora:

Agora sim, um executável .NET puro, suficiente para agradar os puristas. Lembre-se que usando "/clr:safe", não podemos usar nada que não seja seguro e verificável pela runtime. Um simples "#include
Em 09/08/2004 19:41 - Comentários (0)
PREFAST rocks!
Para quem não sabe, o Prefast é um analisador estático de código fonte, que vem junto com o DDK do Windows Server 2003. Ele foi feito para pegar erros de lógica, que o compilador não pega. Olhe esse código:
NTSTATUS s; IO_STACK_LOCATION* pIrpSp; pIrpSp = IoGetCurrentIrpStackLocation(Irp); ... switch(pIrpSp->MinorFunction) { case FUNC1: s = OnConnect(DeviceObject,Irp,NextDevice); break; case FUNC2: OnDisconnect(DeviceObject,Irp,NextDevice); break; default: IoSkipCurrentIrpStackLocation(Irp); s = IoCallDriver(NextDevice,Irp); } return s;
Achou o erro? O PREFAST achou. Olhe o log dele:
dispatch.cpp(197) : warning 1: Using uninitialized memory 's'. problem occurs in function 'OnDeviceInternalIoControl' Path includes 6 statements on the following lines: 177 178 180 182 189 197
A linha 197 é a que chama "OnDisconnect". Repare bem que o retorno dessa função não é atribuído à variável s. Caso o valor de "pIrpSp->MinorFunction" seja "FUNC2", a variável s nunca seria inicializada, e minha função retornaria o lixo que estivesse na pilha.
Em 12/08/2004 23:22 - Comentários (0)
Computação não é uma ciência exata, parte 2
Passei quinta e sexta da semana passada fazendo um dos serviços mais enfadonhos que um programador pode fazer: documentar um sistema que nem fui eu que criei. É quase uma tortura passar o dia inteiro com o Word aberto e com o Visual Studio fechado...
Estava eu terminando a documentação, quando enrosquei o pé no cabo de força do estabilizador e tudo apagou. É claro que eu nem tinha salvo a documentação, já que eu deixo meu micro em "hibernation" todo dia e o Word 2003 tem os recursos de recuperação de documentos e salvamento automático. Despreocupado, liguei o micro novamente e abri o Word na esperança de ver meu documento lá, do jeito que estava antes da infeliz fatalidade.
Pois é, ele não estava lá. Procurei os ~*.doc nos temporários do Windows e nada. Acredito que eu nem preciso descrever meu desespero, já que fazer documentação uma vez é enfadonho, e fazer duas vezes é torturante.
Sem mais opções, recomecei a escrever a documentação, e lembrei que o Word 2003 é o primeira versão que eu encontrei bugs, principalmente de redesenho de tela. Eu uso o Word desde a versão 6.0 para Windows 3.11, e nunca encontrei nenhum problema. Até aparecer o Word 2003. O pior não é o bug do redesenho, e sim o que me fez perder o documento, mesmo com a opção de salvamento automático ativada.
Passou o fim de semana, terminei minha segunda versão da documentação, e resolvi instalar o Service Pack 1 do Office 2003. Perguntei a um amigo se esse Service Pack solicitava o CD durante a instalação, porque todos os updates do Office que eu vi até hoje pediam. Ele me disse que no micro dele e de um outro amigo nosso, o Windows Installer não pediu o CD. Então, eu resolvi arriscar.
É claro que ele pediu o CD, e é claro que o CD do Office estava na sede da empresa, e não onde estou prestando consultoria. Afinal, é para isso que serve a Lei de Murphy.
Cancelei a instalação, fiquei assistindo a barra de progresso do Windows Installer retroceder enquanto eu torcia para que meu Office continuasse funcionando, para que eu não precisasse esperar que alguma boa alma me trouxesse o CD do Office ou que eu tivesse que fazer o download da MSDN.
Depois de cancelar o update, abri o Word para testar se tudo estava funcionando. Apareceu a tela do Windows Installer esperada, algumas dezenas de segundos e pronto, lá estava o Word aberto, COM O MEU DOCUMENTO PERDIDO SEMANA PASSADA RECUPERADO
Em 19/08/2004 02:01 - Comentários (0)
Por que você programa?
Tentando encontrar uma forma de explicar para um entrevistador como eu sou fascinado por programação sem parecer mentiroso ou artificial, eu me lembrei de uma coisa que li a muito tempo atrás: "Why Do You Code?".
Precisa existir algum motivo lógico? No meu caso é simplesmente inexplicável, quase uma doença. Caso alguém queira tentar fazer um diagnóstico, vou enumerar alguns sintomas:
- Meu micro tem 512MB de RAM e uma Geforce FX 5200 128MB. Eu até fico feliz que minha máquina rode Doom3 numa velocidade razoável, mas esse não é motivo da minha felicidade. Eu fico feliz porque posso abrir duas máquinas virtuais, o Visual Studio.NET, a MSDN, o Firefox com milhares de tabs e o WinDbg ao mesmo tempo.
- Eu trabalho com programação o dia inteiro. Sabe o que eu faço pra me divertir quando chego em casa? Abro meu Visual C++ e trabalho em um software que eu estou fazendo a 10 meses, envolvendo computação distribuída e device drivers. Ou seja, continuo programando e estudando.
- Fico feliz pelo fato da minha HD ter 120GB. Assim eu posso instalar sem preocupação a MSDN, o DDK, o Platform SDK, o Visual Studio 6, o Visual Studio.NET, posso baixar milhares de fontes do Source Forge, criar várias máquinas virtuais para testar softwares como o Visual Studio 2005, Yukon e sistemas operacionais, posso instalar Linux ou até mesmo o Longhorn em outra partição, etc, etc.
- Fico feliz por ganhar um salário bom. Assim eu posso gastar dinheiro comprando mais livros sobre programação todo mês na Amazon.
- Se hoje eu tenho um bom conhecimento de inglês, é de tanto ler livros sobre programação e aperfeiçoar o inglês para estudar mais sobre programação e para trabalhar em projetos envolvendo programação no exterior. Um dia um amigo me disse que queria virar programador e perguntou por onde começar. Eu disse para começar estudando inglês.
Essa matéria que eu citei conta a história de um sujeito que queria aprender a programar mas não tinha micro, só uma WebTV (um finado aparelho no qual você podia navegar pela web com sérias limitações e enviar/receber e-mails ligando o aparelho à linha telefonica e à TV, quase um TK90X). Então ele escrevia os fontes C em um e-mail, e enviava para um amigo que tinha computador. Esse amigo compilava e mandava os erros de volta. Assim ele começou a programar.
Esse sujeito parece maluco? Pois é, mas eu comecei mais ou menos assim. Eu aprendi a programar com 12 anos, quando minha mâe trabalhava na UNESP de Botucatu e eu resolvi fuçar em computadores no polo computacional de lá. Depois eu resolvi pegar uns livros para ler. O que você faria se visse um garoto de 12 anos de idade na biblioteca da sua faculdade procurando livros de programação? Hoje eu fico imaginando como devia ser estranho...
Então eu peguei um livro de BASIC e comecei a programar em GW-BASIC usando os micro de lá. Mas eu não tinha micro em casa, não podia programar sempre. Não demorou muito tempo para que eu começasse a escrever programas em um caderno, na minha casa. Eu tinha 12 anos de idade...
Tem alguma explicação para isso? Existem pessoas que programam para viver, e pessoas que vivem para programar. Eu me encaixo na segunda categoria, e conheço algumas pessoas assim.
Por que eu programo? Sinceramente, eu não sei explicar. Só espero que o entrevistador entenda...
Em 19/08/2004 03:18 - Comentários (27)
Planeta C++
O criador do C++ (Bjarne Stroustrup) mantém uma pequena lista dos softwares que foram feitos usando C++. Acredito que mais de 95% dos softwares que rodam em plataforma Windows são feitos em C e C++. Não sei se existe uma estatística oficial sobre isso, mas a esmagadora maioria dos software conhecidos são feitos em C ou C++.
Para as pessoas que trabalham diretamente com C ou C++ isso parece óbvio, mas como no Brasil pouca gente trabalha com isso, esse post deve trazer a resposta para a pergunta que os programadores VB e Java nunca pararam para fazer.
Não se esqueçam de olhar o item "Microsoft".
Em 19/08/2004 15:34 - Comentários (4)
Diversão para programadores de drivers
Muito melhor do que jogar paciência, é fazer as palavras cruzadas da OSR e testar seu conhecimentos sobre desenvolvimento de drivers para Windows. Alguém poderia providenciar mais alguns desses sobre Win32 e C++. E talvez até .NET... :-)
Além disso, eles publicaram um artigo interessante sobre como trocar os arquivos do Windows (sem que o Windows File Protection coloque os originais de volta) usando os recursos nativos do kernel debugger. Por exemplo, o IFS Kit (usado para fazer drivers de file system) vem com os fontes do fastfat.sys, que é o driver do sistema de arquivos FAT (sim, o mesmo do Windows, feito pelo Gary Kimura). É interessante compilá-lo em modo checked e substituir o do Windows para ver como funciona, mas o WFP não deixa que você troque o arquivo. Existem algumas gambiarras possíveis, como editar uma DLL do Windows usando um editor hexadecimal, mas até eu que estou acostumado a fazer uns patches no kernel do Windows usando o WinDbg acho isso um pouco de exagero...
Em 25/08/2004 12:43 - Comentários (3)
Dicas para particionamento e organização do HD, parte 2
Nessa segunda parte, darei uma pequena explicação do sistema de arquivos FAT. Depois faremos uma comparação entre FAT e NTFS para podermos decidir qual tipo é melhor para qual finalidade.
FAT é um sistema de arquivos que foi criado na década de 80, originalmente para ser usado em disquetes. Foi o sistema de arquivos padrão da Microsoft desde as primeiras versões do MS-DOS, e continua sendo o mais utilizado até hoje, sendo suportado pelas últimas versões do Windows (XP, Server 2003 e Longhorn) e por diversos outros sistemas operacionas, como Linux e OS/2.
Primeiro vamos resumir a história do FAT:- FAT12: Primeira versão, foi projetada para disquetes. Nomes de arquivo no formato 8.3. O "12" vem do número de bits usados para numerar os clusters;
- FAT16: Com o aparecimento dos primeiros HDs (naquele tempo alguns chamavam de "Winchester", lembram?), o FAT12 não era mais suficiente. Aumentaram então o número de clusters para 16 bits;
- VFAT: Com o surgimento do Windows 95, a Microsoft queria suportar nomes de arquivos longos, como no OS/2 (que usava HPFS). Então foi feita uma adaptação no FAT para ele suportasse nomes longos e ainda ficasse compatível com os aplicativos antigos;
- FAT32: Com o surgimento dos HDs maiores, o tamanho máximo de 2GB para um partição FAT16 tornou-se uma limitação crítica. Então o número de clusters foi aumentado para 32 bits. Apesar de resolver o problema, o novo sistema de arquivos não era compatível com os sistemas operacionais mais antigos. O Windows NT4, por exemplo, não suporta FAT32 nativamente. O FAT32 também suporta nomes longos, assim como o VFAT (não sei se podemos chamar de VFAT32...).
Por ser um sistema de arquivos antigo, muitas das funcionalidades presentes nos sistemas de arquivos mais modernos não estão disponíveis. Para facilitar, vou enumerar as vantagens e desvantagens do FAT32:
Vantagens:
- Como a estrutura é simples, o acesso aos arquivos é rápido;
- É compatível com praticamente todos os sistemas operacionais, como Windows 98, Windows NT 4, Linux, OS/2, etc.
Desvantagens:
- Não tem recursos de segurança. Não permite que o usuário ou administrador limite o acesso de determinados arquivos a determinados usuários;
- O controle anti falhas é muito simples e pouco eficiente. O FAT usa como sistema de segurança para corrompimento dos metadados uma cópia backup da tabela de alocação. Isso já se mostrou ineficiente. Uma simples queda de energia durante uma operação que modifique os metadados pode tornar a partição inacessível.
Em todas as comparações que eu fizer daqui para frente, somente o FAT32 será considerado. O FAT16 tem a limitação de 2GB no tamanho da partição, motivo suficiente para ser desconsiderado.
Na terceira parte eu descreverei o NTFS.
Veja também
Dicas para particionamento e organização do HD, parte 1Dicas para particionamento e organização do HD, parte 3
Verdades e mitos sobre NTFS e FAT
Em 26/08/2004 17:47 - Comentários (0)
Notícias do Windows Longhorn
Microsoft decide que o WinFS não fará parte do Longhorn e que o WinFX, Avalon e Indigo serão disponibilizados para Windows XP e 2003. Acho que isso vai dar muito o que falar. Fico feliz que o "Raymond Chen camp" venceu mais uma, mas acho que a situação vai ficar bem complicada. .NET Framework 2.0 + WinFX + Avalon + Indigo, imaginem só o tamanho do download de tudo isso. Mas isso me faz pensar em algumas coisas:
- Já era sabido que o Indigo seria portado, isso só foi colocado no mesmo pacote de divulgação;
- Se o Avalon vai ser portável para Windows XP, isso quer dizer que não será possível muita dependência do Avalon em relação ao kernel e ao DirectX, a não ser que ele faça parte de um Service Pack (o que eu duvido que aconteça). Eu acho o managed code lento pra manipulação de gráficos. Mas isso poderia ser resolvido no Longhorn, atrelando o Avalon diretamente com o DirectX. Assim a maioria do trabalho seria feito em kernel mode, o que diminuiria a quantidade de trabalho feito em managed code;
- Acho que isso tende a deixar as APIs managed bastante atreladas ao Win32, a não ser que a Microsoft faça do WinFX um subsystem separado. Acredito que um subsystem managed para user mode, contando com boa parte da implementação em kernel mode apoiado em DirectX iria ficar muito interessante e com um desempenho muito bom. Mas não acho que a Microsoft vá por esse lado (não testei o Longhorn ainda), porque isso tornaria difícil manter a compatibilidade e fazer a integração com o Win32, já que o WinFX estaria fora do win32k.sys;
- Mais uma vez o Bill Gates terá seu tão sonhado sistema de arquivos adiado... Mais uma vez...
- Não teremos nenhuma revolução como a Microsoft diz, mas sim uma evolução. Avalon será a [GDI+++ + DirectX], Indigo o Remoting/SOAP vitaminado, e o WinFX será um WinForms 3.0. Ainda muito bom, mas sem o exagero característico do pessoal de marketing da MS.
[editado em 10/09/2003. "WinFX será um WinForms 2.0" >> "WinFX será um WinForms 3.0"]
Em 30/08/2004 02:43 - Comentários (0)
Como sempre, Carmack nos surpreende
Existe uma palavra que define Doom3: medo. Além dos gráficos muito bons, que todo mundo fala, o enredo e ambiente do jogo também são ótimos. O jogo realmente dá medo, e eu não consigo jogar mais de uma hora por causa da tensão. John Carmack mais uma vez prova que continua sendo um gênio.
Agora vou ler um livro para me acalmar depois de uma sessão de Doom3...
Em 11/09/2004 01:31 - Comentários (0)
Dicas para particionamento e organização do HD, parte 3
Como prometido, agora na terceira parte vou explicar um pouco sobre NTFS. Acho desnecessário dizer, mas isso é só o básico sobre os sistemas de arquivos. Caso você precise de maiores detalhes, procure a especificação ou maiores informações na web.
O NTFS (NT File System) foi criado especialmente para o Windows NT, logo na sua primeira versão. Houve uma grande discussão durante o projeto do Windows NT sobre a viabilidade de criar-se um novo sistema de arquivos ou usar/adaptar um existente na época, como o FAT ou o HPFS. Sabemos hoje a decisão que foi tomada.
Os únicos sistemas operacionais realmente compatíveis com NTFS são os da linha Windows NT: Windows NT 3.x, Windows NT 4.0, Windows 2000 (5.0), Windows XP (5.1), Windows Server 2003 (5.2) e a próxima versão, ainda em alfa, Windows Longhorn (6.0). Existem drivers para Linux, mas somente readonly. Para Windows 9x existe o NTFS for Windows 98 dos nossos geniais amigos da SysInternals, que usa os drivers do Windows NT para acessar as partições NTFS.
Vamos às vantagens e desvantagens do NTFS.
Vantagens:
- NTFS possui journaling, que controla todas as modificações nos metadados da partição. Os metadados são as informações de como e onde estão os dados e os arquivos na partição. Todas as modificações são gravadas em um log ANTES de serem efetuadas. Assim, caso um problema (como queda de energia) aconteça durante a gravação, é possível terminar ou reverter a operação na próxima vez que o computador for ligado. Note que isso garante a integridade da partição, mas não a integridade dos dados. O controle de dados é deixado por conta da aplicação. Os bancos de dados (como SQL Server ou Oracle) fazem controle de integridade de dados;
- Possui suporte a metadados para os arquivos e pastas, o que permite, entre outras coisas, que as informações de permissão do arquivo sejam gravadas diretamente na partição. Por isso que você consegue determinar permissões de acesso em uma partição NTFS, e não em uma partição FAT (usando Windows NT/2000/XP, é claro);
- Possui suporte a streams alternativas. Além de gravar no arquivo, você pode criar um novo fluxo de dados para o arquivo e gravar informações separadamente. Isso permite, por exemplo, que você mantenha diferentes versões dos dados do arquivo em streams diferentes;
- Tem menos problemas com fragmentação do que o FAT;
- Possui suporte nativo a criptografia e compactação (a partir do Windows 2000).
Desvantagens:
- Só é 100% compatível com o Windows NT/2000/XP.
(tentei encontrar mais desvantagens, mas não achei. Existem boatos de que FAT é mais rápido do que NTFS, mas não achei nenhum estudo realmente conclusivo sobre isso)
Veja também
Dicas para particionamento e organização do HD, parte 1Dicas para particionamento e organização do HD, parte 2
Verdades e mitos sobre NTFS e FAT
Em 13/09/2004 00:43 - Comentários (2)
Pode acontecer algum dia, em algum computador

Se ao invés de linguas nórdicas, o Raymond Chen estivesse estudando português, e ele por acaso lesse meu weblog, ele ficaria muito bravo... :-)
Em 13/09/2004 00:51 - Comentários (0)
Parece brincadeira, mas a Microsoft fez
Parece brincadeira, mas um dia depois de escrever o post tirando sarro do Windows Me ("Pode acontecer algum dia, em algum computador"), com uma mensagem que pouco provavelmente apareceria em um software comercial, encontrei essa mensagem no Microsoft Word 2003:

Essa mensagem estaria correta se eu não tivesse um browser instalado. Mas o detalhe é que o link que eu cliquei ("More information about this error message online") foi aberto no Firefox, que é meu browser padrão...
Além disso, o Office 2003 só roda em Windows 2000 ou superior, o que descarta a possibilidade de não haver um browser instalado.
Em 14/09/2004 03:27 - Comentários (0)
Mais uma mudança de paradigma
Quando eu comecei a acessar a Internet, em 1997, uma das primeiras coisas que você aprendia era que você deveria ser sempre anônimo. Além dos nicks para os chats, a grande maioria das pessoas tinham um e-mail com nick. Eu lembro de um colunista de uma conceituada revista de informática dizer que criar um e-mail com o próprio nome ou sobrenome era uma falta de criatividade. Hoje sabemos que isso não passa de estupidez.
Um fenômeno que eu estou percebendo de um tempo para cá é que as pessoas estão perdendo o medo da Internet, e ela está se tornando menos anônima.
Primeiros foram as páginas pessoais (faz tempo...). Todo mundo queria ter uma página pessoal, mesmo as pessoas que não tinham muito a dizer. Nem que fosse para colocar quais eram seus passatempos prediletos e onde você mora. Mas as pessoas eram receosas em colocar o nome completo ou mesmo uma foto, afinal, alguém poderia usar essas informações para fins ilegais. Lá as pessoas diziam o primeiro nome e do que gostavam.
Depois, bem depois, vieram os blogs. Além das pessoas colocarem suas preferências na rede, agora as pessoas colocam seu diário e sua opinião pessoal também. A nova mania são os fotoblogs, onde as pessoas colocam fotos em todas as situações possíveis e imagináveis. Agora as pessoas publicam sua rotina, com nome, sobrenome, e muitas fotos.
E agora, o Orkut. Lá você coloca nome, sobrenome, fotos e ainda diz quem é ou não é seu amigo. As pessoas participam de fóruns e discutem diversos assuntos (de sexo a bons bares para tomar chope alemão) com o nome estampado e um link para um profile quase sempre bem detalhado. Agora além de tudo isso, você diz quem são seus amigos, discute suas preferências e gostos abertamente. Coisa que muitas pessoas não fazem nem com os amigos no mundo real. Deixamos de ser anônimos, mas ainda usamos o fato de estar por trás de um computador para dizer coisas que não diríamos em outra situação.
E ultimamente, tenho visto que as pessoas entram em fórums de discussão usando o próprio nome e colocando um foto verdadeira como avatar. No MSN isso também tem sido mais constante.
Eu fico me perguntando o que virá depois...
Em 15/09/2004 01:46 - Comentários (0)
Somos todos estranhos
Lendo o blog do Raymond Chen, como faço todos os dias, encontrei um post muito interessante, comparando a arquitetura x86 com as demais arquiteturas disponíveis no mercado. Nesse post ele fala sobre as características da arquitetura x86, e que muitas delas não são encontradas em outras arquiteturas (como PPC, MIPS, Alpha e ia64). Como estamos acostumados com a arquitetura do x86, parece que essas arquiteturas são estranhas e exóticas. Mas não são.
Olhando a lista resumida do Raymond, vemos que a arquitetura x86 é limitada, por manter compatibilidade desde o 8086 (PC XT). E vemos também que a nova arquitetura da Intel, a ia64, agora compartilha diversas características com as outras arquiteturas. Inclusive algo que em termos de performance chega a ser óbvio, que é colocar os parâmetros em registradores, e não na pilha. Existe, dois artigos interessante sobre arquitetura ia64 na MSDN Magazine (aqui e aqui)
Mais uma prova de que nem sempre o melhor produto é o que ganha o mercado. O padrão Beta sempre foi melhor do que o VHS, mas ninguém usa. Essas outras arquiteturas são bem melhores que o x86, mas ninguém usa (em desktops).
Em 16/09/2004 14:17 - Comentários (0)
A um ano atrás eu teria orgulho disso, mas hoje...
São Paulo será a 2ª maior cidade do mundo em 2005
Em 16/09/2004 17:52 - Comentários (0)
Minha opinião sobre open source e o governo
Eu sou um programador que trabalha com tecnologia Microsoft. Uso Visual C++, C#. VB, SQL Server, etc. Gosto bastante dos softwares da Microsoft e o método que eles usam para desenvolvê-los. Mas não sou um defensor ferrenho da Microsoft. Existem alguns produtos deles que são ruins, eles tomam decisões erradas e têm algumas posições políticas pouco recomendáveis.
Como todo programador C/C++, sou bastante interessado pelo Linux. Programo em PHP e estou aprendendo Qt/GTK e Mono. Acho muito interessante que ele seja desenvolvido por programadores voluntários, que seja livre e com o código aberto. Mas eu não me importo muito com a ideologia do Linux. Eu tento julgá-lo pela qualidade, e não pelo puritanismo de usar Linux só pelo fato de não ser proprietário ou coisas assim. As empresas gastam dinheiro para desenvolver produtos e vendê-los. E eles querem garantir o direito deles a essa invenção/criação/descoberta usando patentes e coisas assim. Isso é absolutamente normal. (O sistema de patentes norte-americano é ruim e anormal, mas não vou falar disso agora). O software pode ser livre, mas a grande maioria dos outros bens de consumo (considerando que software é um bem) não são.
Eu sou contra a preferência do governo por software livre. E sou absolutamente contra a existência de qualquer lei nesse sentido, porque isso acaba com a concorrência. O critério para escolha de software pelo poder público deve ser o mesmo critério que ele usa para qualquer coisa que compra: preço e qualidade, custo e benefício. Ele não deve se prender a uma determinada "origem", seja ela o pessoal do open source, a Microsoft, a IBM ou qualquer outra empresa.
Além disso, com essa lei, o governo somente deixará de comprar serviços de algumas empresas para comprar de outras. Por acaso a IBM ou RedHat são mais boazinhas do que a Microsoft só porque promovem o Linux? O custo da licença de um software é só uma fração do seu custo ao longo do tempo. Além disso temos o custo de suporte e atualização. Isso quer dizer que, ao invés do governo ficar amarrado com a Microsoft, ficará amarrado com a IBM, RedHat, Conectiva ou qualquer empresa que trabalhe com Linux. É correto privilegiar essas empresas e seus parceiros? Uma empresa que dá suporte (help desk) Linux não necessariamente contribui com a comunidade open source. Por que uma empresa dessas deve ter preferência em detrimento de uma empresa que dê suporte Windows?
Mas sim, hoje existe privilégio por parte da Microsoft. As pessoas estão tão acostumadas a usar softwares Microsoft que muitas vezes não param para estudar se existe um alternativa que seja viável. Isso sem contar o orçamento de marketing da Microsoft. Se deve existir uma lei sobre escolha de software, ela deve exigir que o governo faça um estudo de um numero mínimo de alternativas de software para aquele problema específico. Então o governo vai comprar sistemas operacionais? Ok, então que eles façam um estudo da viabilidade de usar Linux ou Windows, estudar o custo-benefício da solução. O Linux é mais barato, mas tem problemas de compatibilidade com hardware e software. O Windows tem compatibilidade 100%, mas tem um alto custo com licenças e te deixa preso com somente um fabricante.
Resumindo, o critério deve ser qualidade e custo-benefício. Querem que o Linux seja usado por todos? Façam com que ele tenha qualidade. Do resto o mercado se encarrega.
Em 20/09/2004 20:02 - Comentários (8)
Tudo que eu já sabia
Para empresas, faltam profissionais qualificados na área de tecnologia
Em 04/10/2004 19:24 - Comentários (0)
Verdades e mitos sobre NTFS e FAT
Verdade: NTFS é mais seguro (quanto a perda de arquivos)
O NTFS conta com um sistema de journaling, que grava um log de tudo que está sendo modificado na estrutura da partição NTFS. Caso acabe a luz ou ocorra algum desastre similar, o NTFS termina (ou desfaz) as últimas modificações nos metadados da partição, deixando sua partição acessível. Quando acaba a luz e você usa FAT, só resta rezar enquanto religa máquina.
Mito: É mais fácil recuperar dados em uma partição FAT
Esse mito vem do fato que os disquetes de boot DOS e Windows 9x não acessam partições NTFS. Mas as pessoas geralmente esquecem que os disquetes de boot já não são essenciais. Todos os CDs do Windows 2000/XP podem ser usados para dar boot na máquina e acessar os arquivos da partição usando a opção de "Recovery".
Para esses casos específicos também existem as distribuições Linux que consegue fazer boot com interface gráfica, conexão com Internet e suporte a Pen Drive USB, tudo isso rodando diretamente do CD. Assim você pode copiar seus arquivos tranquilamente. Algumas permitem que você copie o Linux inteiro na RAM, retire o CD de boot e use o gravador de CD normalmente. A grande maioria das distribuições Linux hoje em dia vêm com o driver de NTFS (somente leitura). (A grande excessão é o Fedora Core, mas eles devem ter algum motivo político/ideológico para isso...)
Mito: FAT32 é mais rápido do que NTFS
Eu também tinha essa impressão. O fato do driver de FAT do Windows chamar fastfat.sys também ajuda. Mas eu nunca encontrei nenhum estudo conclusivo que dissesse isso. O que eu mais encontrei na Internet foram informações de que o NTFS é mais rápido do que o FAT em partições grandes. E como hoje em dia o menor HD que você consegue comprar é de 80 GB...
Mito: Partição NTFS não fica fragmentada
Realmente, a partição NTFS tem bem menos problema com fragmentação. Mas não é verdade que NTFS não fragmenta. Tanto não é verdade que existe um desfragmentador no Windows.
Veja também
Dicas para particionamento e organização do HD, parte 1Dicas para particionamento e organização do HD, parte 2
Dicas para particionamento e organização do HD, parte 3
Em 05/10/2004 12:17 - Comentários (1)
MPROB (mais um post referenciando outro blog)
O pessoal da Microsoft às vezes exagera no uso de siglas:
Congrats to the XMLP WG for getting the MTOM and XOP specs to CR
Alguém pode me explicar o que o Don Box quis dizer com isso?? :-)
Em 06/10/2004 18:59 - Comentários (0)
Mais uma prova que computação não é uma ciência exata
A Microsoft, a um tempo atrás, implementou a política "Zero Defects" para desenvolvimento de software. Essa política determinava que, enquanto todos os bugs de um determinado software não estivessem corrigidos, nenhuma nova funcionalidade seria adicionada. Mas os softwares da Microsoft (assim como 100% dos softwares existentes) ainda tem bugs. O que acontece então? Leiam isso:
Larry's rules of software engineering, Part 3: "Zero Defects" doesn't result in zero defects
Em 08/10/2004 12:41 - Comentários (0)
Mais ferramentas
Achei sites muito bons com ferramentas:
John Lyon-Smith: Libs C++/Win32, libs .NET. Além disso, tem o "C# Script Executor 2.6.8", que permite usar C# como ferramenta de script.
SmidgeonSoft: Ferramentas a la Sysinternals. Debuggers, Disassemblers, e visualizadores de objetos do NT (threads, arquivos, etc). Merece uma visita.
Em 08/10/2004 13:17 - Comentários (0)
Conhecimento é poder
Eu já escrevi sobre como é extremamente necessário que você tenha informações para tomar decisões. Tenho pensado bastante em open source, e resolvi me informar melhor de uma vez por todas. Eu sou um usuário Linux razoável, tenho um SUSE instalado em casa e até consigo me virar. Bom, mas que graça tem usar um sistema operacional sem programá-lo?
Além do C/C++, que é lingua franca em todos os sistemas operacionais, tendo estudado algumas bibliotecas. Fiz alguns testes com Qt (o toolkit usado pelo KDE) e também com GTK (usado pelo Gnome). Tendo mais ao Qt, por ser nativamente C++ e por achar o KDE mais conciso do que o Gnome.
Além do C++, tenho feito testes com o Mono, a runtime .NET para Linux, do pessoal da Ximian/Novell. Apesar de toda a dificuldades com a implementação do Windows.Forms (eles também desistiram do Wine), o trabalho deles é espantoso. Nos poucos testes que eu fiz, o JIT do Mono me pareceu sensivelmente mais rápido do que o JIT do .NET Framework. Ainda vou fazer alguns testes com sistemas maiores, mas a primeira impressão é muito boa. Na empresa onde eu trabalho, estamos começando a projetar um sistema grande, com a camada de negócios separada da apresentação. Isso vai me dar vários componentes sem dependência de Windows.Forms para testar no Mono. E prometo que publicarei os testes aqui no site.
Falando em Mono, eu troquei uns e-mails com o Miguel de Icaza, o cara que projetou e coordenou a implementação do Mono. O mais legal é que, em um dos e-mails, ele me deu uma "bronca", dizendo que o fato de eu ter nascido no mundo Microsoft não é um motivo para eu me sentir tão perdido no UNIX ("não vou comprar seu argumento, simplesmente porque computadores são divertidos"). Além disso, ele me indicou um livro, o The UNIX Programming Environment, que eu comprei e estou lendo.
Esse livro foi escrito em 1984. Pode parecer desatualizado, não? É, mas não está. E lendo esse livro eu, além de aprender um pouco da filosofia do UNIX, tenho aprendido que as grandes novidades na área de programação são reinvenções de tudo que já existe desde de 1960.
O UNIX trabalha com o conceito de stream, usando e abusando da capacidade de redirecionar o stdout de um programa para o stdin de outro (em português: redireciona a saída de um programa para a entrada de outro). Esse conceito permite que vários programas trabalhem em conjunto, multiplicando o poder das ferramentas. Você pode até trocar aquele funcionário incompetente por um shell script :-).
Mas como um programa entende a saída de outro? Simples, usando o formato texto, com tudo separado com quebra de linha (\n). Assim todo mundo se entende. Isso te lembra alguma coisa? Não mesmo? Pense melhor...
XML. Padrão baseado em SGML (texto) para intercâmbio de informações. Assim todo mundo se entende. Mas, considerando os fatos acima, XML é uma evolução, e não uma revolução. Seria uma revolução se todos os programas, desde o início dos tempos, trabalhassem com formatos fechados e binários, como o Microsoft Word. Mas é evolução, já que isso já existe desde a década de 60.
Mais uma simples evolução: SOA, arquitetura orientada a serviços. RPC baseado em SOAP (XML) trafegando em HTTP. Sem binding em tempo de compilação = IDispatch. Sem guardar estado = programação procedural. Sim, isso mesmo, programação procedural. As funções são "abrigadas" em objetos, que simplesmente fazem o mesmo papel que um namespace C++. Isso vem desde o pooling de componentes do COM+, com objetos stateless (que não guardam estado). E aí, qual a revolução?
Conclusões que eu cheguei:
- Evolução é uma palavra que só serve para o pessoal de marketing
- Sim, o Linux é legal... :-)
- Como ler um livro pode fazer a gente pensar em tantas coisas
- Como é colossal a quantidade de informações que você pode absorver estudando sobre um assunto
- Quando você estuda um assunto, você obtêm informações que podem te levar a conclusões sobre outros assuntos
- Ainda bem que eu não virei advogado, como minha família queria...
Em 11/10/2004 13:07 - Comentários (1)
Saudações ao debutante
Alfred Gary Myers, o cara que mais entende de .NET que eu conheço, resolveu de uma vez por todas escrever um blog. Vão aqui meus votos para que ele realmente leve isso a sério e escreva freqüentemente.
Em 18/10/2004 20:03 - Comentários (2)
Projeto de lei 1947/2003 sobre a regulamentação da profissão de Analista de Sistemas: eu sou contra!
Existe um projeto de lei, proposto por um deputado do Rio de Janeiro (Eduardo Paes), que prevê a regulamentação da Profissão de Analista de Sistemas e a criação de um conselho, como a CREA, para os profissionais de informática.
Até aí, tudo muito bom. Até ler o conteúdo da lei:
Art.2º Poderão exercer a profissão de Analista de Sistema no País:
I - os possuidores de diploma de nível superior em Análise de Sistemas, Ciência da Computação ou Processamento de Dados, expedidos no Brasil por escolas oficiais ou reconhecidas pelo Governo Federal;
II - os diplomados por escolas estrangeiras reconhecidas pelas leis de seu País e que revalidarem seus diplomas de acordo com a legislação em vigor;
III - os que, na data de entrada em vigor desta lei, tenham exercido, comprovadamente durante o período de, no mínimo 5(cinco) anos, a função de Analista de Sistema e que requeiram o respectivo registro aos Conselhos Regionais de Informática.
E tem mais:
Art.31 Constituem infrações disciplinares, além de outras:
I - transgredir preceito de ética profissional;
II - exercer a profissão quando impedido de fazê-lo, ou facilitar, por qualquer meio, o seu exercício aos não inscritos ou impedidos;
Não esqueça que "impedido de fazê-lo" é alguém que não tenha diploma na área de informática. E passar um projeto para uma pessoa não formada será uma infração passível de punição.
O deputado Eduardo Paes é advogado, ex Secretário do Meio Ambiente do Rio, e assumidamente não entende de informática. Não estou simplesmente o desqualificando, mas acho que a visão dele da nossa área é equivocada, ele está tratando nossa área como se fosse Medicina e Engenharia. Inclusive, as pessoas que defendem a criação da lei insistem em fazer comparações com essas áreas, que como sabemos, tem um dinâmica completamente diferente da nossa. Eles chegam até a dizer que tirando os "sem diploma" do mercado o salário aumentará graças a lei da oferta e procura. Egoísmo pouco é bobagem mesmo...
Eu já gastei meu latim (sem sucesso) em uma lista de discussão sobre o assunto, tentando explicar que tirar as pessoas sem diploma do mercado não é o mais correto. Sabemos que existem MUITOS analistas e programadores sem diploma que são MUITO melhores do que os formados. Além disso, me parece um instrumento visivelmente criado por alguém que não tem conhecimento da área, e para profissionais limitados que querem manter seus empregos às custas de um diploma. Querem criar mais um indústria dos "assinadores de projeto", como existe em jornalismo e engenharia. Talvez a regulamentação seja boa, mas o texto dessa lei está completamente equivocado.
Criei uma nova lista de discussão para as pessoas que SÃO CONTRA essa lei. Caso alguém queira ajudar com argumentos, ou ajudar a pensar na forma mais adequada de manifestação para evitar que essa lei seja aprovada, sinta-se convidado.
Caso você não conheça direito a lei, dê uma lida nela e nos seus apensos. Caso você chegue a conclusão que também é contra, entre na lista. Caso ainda não tenha opinião formada ou deseje somente discutir o mérito da questão, use a lista da RioJUG que foi criada para isso.
Parece que o pessoal da Sociedade Brasileira de Computação também é contra a exigência de diploma na área. Fiquei muito feliz ao saber disso.
Para mais detalhes
Texto do projeto de lei
Página com todas as informações dos projetos. Leia os apensos e veja as justificativas, você dará boas risadas
Em 19/10/2004 12:16 - Comentários (16)
Wikipedia tem tudo, inclusive algoritmos
Quem leu o About do site deve saber o quanto eu gosto da Wikipedia. É a enciclopédia livre e aberta, com mais conteúdo do que as enciclopédias pagas. E como bastante gente que trabalha diretamente com programação escreve lá (até eu já escrevi algumas coisas...), existe bastante conteúdo sobre programação.
Mas um das coisas mais legais é que a Wikipedia tem muita informação sobre algoritmos, inclusive com implementações em diversas linguagens. Duvido que a Barsa que sua mãe comprou tenha a implementação de quicksort em Lisp. :-)
Além da definição de um algoritimo, temos a explicação e implementação de quick sort, busca binária, red black tree, entre outros. Fora os links para sites com mais detalhes e como animações Java para você entender melhor o algoritmo. Precisa de mais alguma coisa?
Em 19/10/2004 17:56 - Comentários (1)
Mostre-me teu Menu Iniciar e digo quem tu és

Em 20/10/2004 00:02 - Comentários (1)
Se o programador é bom, não importa a ferramenta
Uma das características de um bom programador é saber escolher a ferramenta certa para a tarefa certa. Apesar de eu ser um ferrenho programador Visual C++, quando eu preciso fazer programinhas de cadastros eu uso VB6 ou .NET.
Mesmo assim, existem pessoas que fazem coisas muito boas, mesmo que a ferramenta não seja a mais adequada. Eu lembro que a uns 8 anos atrás eu copiei da antiga revista Micro Sistemas (alguém lembra dessa?) um driver de mouse para QBASIC, usando DATA e PEEK/POKE. Eu eu comecei a fazer um Adventure, com interface gráfica e tudo, em QBASIC. Cheguei até a fazer uma lib para interface tipo Windows, como botão 3D e um sistema tosco de caixas e coordenadas. Bons tempos aquele, quando eu nem sabia que programação era uma profissão, pra mim era tudo diversão.
O fato é: a grande maioria dos softwares são feitos em C/C++. Apesar de serem linguagens altamente técnicas e muito complexas para iniciantes, a flexibilidade faz com que elas sejam as preferidas. Já falei sobre isso em um post anterior. Mas existem pessoas que que usam linguagens menos comuns - ou até mesmo não adequadas - para contruir programas. Alguns exemplos:
BitTorrent: Software para downloads distribuídos, uma das grandes invenções em P2P. Um conceito maravilhoso, implementado em Python e com a GUI feita em wxWindows, usando um bind para Python.
Azureus: Client para BitTorrent, feito em Java. Não que Java não seja uma ferramenta adequada para isso, mas os programas GUI feitos em Java, na sua grande maioria, são muito feios. Esse programa (junto com o Eclipse e as IDEs da Borland) é muito bonito e funciona muito bem. É meu client BitTorrent preferido.
DHTML Lemmings: O CAMPEÃO!!! Link enviado pelo meu amigo Fábio. Um clone do jogo Lemmings implementado em DHTML/CSS/JavaScript. Joguei só as primeiras fases, mas o jogo é perfeito. Eu custei a acreditar que ele foi feito somente em JavaScript.
Em 20/10/2004 17:24 - Comentários (0)
Testando ASP.NET, rodando em Linux e Mono
O MonoForge, uma iniciativa do provedor italiano Impulso, está aceitando candidatos para um período de beta test para hospedar aplicativos feito em ASP.NET. A grande novidade é que os servidores usarão Linux e Mono (a runtime .NET para Linux/Unix/MacOS da Ximian/Novell), ao invés servidores com Windows.
Serão 10MBs de espaço, e 1 banco mySQL. Sendo assim, você não pode simplesmente copiar seu aplicativo ASP.NET feito para SQL Server e vê-lo rodando, a não ser que você tenha usado alguma camada para abstração de banco de dados. Mas como as classes de acesso a banco de dados suportam as interfaces IDbXXX, você pode dar sorte, e um find/replace para trocar as declarações pode resolver o seu problema - se você não usou nenhum recurso esotérico do SQL Server, é claro.
É uma ótima oportunidade para testar o Mono sem usar um servidor próprio.
Em 25/10/2004 13:04 - Comentários (0)
Um dia minha filha terá orgulho disso
Minha pequena Heloisa nasceu faz um pouco mais de uma semana. Além da minha felicidade de pai de primeira viagem, isso também gerou uma história interessante para contar. Afinal, nada da vida de um escovador de bits pode passar em branco... :-)
Quem conhece um pouco de gravidez, sabe que horas antes (pode ser até 48 horas) do parto, a mulher começa a sentir as contrações e o corpo começa a se preparar para o trabalho de parto. As mães que fazem pré natal são orientadas pelos médicos e enfermeiras a anotar a duração e intervalo das contrações, para saber como anda a evolução do trabalho e ajudar a saber a hora certa de ir para um Hospital (ou para uma Casa de Parto, como foi o meu caso).
Enquanto eu estava no trabalho, minha esposa ligou dizendo que já estava sentindo algumas contrações leves. E também me disse que estava controlando isso, anotando os horário no papel. Poxa, no papel?? Nem uma planilhinha Excel?? Em que mundo vivemos?? :-)
Quando eu cheguei em casa, ouvi o que eu queria: "Ficar olhando no relógio e anotando essas contrações já está enchendo o saco...". Foi aí que eu perguntei se um programinha no iPaq ajudava. Disse que seria só clicar quando começasse e quando terminasse a contração, que ele faria o resto. Então, ela disse sim. :-)
Abri feliz meu Visual Studio, iniciei um projeto para PocketPC em C#. Meia hora, um DataGrid, um DataSet e um Button depois, eu tinha uma versão alfa, que testamos nas próximas contrações. Corrigi alguns bugs e fui colocando mais recursos a medida que ela ia pedindo. Mais uma hora programando e acompanhando as contrações eu tinha um programa para controlar contrações pronto.
A parte que está no DataGrid é simples. Os tempos que estão embaixo são as médias. O programa salva o DataSet em um arquivo "\contra.xml", e pergunta no início se você quer carregá-lo para continuar contando as contrações.
Você pode baixar os fontes do programa aqui. Caso queria somente o programa para usar, você pode baixar o programa, instalar o .NET Compact Framework no seu PocketPC e depois copiar o programa pra ele (não precisa instalar). E como ele é feito em .NET, esse programa também roda em qualquer PC que tenha o .NET Framework instalado (fica feio, mas roda).
Acho desnecessário, mas lá vai:
Esse programa é livre e pode ser usado por qualquer um, sem restrições. Sendo assim, NÃO DAREI NENHUM TIPO DE SUPORTE. Também não me responsabilizo caso alguma conta esteja errada, não se esqueça que eu programei isso enquanto minha esposa estava tendo contrações... Também não me responsabilizo se alguém parir em meia hora ou se a mulher passar o tempo todo jogando paciência no iPaq e não controlar as contrações. E claro, ignorarei qualquer pedido para que o programa seja portado para VB.NET :-)
Em 31/10/2004 17:40 - Comentários (12)
WinDbg novo!
O WinDbg 6.4.4.4 beta já está disponível para download. Eu já baixei o meu :-)
Em 01/11/2004 00:15 - Comentários (0)
Novo servidor
Depois de ficar realmente decepcionado com a instabilidade do meu antigo servidor, resolvi fazer uma troca. Espero que esse novo hosting faça jus aos 97% de aprovação e satisfação que eles conseguiram no Find My Hosting. A aprovação do meu antigo era de 80%, talvez isso diga alguma coisa...
Em 02/11/2004 11:28 - Comentários (5)
Programando drivers com bom humor
Toda equipe sempre tem um programador que acaba colocando uma gracinha ou outra em um programa. Eu faço questão de não deixar as equipes que eu participo sem esse tipo de pessoa. Além de ter o costume de colocar uns comentários não muito convencionais no código, eu às vezes aproveito para colocar um ovinho de páscoa nos programas. O que seria da nossa vida sofrida de programador se não tivessemos bom humor?
Olhem só um erro que foi retornado pelo BUILD (programa que gerencia a compilação de drivers) do DDK quando eu, por engano, coloquei um arquivo .h na lista de SOURCES:
BUILD: Adding /Y to COPYCMD so xcopy ops won't hang.
BUILD: Object root set to: ==> objchk_w2K_x86
BUILD: Compile and Link for i386
BUILD: Loading c:\WINDDK\3790\build.dat...
BUILD: Computing Include file dependencies:
BUILD: Examining d:\data\sp\source2\drivers\spfwu directory for files to compile.
d:\data\sp\source2\drivers\spfwu
BUILD: d:\data\sp\source2\drivers\spfwu: Interesting sources extension: callbacks.h
Eu também acho que .h é uma extensão bem interessante... :-)
Em 02/11/2004 19:47 - Comentários (3)
Programadores sepultam programas mortos
Terra Informática: Programadores sepultam programas mortos
Slashdot: Programmers Hold Funerals for Old Code
Eu tenho tantos programas para chorar... Os meus pelo menos eu mantenho em estado de hibernação no meu HD, não tenho coragem de matar. Afinal, algum dia eu ainda posso querer modificar o programa em Clipper que eu fiz quando tinha 16 anos, vai saber...
Editado em 05/11/2004: Um link do Slashdot é muuuuuuuuuito melhor do que um link do Terra Informática
Em 04/11/2004 13:18 - Comentários (0)
Atendendo a pedidos: Controle de Contrações para PC, baixável e feito em WTL
Atendendo aos pedidos do meu amigo Wanderley e da minha querida doula Ana Cris, resolvi fazer uma versão do meu Programa Para Controle de Contrações Para Parturientes e Similares que roda em PC e feito em WTL. O layout do programa não é lá essas coisas, mas eu tentei manter o design e o funcionamento parecidos com a versão para PocketPC. E apesar do pedido da Ana Cris para que o programa fosse "instalável", eu resolvi teimar e fazer um que não precisa instalar, é só baixar e rodar. :-)
O programa foi desenvolvido usando o Visual C++ 7.1 e o WTL 7.5. Como eu não usei nada esotérico, acredito que ele deve ser compilável usando versões mais antigas do WTL. Mesmo assim, não sei se isso vai compilar no Visual C++ 6.0.
Como em Win32 não existe DataGrid, eu usei um ListView, que serve muito bem para esse propósito. Ao invés de usar um DataSet para gravar os dados, eu usei um std::list e populei o ListView "na mão".
Foi difícil resistir a tentação de usar o ATL::CAtlList no lugar do std::list, mas eu estou querendo me livrar do vício do ATL e ser um pouquinho mais multiplataforma. Acho que eu nunca escrevi sobre isso ainda, mas eu me recuso a usar a lib do C. Eu gosto mesmo é de CreateFile, ATL::CAtlFile, CreateFileMapping, CoCreateInstance e CoMarshalInterThreadInterfaceInStream :-)
Olhem os trechos principais do código:
typedef struct _CONTRA_INFO
{
__time64_t StartTime;
__time64_t EndTime;
} CONTRA_INFO;
typedef std::list CContraList;
...
void CMainDlg::ChangeButtonText()
{
m_Button.SetWindowText(m_bContraInProgress ?
_T("Ufa, acabou...") :
_T("Está doendo, socorro!!"));
}
void CMainDlg::UpdateList()
{
CContraList::iterator CurrentIterator, PreviousIterator;
int iItem;
ATL::CTime CurrentTime, PreviousTime;
ATL::CTimeSpan Duration, Interval;
CurrentIterator = m_ContraList.end();
CurrentIterator--;
if(m_bContraInProgress)
{
//
// contração acabou de iniciar. Calcular o intervalo entre
// a última e colocar o horário inicial no ListView
//
//
// Colocar no ListView
//
CurrentTime = CurrentIterator->StartTime;
iItem = m_lstContra.InsertItem(100000, CurrentTime.Format(_T("%x %X")));
//
// se for a primeira contração, não tem intervalo para calcular
//
if(CurrentIterator != m_ContraList.begin())
{
PreviousIterator = CurrentIterator;
PreviousIterator--;
ATLASSERT(PreviousIterator->EndTime != 0);
Interval = CurrentIterator->StartTime - PreviousIterator->EndTime;
m_TotalInterval += Interval.GetTimeSpan();
m_lstContra.SetItemText(iItem,2,Interval.Format(_T("%M:%S")));
}
}
else
{
//
// a contração acabou. É só calcular a duração e colocar no último item
//
iItem = m_lstContra.GetItemCount() - 1;
ATLASSERT(CurrentIterator->StartTime & CurrentIterator->EndTime);
Duration = CurrentIterator->EndTime - CurrentIterator->StartTime;
m_TotalDuration += Duration.GetTimeSpan();
m_lstContra.SetItemText(iItem,1,Duration.Format(_T("%M:%S")));
}
}
void CMainDlg::DoStatistics()
{
ATL::CTimeSpan t;
int iItemCount = m_ContraList.size();
if(iItemCount < 2)
return;
t = m_TotalDuration / (iItemCount - (m_bContraInProgress ? 1 : 0));
m_stcDuration.SetWindowText(t.Format(_T("%H:%M:%S")));
//
// como o primeiro item não tem intervalo, é -1
//
t = m_TotalInterval / (iItemCount - 1);
m_stcInterval.SetWindowText(t.Format(_T("%H:%M:%S")));
}
LRESULT CMainDlg::OnContraClick(WORD,WORD,HWND,BOOL&)
{
CONTRA_INFO ContraInfo;
CContraList::iterator i;
if(!m_bContraInProgress)
{
//
// início da contração
//
ContraInfo.StartTime = _time64(NULL);
ContraInfo.EndTime = 0;
m_bContraInProgress = TRUE;
m_ContraList.push_back(ContraInfo);
}
else
{
ATLASSERT(!m_ContraList.empty());
i = m_ContraList.end();
i--;
i->EndTime = _time64(NULL);
m_bContraInProgress = FALSE;
}
UpdateList();
ChangeButtonText();
DoStatistics();
return TRUE;
}
Algumas coisas podem ser notadas nesse trecho de código:
- Não acho que esse código seja muito mais complicado do que um código em .NET. Complicado e difícil de compreender é a lib do C, que tem mais de 3 décadas. ATL/WTL facilitam muito as coisas, e o código fica MUITO pequeno e MUITO rápido.
- Eu não me preocupei com otimizações. O máximo que eu fiz é usar __time64_t ao invés de ATL::CTime na hora de gravar os horários, para reduzir a atividade desenfreada de copy constructors. Até porque, hoje em dia todo mundo usa .NET, que é muuuuuuuuito lento (não me venham com esse papo de "depende"). Então não me venham falar que meu código em C++ poderia ser mais rápido... :-)
- Programar drivers faz bem! Quem já programou KernelMode vê a clara influência do estilo WinDDK no meu código. Uso de ASSERTS, código claro, comentários claros e destacados, variáveis com nomes claros. Olhe algum sample do DDK e veja o que é programar bonito!
- Eu usei TCHAR (veja as macros _T()) para que eu pudesse compilar em UNICODE (Windows NT/2000/XP/2003) e em ANSI (Windows 9x/Me). No projeto existem 3 configurações: Debug, Release e Release ANSI. Eu costumo compilar somente UNICODE, mas resolvi de última hora ser solidário com os usuários de Win9x, afinal, eles já têm problemas suficientes.
- Eu coloquei o ATL:: antes de CTime e CTimeSpan para deixar bem claro que o código não tem nada a ver com MFC.
Como o programa é feito em WTL (a melhor lib do planeta para desenvolver código Win32), nós temos um executável de 84kb sem dependência de nenhuma runtime ou DLL. É só baixar o executável e rodar.
Downloads
Executável UNICODE (Windows NT/2000/XP/2003/Longhorn)Executável ANSI (Windows 9x/Me). Eu não tenho uma máquina Windows 9x para testar, me avisem caso não funcione.
Fontes do programa. Você vai precisar do WTL para compilar.
Em 07/11/2004 17:41 - Comentários (0)
Realizando o meu desejo: Todos os posts do weblog, em ordem cronológica
Eu leio diversos weblogs diariamente, e existe um recurso que eu sinto falta: poder ler todos os posts de um weblog em ordem cronológica. Em todos os blogs os posts são organizados no esquema de "os mais atuais primeiro", e quando alguém escreve uma série de posts relacionados, você é obrigado a ficar lendo de trás para frente, como fazemos com rastros de e-mail. Ou pior, você tem uma lista com os posts antigos e você tem que clicar um por um. Alguns weblogs tem a funcionalidade de calendário, para que você veja em uma tela só os posts de um determinado mês. Sinceramente, a não ser que seja um weblog daqueles sentimentais ("hoje acordei feliz, o dia está bonito e eu vesti aquela minha meia das Meninas Superpoderosas"), a data em que o post foi escrito pouco importa.
Como eu não posso modificar os weblogs dos outros, então eu mudo o meu. Se você quer ver tudo que eu escrevi até hoje, e em ordem cronológica, agora você pode. Um link para esse recurso também está disponível no arquivo do WebLog.
Em 07/11/2004 20:20 - Comentários (0)
Firefox 1.0!
Hoje, dia 09/11/2004 está oficialmente lançado o Mozilla Firefox 1.0
Eu uso o Firefox desde o 0.1 (quando ele ainda chamava Firebird), ele já era muito bom desde aquela época. E está ficando cada dia melhor.
Caso você ainda sofra com os demorados patches do Internet Explorer, sugiro que você mude para o Firefox. Caso você seja um power-user, mude para o Firefox e depois escolha as extensões (plugins) que mais te agradam. Eu uso Ad-Block (bloqueia banners), Tabbrowser Extensions (melhor controle das tabs), Sage (leitor RSS), e o All-in-one Gesture (comande seu browser somente movendo o mouse). Resumindo: caso você navegue na web, eu sugiro que você use o Firefox!
Em 09/11/2004 10:13 - Comentários (0)
Novo artigo: Como ser um bom programador
Existem diversos fatores que levam alguém a ser um bom programador. Selecionei os mais importantes e escrevi um artigo, sobre como ser um bom programador. Coloquei nele também algumas dicas importantes sobre como procurar informações na Internet e em lista de discussão. Além de lembrar que essa estória de "não preciso de livros, tem tudo na Internet" é coisas de gente que não sabe o que fala. :-)
Em 15/11/2004 19:15 - Comentários (0)
Achei um blog sobre desenvolvimento de drivers!
Para os interessados em programação de drivers para WinNT, dêem uma olhada no blog de Steve Dispensa (MVP para Windows DDK), one ele escreve algumas dicas sobre desenvolvimento e teste de drivers.
Estou preparando um post sobre como iniciar o desenvolvimento de drivers e onde encontrar informações, aguardem!
Em 18/11/2004 10:13 - Comentários (0)
Como fazer drivers para Windows NT/2000/XP/2003, parte 1
A dúvida mais frequente que eu recebo pelo formulário de contato é: "como eu faço para desenvolver drivers para Windows?". Vou publicar algumas dicas aqui para quem está iniciando.
Pré requisitos
Primeiramente eu espero que você seja um bom programador, programar drivers não é fácil. :-)
Para fazer um driver, você precisa SABER programar drivers (programação kernel mode). Parece óbvio mas não é. Eu recebo todo mês pelo correio a newsletter da OSR, e a do mês passado era uma edição especial com o dobro do tamanho normal, falando sobre teste de drivers. E lá eu li algo muito interessante: em kernel mode, é impossível fazer programação cowboy. Programação cowboy é quando você não entende muito do assunto, pega um código exemplo daquilo que você quer e sai ajustando e remendando até que fique bom, e depois entrega para o cliente. Quando a coisa roda em kernel mode, isso nunca vai ficar bom, a não ser que você saiba mesmo o que está fazendo. Eu conheço uma empresa que está remendando um driver faz mais de dois anos, e até hoje não funciona direito.
Você precisa ser um bom programador C, ponto. Caso você ainda tenha dúvida sobre ponteiros ou estruturas de dados, programação de drivers é um péssimo lugar para treinar isso. O indicado é que você consiga fazer um programa Win32 com certa facilidade antes de se aventurar a programar drivers. Alguns conceitos de passagem de parâmetros IN e OUT usando estruturas e ponteiros void que viram ponteiro para estruturas mágicas também são usados em Win32. Ah, e se você não souber o que é uma lista ligada, veja antes na wikipedia, você vai usar isso muito.
(E antes que alguém pergunte, experiência com C#, VB.NET, VB6 ou Java não vai te ajudar em muita coisa além do treino em lógica de programação)
Onde encontrar informações
Agora que você já passou pelo blá-blá-blá, vamos ao que realmente interessa. Se você quer programar em kernel mode você terá que estudar bastante, e é melhor que comece o quanto antes.
Livros
Microsoft Windows Internals - Esse é o primeiro que você deve ler e reler. Não trata especificamente sobre programação kernel mode, mas descreve o funcionamento do kernel do Windows. E é ESSENCIAL que você saiba isso.
Programming the Windows Driver Model - Esse trata especificamente de programação kernel mode. Windows Driver Model (WDM) é um modelo de programação de drivers (mais voltado para drivers que controlam hardware). Caso seu driver siga as regras do WDM, seu driver pode ser compilado para Windows 2000 ou superior e Windows 98 e superior. Mesmo que seu driver não seja para um hardware (um firewall é um driver e não controla hardware), vale a pena ler esse livro, ele explica muito bem como funciona a sincronização e o I/O em kernel mode.
Existem mais livros, esses dois são os que eu tenho e uso para consulta. Procure na Amazon.
Internet
OSR Online - Empresa dos Estados Unidos que além de dar treinamentos sobre desenvolvimento kernel mode, disponibiliza bastante material sobre isso.
Windows Drivers Developer's Digest (W3D) - Artigos escritos por autoridades do assunto, como Walter Oney e Thomas Divine.
Listas de discussão - Nessa categoria temos as listas da OSR, o newsgroup da Microsoft sobre drivers e a lista da PCAUSA (específica para a parte de rede e afins).
Na continuação dessa série, falarei sobre o DDK e como colocar a mão na massa.
Em 21/11/2004 09:47 - Comentários (7)
Como contratar alguém para uma equipe de testes
Sem uma equipe de testes é MUITO DIFÍCIL entregar um software com qualidade, qualquer que seja a equipe de testes. A equipe pode ser formada por profissionais treinados e experientes em testes ou um estagiário mais esforçado. Apesar de não ser o ideal, o estagiário esforçado é muito melhor do que ninguém ligado ao desenvolvimento testando. Uma coisa muito importante: um estágiário de desenvolvimento serve, mas um estagiário ligado ao usuário não serve. O foco dele é outro e muitas vezes a equipe não tem o acceso necessário a ele. Todos os "testadores" devem ser ligados a equipe de desenvolvimento.
(Já trabalhei em uma empresa onde o responsável pelos testes era o Analista Funcional. Não considero isso uma equipe de testes, pois um Analista Funcional vai fazer os mesmos testes que o usuário vai fazer, testes de regras de negócios. Uma equipe de testes faz testes de stress, casos de usos e usos atípicos)
Eu já trabalhei com equipe de testes e sem equipe de teste. Sem é muito mais difícil, porque o programador tem que perder tempo com testes de validação, tentar deixar campos sem preencher, etc. Um bom estagiário faria isso sem problemas, e é muito melhor do que o programador perder tempo com isso. Isso otimiza o tempo de desenvolvimento e deixa o programador fazendo o que ele tem que fazer: programar.
Uma equipe de testes ajuda os programadores a escreverem um código de melhor qualidade. Se o programador sabe que a maioria dos erros serão pegos pela equipe de testes, ele terá mais atenção ao programar. Não existe nada mais desanimador do que um sistema de controle de bugs (sua empresa tem um, não tem?) com dezenas de bug com o seu nome estampado.
Caso sua empresa não tenha uma equipe de testes ou você esteja montando essa equipe, dê uma lida nesse artigo da Sticky Minds com dicas para contratar "testadores".
Em 26/11/2004 15:12 - Comentários (0)
Lendo a camiseta do ThinkGeek sem programar
O site do ThinkGeek está com uma promoção onde, gastando mais do que US$ 100,00 você ganha uma camiseta:
Essa camiseta tem o logo do SourceForge na frente e um número binário giganteco atrás. É CLARO que esse número quer dizer alguma coisa. Perdi 10 minutos hoje para encontrar o significado, me propondo a não usar uma só linha de código. Olhe o que eu fiz:
- Copiei o número binário do site;
- Criei um novo arquivo TXT no Visual Studio.NET, e colei o binário lá;
- Usando Regular Expressions, tirei as quebras de linha (troquei "n" por "");
-
Usando Regular Expressions novamente, deixei que cada linha tivesse oito dígitos (troquei "{^........}" por "1n"). Pronto, agora temos números binários de 8 dígitos, que podem ser convertidos para char.

- Copiei o resultado e colei no Excel;
- Usei a função "BIN2DEC" do Excel para converter os binários em decimais. Caso o seu Excel diga que essa função não existe (colocando #NAME nas células), vá no menu Tools >> Addins e ative o "Analysis ToolPak";
-
Depois, usei a função "CHAR" para achar os caracteres correspondentes aos números de acordo com a tabela ASCII;

- Copiei os caracteres para Visual Studio.NET e substitui "n" para "";
- I spent $100 at ThinkGeek and all I got was this lousy limited edition t-shirt.

Caso você tenha outra solução, sinta-se a vontade para mostrá-la nos comentários.
Em 02/12/2004 15:40 - Comentários (5)
Internet sem firewall é suicídio
Um texto da ArsTechinica conta sobre uma experiência feita com computadores conectados à Internet via banda larga, para descobrir quanto tempo eles levariam para ser atacados.
O resultado é inacreditável. O computador com Windows XP Service Pack 1 foi invadido 4 minutos após ter sido conectado. Na maioria dos casos, o computador invadido é transformado em um robô para envio de spam e vírus, e o usuário nem se dá conta disso.
Apesar de complicado para os usuários comuns, isso tem uma solução. Atualize seu Windows, e permita que o Service Pack 2 do Windows XP ative o firewall.
Em 03/12/2004 09:00 - Comentários (0)
Você acha que todos os autores de livros sabem o que falam?
Eu encontrei essa pérola no livro "Aprendendo ASP.NET com C#", de autoria de "Américo Damasceno Jr":
"
No Windows temos duas áreas de memória que podemos colocar algo: o stack e o heap
O stack é uma área menos nobre, pois quando entram novos item nela, os mais antigos caem fora (se autodestroem, digamos assim). Coisas que não requerem muita permanência são jogados no stack. Um parâmetro que não é um value-type e seu valor são um caso típico, pois geralmente o processamento do bloco termina rapidamente."
Sabe o que é pior? Eu já vi gente no fórum da MSDN brasileira recomendando esse livro.
Eu sei que mesmo os livros ruins têm mercado, principalmente entre os desenvolvedores iniciantes. Mesmo assim eu me reservo o direito de repugnar um livro escrito às pressas, com péssima qualidade e cheio erros.
Em 13/12/2004 09:14 - Comentários (1)
O bom filho à casa torna
Chega de DataSets, chega de DataAdapters, chega de MessageBox.Show. A partir de segunda-feira (dia 20 de dezembro), voltarei a trabalhar com minha linguagem de programação preferida. Agora, ao invés de ".NET de dia e C++ de noite", eu voltarei ao esquema "C++ de dia e C++ de noite".
Apesar da tristeza por deixar meus amigos de trabalho, minha alma de escovador de bits fala mais alto. Até onde eu sei terei bastante ATL, multithread e sockets pela frente. Ou seja, do jeito que eu gosto... :-)
Em 15/12/2004 14:39 - Comentários (1)
Usando o WinDbg para entender um software multithread
É necessário que você conheça pelos menos as funções básicas do WinDbg para entender esse post. Escrevi dois artigos sobre WinDbg que podem ajudar (parte 1 e parte 2)
Como já disse no post anterior, comecei o ano com o pé direito, voltando a trabalhar com Visual C++. E essa mudança de emprego e as festas de fim de ano são as minhas desculpas para o grande intervalo nos posts. E feliz 2005 para todos!
Mas esse tempo não foi de todo perdido. Encontrei alguns problemas com o RSS do blog e resolvi. Agora o RSS está verificado e deve funcionar com qualquer NewsReader.
Vamos ao que interessa. A empresa onde eu trabalho produz software de alto desempenho para o mercado financeiro. Os softwares se comunicam de diversas maneiras, sockets, File Mapping, MSMQ, etc. Muitas vezes existem comunicações entre as threads do mesmo processo, e essas comunicações são feitas de diversas maneiras, filas, mensagens inter thread, etc. Lendo o código é possível entender o que cada ThreadFunc faz, mas o mais fácil mesmo é colocar o software para rodar e analizar as comunicações entre as threads. Vamos ver como o WinDbg ajuda nisso.
Com o executável já rodando e sob o controle do WinDbg, vamos dar um break e analizar como as coisas acontecem. Primeiro vamos listar as threads do processo usando o comando "~":
0:027> ~ 0 Id: 890.bf8 Suspend: 1 Teb: 7ffde000 Unfrozen 1 Id: 890.cd8 Suspend: 1 Teb: 7ffdd000 Unfrozen 2 Id: 890.da0 Suspend: 1 Teb: 7ffdc000 Unfrozen ... 41 Id: 890.95c Suspend: 1 Teb: 7ff91000 Unfrozen 42 Id: 890.2a4 Suspend: 1 Teb: 7ff90000 Unfrozen 43 Id: 890.de4 Suspend: 1 Teb: 7ff8d000 Unfrozen
Bom, temos 44 threads. Um processo pode ter diversos thread pools, cada um para uma determinada tarefa. Podemos ter um thread pool para recepção de comunicação TCP/IP, outro pool para acesso ao banco de dados e outro ainda para acessar o MSMQ. Primeiro temos que saber o que cada thread está esperando.
(Está se perguntando o que é um thread pool? É quando você colocar diversas threads para atender solicitações em paralelo. Cada vez que é recebida uma solicitação pelo processo, a thread que gerencia o pool sinaliza uma das threads para que ela trate essa solicitação. Isso faz com que uma solicitação não trave outra, já que elas estarão rodando em threads diferentes. Uma thread de um pool quase sempre fica esperando uma sinalização (evento, semáforo, etc) usando WaitForMultipleObjects)
O comando "~", além de listar as threads do processo, também é usado como um modificador de comandos, fazendo com que o comando em uso seja direcionado para uma ou mais threads especificadas. Vamos testar isso com o comando "k". Esse comando faz um dump da pilha da thread atual. Vamos usá-lo:
0:027> k ChildEBP RetAddr 02f3ffc8 77f77fe8 ntdll!DbgBreakPoint 02f3fff4 00000000 ntdll!DbgUiRemoteBreakin+0x36
Como nós forçamos um breakpoint com CTRL+BREAK, nós estamos na thread de debug. Primeiro vamos utilizar o comando "~" para ver algumas informações da thread, e depois veremos como o comando "~" pode modificar o comando "k":
0:027> ~35
35 Id: 890.84 Suspend: 1 Teb: 7ff98000 Unfrozen
Start: kernel32!BaseThreadStartThunk (77e4a99b)
Priority: 0 Priority class: 32
0:027> ~35 k
ChildEBP RetAddr
0374fda8 77f4372d SharedUserData!SystemCallStub+0x4
0374fdac 77e41bfa ntdll!NtWaitForMultipleObjects+0xc
0374fe54 77e4b0e4 kernel32!WaitForMultipleObjectsEx+0x11a
0374fe6c 0041d3bc kernel32!WaitForMultipleObjects+0x17
0374fee8 004300eb XXX!CInterThreadMessageQueue::WaitForMessageEx+0x8c
0374ffb8 77e4a990 XXX!CResponseThread::ResponseThreadProc+0x9b
0374ffec 00000000 kernel32!BaseThreadStart+0x34
Agora temos um dump da pilha da thread 35. Mas como queremos estudar o que faz cada thread, com esse comando teríamos que ver thread por thread. Agora usaremos o suporte a curingas do comando "~".
0:027> ~* k ... 1 Id: 890.cd8 Suspend: 1 Teb: 7ffdd000 Unfrozen ChildEBP RetAddr 00bbfea0 77f4372d SharedUserData!SystemCallStub+0x4 00bbfea4 77f6c86c ntdll!NtWaitForMultipleObjects+0xc 00bbff48 77f6d7f5 ntdll!EtwpWaitForMultipleObjectsEx+0xf7 00bbffb8 77e4a990 ntdll!EtwpEventPump+0x27d 00bbffec 00000000 kernel32!BaseThreadStart+0x34 2 Id: 890.da0 Suspend: 1 Teb: 7ffdc000 Unfrozen ChildEBP RetAddr 014dfe20 77f4313f SharedUserData!SystemCallStub+0x4 014dfe24 77c57b85 ntdll!NtReplyWaitReceivePortEx+0xc 014dff8c 77c60829 RPCRT4!LRPC_ADDRESS::ReceiveLotsaCalls+0x193 014dff90 77c60771 RPCRT4!RecvLotsaCallsWrapper+0x9 014dffb0 77c60857 RPCRT4!BaseCachedThreadRoutine+0x9c 014dffb8 77e4a990 RPCRT4!ThreadStartRoutine+0x17 014dffec 00000000 kernel32!BaseThreadStart+0x34 3 Id: 890.c88 Suspend: 1 Teb: 7ffdb000 Unfrozen ChildEBP RetAddr 015dff10 77f4262b SharedUserData!SystemCallStub+0x4 015dff14 77e418ea ntdll!NtDelayExecution+0xc 015dff7c 77e416ee kernel32!SleepEx+0x68 015dff88 77162501 kernel32!Sleep+0xb 015dff94 771625ea ole32!CROIDTable::WorkerThreadLoop+0x12 015dff9c 77160000 ole32!CRpcThread::WorkerLoop+0x1e 015dffac 77162653 ole32!_imp__InstallApplication(ole32+0x0) 015dffb8 77e4a990 ole32!CRpcThreadCache::RpcWorkerThreadEntry+0x1f 015dffec 00000000 kernel32!BaseThreadStart+0x34 ... 5 Id: 890.f38 Suspend: 1 Teb: 7ffd9000 Unfrozen ChildEBP RetAddr 01a2fc38 77f4372d SharedUserData!SystemCallStub+0x4 01a2fc3c 77e41bfa ntdll!NtWaitForMultipleObjects+0xc 01a2fce4 77e4b0e4 kernel32!WaitForMultipleObjectsEx+0x11a 01a2fcfc 0041d3bc kernel32!WaitForMultipleObjects+0x17 01a2fd78 004171bd XXX!CInterThreadMessageQueue<>::WaitForMessageEx+0x8c 01a2ffb8 77e4a990 XXX!CExecutionThread::ExecutionThreadProc+0x1bd 01a2ffec 00000000 kernel32!BaseThreadStart+0x34 6 Id: 890.f08 Suspend: 1 Teb: 7ffd8000 Unfrozen ChildEBP RetAddr 01b2fc38 77f4372d SharedUserData!SystemCallStub+0x4 01b2fc3c 77e41bfa ntdll!NtWaitForMultipleObjects+0xc 01b2fce4 77e4b0e4 kernel32!WaitForMultipleObjectsEx+0x11a 01b2fcfc 0041d3bc kernel32!WaitForMultipleObjects+0x17 01b2fd78 004171bd XXX!CInterThreadMessageQueue<>::WaitForMessageEx+0x8c 01b2ffb8 77e4a990 XXX!CExecutionThread::ExecutionThreadProc+0x1bd 01b2ffec 00000000 kernel32!BaseThreadStart+0x34 7 Id: 890.71c Suspend: 1 Teb: 7ffd7000 Unfrozen ChildEBP RetAddr 01c2fc38 77f4372d SharedUserData!SystemCallStub+0x4 01c2fc3c 77e41bfa ntdll!NtWaitForMultipleObjects+0xc 01c2fce4 77e4b0e4 kernel32!WaitForMultipleObjectsEx+0x11a 01c2fcfc 0041d3bc kernel32!WaitForMultipleObjects+0x17 01c2fd78 004171bd XXX!CInterThreadMessageQueue<>::WaitForMessageEx+0x8c 01c2ffb8 77e4a990 XXX!CExecutionThread::ExecutionThreadProc+0x1bd 01c2ffec 00000000 kernel32!BaseThreadStart+0x34 8 Id: 890.38c Suspend: 1 Teb: 7ffd6000 Unfrozen ChildEBP RetAddr 01d2fc38 77f4372d SharedUserData!SystemCallStub+0x4 01d2fc3c 77e41bfa ntdll!NtWaitForMultipleObjects+0xc 01d2fce4 77e4b0e4 kernel32!WaitForMultipleObjectsEx+0x11a 01d2fcfc 0041d3bc kernel32!WaitForMultipleObjects+0x17 01d2fd78 004171bd XXX!CInterThreadMessageQueue<>::WaitForMessageEx+0x8c 01d2ffb8 77e4a990 XXX!CExecutionThread::ExecutionThreadProc+0x1bd 01d2ffec 00000000 kernel32!BaseThreadStart+0x34 ... 29 Id: 890.c4c Suspend: 1 Teb: 7ff9d000 Unfrozen ChildEBP RetAddr 0324fe64 77f4372d SharedUserData!SystemCallStub+0x4 0324fe68 77e41bfa ntdll!NtWaitForMultipleObjects+0xc 0324ff10 77e4b0e4 kernel32!WaitForMultipleObjectsEx+0x11a 0324ff28 00455d59 kernel32!WaitForMultipleObjects+0x17 0324ffb8 77e4a990 XXX!ReceiverThreadProc+0x49 0324ffec 00000000 kernel32!BaseThreadStart+0x34 30 Id: 890.8ac Suspend: 1 Teb: 7ff9c000 Unfrozen ChildEBP RetAddr 0334fe80 77f4372d SharedUserData!SystemCallStub+0x4 0334fe84 77e41bfa ntdll!NtWaitForMultipleObjects+0xc 0334ff2c 77e4b0e4 kernel32!WaitForMultipleObjectsEx+0x11a 0334ff44 00455b68 kernel32!WaitForMultipleObjects+0x17 0334ffb8 77e4a990 XXX!ListenerThreadProc+0x48 0334ffec 00000000 kernel32!BaseThreadStart+0x34 31 Id: 890.f44 Suspend: 1 Teb: 7ff9b000 Unfrozen ChildEBP RetAddr 0344fe78 77f4372d SharedUserData!SystemCallStub+0x4 0344fe7c 77e41bfa ntdll!NtWaitForMultipleObjects+0xc 0344ff24 77e4b0e4 kernel32!WaitForMultipleObjectsEx+0x11a 0344ff3c 00455a2c kernel32!WaitForMultipleObjects+0x17 0344ffb8 77e4a990 XXX!PublisherThreadProc+0x4c 0344ffec 00000000 kernel32!BaseThreadStart+0x34
Podemos ver que as threads em vermelho são parte de um pool (note que a pilha das threads é a mesma, chamando as mesmas funções). Agora vamos fazer debug dessas threads do pool, colocando um breakpoint bem no retorno do WaitForXXX. Repare que quando fazemos o dump da pilha, temos o endereço de retorno da função:
8 Id: 890.38c Suspend: 1 Teb: 7ffd6000 Unfrozen ChildEBP RetAddr 01d2fc38 77f4372d SharedUserData!SystemCallStub+0x4 01d2fc3c 77e41bfa ntdll!NtWaitForMultipleObjects+0xc 01d2fce4 77e4b0e4 kernel32!WaitForMultipleObjectsEx+0x11a 01d2fcfc 0041d3bc kernel32!WaitForMultipleObjects+0x17 01d2fd78 004171bd XXX!CInterThreadMessageQueue<>::WaitForMessageEx+0x8c 01d2ffb8 77e4a990 XXX!CExecutionThread::ExecutionThreadProc+0x1bd 01d2ffec 00000000 kernel32!BaseThreadStart+0x34
Esse é o endereço que será executado logo após o retorno da função. Então, se colocarmos um breakpoint nesse endereço, o programa parará logo que a thread retornar do Wait. Vamos colocar o breakpoint e usar o comando "ln" (que mostra o symbol mais próximo de uma posição de memória) para ver como o RetAddr está realmente na função que queremos:
0:027> ln 0041d3bc (0041d330) XXX!CInterThreadMessageQueue::WaitForMessageEx+0x8c 0:027> bp 0041d3bc
Pronto. Agora quando chegar uma solicitação para uma das threads, o programa parará no breakpoint e poderemos ver o que a thread faz.
Uma última dica: você pode também colocar o breakpoint somente em uma thread, caso não tenha interesse em fazer debug de todas as threads do pool (até porque se o programa estiver recebendo diversas solicitações em várias threads vai ficar difícil fazer o debug). Para isso use o modificador "~" e especifique o ID da thread antes de colocar o breakpoint:
0:027> ~8 bp 0041d3bc 0:027> bl ... 0:~008 XXX!CInterThreadMessageQueue<>::WaitForMessageEx+0x8c
Em 03/01/2005 12:36 - Comentários (1)
Meu Windows Internals já está em casa!
Fiz um ótimo negócio em encomendar o Windows Internals na Amazon antes do lançamento. A data prevista para o lançamento era de 5 de janeiro nos USA, o livro chegou na minha casa dia 4. A previsão de entrega era 2 de fevereiro... :-)
Ainda não li o livro inteiro (...), mas tudo me parece ótimo! O livro já começa com a introdução escrita por David Cutler, o arquiteto do kernel do Windows NT. Logo depois, no capítulo 1, temos uma perspectiva histórica dos componentes do Windows (subsistemas, Win32 API, meia página sobre WinFX e .NET, etc) e a apresentação ao leitor das ferramentas necessárias para escarafunchar o sistema: Debugging Tools for Windows (WinDbg e outros), ferramentas Sysinternals e Windows 2003 Resource Kit.
Certos programadores da equipe do Windows não só escreveram alguns capítulos, como revisaram todo o livro. Além disso, um dos autores (não lembro se o Mark Russinovich ou o David Solomon) teve acesso aos fontes do kernel do Windows, para ajudar a garantir a consistência e a veracidade das informações. Isso só ajuda a garantir que esse livro é definitivamente a bíblia sagrada da arquitetura NT!
Só um aviso: esse livro não é especificamente sobre programação. Apesar de experiência com programação ser bem vinda durante a leitura, o livro descreve a arquitetura do sistema, não ensina a programá-lo. Assim, caso você seja um administrador de sistemas NT/2000/XP/2003, esse livro lhe será muito útil. Conhecendo a estrutura do sistema, você terá muito mais informações para lidar com problemas, principalmente telas azuis e conflitos diversos entre softwares (já que você saberá como eles interagem entre si).
Em 06/01/2005 07:57 - Comentários (2)
Mais uma falha séria no Internet Explorer, com demonstração
Eu não uso antivírus (eu sei como o scan em tempo real é (mal) feito e sei o quanto acaba com a performance do computador), não uso Adware (que de tão bom diz que um Windows recém instalado tem spyware) nem qualquer tipo de software de segurança. Quando um computador é contaminado com algum tipo de vírus ou malware, eu removo na unha mesmo. Nada que uma busca no Google e Filemon/Regmon/ProcessExplorer/TcpView não resolvam. Apesar de não ser o mais prudente, minha experiência em arquitetura Windows (estou lendo o "Windows Internals", lembra?), um firewall bem configurado e um Windows atualizado têm me mantido longe das pragas virtuais. Eu uso Windows XP Professional (SP2 + últimas correções).
Lendo o Slashdot hoje, encontrei um link para uma página da Secunia que demostra uma nova falha encontrada no Internet Explorer. Abri meu Internet Explorer (eu uso o Firefox, é claro) e o apontei para página com o teste. Muito me impressionou quando, clicando no link para testar se o micro era vulnerável, um cmd.exe foi aberto.
Mas dessa vez a Microsoft foi bem rápida. A correção já está disponível no Windows Update. Apesar de meu Windows estar configurado para fazer atualizações automáticas, quando fiz esse teste eu tinha acabado de ligar o computador, e as atualizações ainda não haviam sido baixadas. Dez minutos depois, o Windows me avisou que haviam novas atualizações. Se eu usasse o Internet Explorer e entrasse em uma página que explorasse essa falha, seria tarde demais....
Em 11/01/2005 19:43 - Comentários (0)
Procure no Google, versão 0.1 alpha
Todo mundo tem pelo menos um amigo que faz perguntas estúpidas antes e procura no Google depois. Muitas perguntas que me fazem por e-mail ou MSN seriam respondidas pelo primeiro link encontrado pelo Google. Você também passa por esse tipo de situação? Cansado de perder a concentração quando você está programando? Seus problemas acabaram!
Além da "manezisse" de perguntar para os outros antes de procurar no Google, os manés ficam tremendamente ofendidos quando você responde com um "procure no Google". Além de se sentir ofendido, o mané age como se isso fosse óbvio (apesar disso, ele não fez o óbvio, se tivesse feito não faria a pergunta). Talvez o mané não sabia interpretar os resultados do Google...
Foi para resolver esse problema que nós (eu) do 1bit.com.br criamos o "Procure no Google 0.1 alpha". Para não responder com um "Procure no Google", ou mesmo com um link para o Google (o mané pode se sentir ofendido da mesma forma), foi criado um sistema altamente complexo de redirecionamento, que envia o mané para o Google, mas sem mandar um link do Google para ele (já que isso poderia ofender o mané).
O funcionamento é simples. Aponte seu navegador para www.1bit.com.br/png/png.php, preencha o formulário com a pergunta do mané e clique em "Gerar link". Depois é só repassar o link gerado para o mané. Quando ele clicar no link que você passou, ele será automaticamente redirecionado por nossos servidores para uma página do Google com as respostas que ele precisa.
Não é só isso! O nosso super "Procure no Google 0.1 alpha" ainda possibilita que você envie seu amigo (que além de mané não sabe inglês) para uma busca do Google somente com páginas em português!
Vamos à um exemplo de utilização do nosso fantástico "Procure no Google 0.1 alpha". Digamos que seu amigo lhe envie a mensagem "Onde posso encontrar tutoriais de ASP?". Ao invés de ser indelicado e mandá-lo procurar no Google, você acessa o nosso espetacular "Procure no Google 0.1 alpha" e gera um link para a consulta "Tutorial ASP". Depois é só repassar o link gerado para seu amigo:
http://www.1bit.com.br/png/png.php?solution=7475746f7269616c20415350266c723d6c616e675f707426686c3d70742d4252
Pronto! Agora seu amigo mané está feliz, e você pode voltar a programar em paz!
Em 12/01/2005 14:18 - Comentários (2)
Forçando a especialização de templates em C++
Estou refazendo o marshaller de um projeto meu, para que ele use menos macros e fique mais orientado a objetos. Para cada tipo de dado suportado pelo marshaler, deve haver uma classe responsável. E todas as classes devem ser derivadas de um template específico.
(Para quem não sabe o que é um marshaler, vamos lá: o marshaler é o responsável por transportar os parâmetros de uma chamada remota, de um contexto para outro. Quando você usa DCOM e chama um método que está fora do seu processo (rodando em outro EXE ou até em outro computador da rede), o marshaler do DCOM pega os parâmetros da função que você chamou, coloca isso num buffer e manda para o outro contexto. Lá ele lê esse buffer e chama a função do objeto remoto. Para o programador tudo é transparente, já que o DCOM (com uma ajuda das classes de proxy/stub) faz tudo sozinho).
No início, o código ficou assim:
template <typename T>
class CSpTypeMarshaler
{
...
};
template <>
class CSpTypeMarshaler<DWORD>
{
public:
CSpTypeMarshaler()
{
ATLTRACE("especialização para DWORD");
}
};
template <>
class CSpTypeMarshaler<GUID>
{
public:
CSpTypeMarshaler()
{
ATLTRACE("especialização para GUID");
}
};
//
// aqui vou declarar os templates
//
CSpTypeMarshaler<DWORD> DwordMarshaler;
CSpTypeMarshaler<GUID> GuidMarshaler;
CSpTypeMarshaler<char> CharMarshaler;
Até aqui tudo bem, nada que a especialização de templates não faça. Mas eu tenho um problema: é possível instanciar o template com qualquer tipo, MESMO QUE NÃO EXISTA ESPECIALIZAÇÃO PARA ELE. Como cada tipo deve ser tratado de uma forma especial, deve existir uma especialização para cada tipo.
Uma possível solução é criar um construtor para o template não especializado. Esse construtor deve gerar um erro de compilação, para que não seja possível instanciar sem especialização. Olhe como ficou agora:
template <typename T>
class CSpTypeMarshaler
{
public:
CSpTypeMarshaler()
{
//
// isso NÃO FUNCIONA, gera erro sempre
//
// #error "Você precisa especializar o template"
//
// vamos declarar uma array com limite negativo.
// Isso gerará um erro de compilação quando o template
// for instanciado sem especialização
//
char por_favor_especialize_esse_template[-1];
}
...
};
template <>
class CSpTypeMarshaler<DWORD>
{
public:
CSpTypeMarshaler()
{
ATLTRACE("especialização para DWORD");
}
};
template <>
class CSpTypeMarshaler<GUID>
{
public:
CSpTypeMarshaler()
{
ATLTRACE("especialização para GUID");
}
};
//
// aqui vou declarar os templates
//
CSpTypeMarshaler<DWORD> DwordMarshaler;
CSpTypeMarshaler<GUID> GuidMarshaler;
CSpTypeMarshaler<char> CharMarshaler;
Agora, quando eu instanciar o template com o tipo char (que não tem especialização disponível), o compilador acusará o erro:
ConfigManager_ProxyStub.h(48) : error C2118: negative subscript
ConfigManager_ProxyStub.h(46) :
while compiling class-template member function
'CSpTypeMarshaler<T>::CSpTypeMarshaler(void)'
with
[
T=char
]
Quando o programador desavisado for verificar o motivo do erro, encontrará uma variável por_favor_especialize_esse_template.Quem usa a biblioteca Boost pode usar o BOOST_STATIC_ASSERT ao invés de usar esse método da array com tamanho negativo.
Em 17/01/2005 22:23 - Comentários (7)
Com a nota 9.6, agora sou certificado em C# também
Fui lá eu, sem pretensão alguma, fazer a prova de certificação em C# (70-316). Dei só uma olhada no livro, e fui contando com a experiência e o curso intensivo de .NET que foi trabalhar com o Alfred. Como eu já não estou mais trabalhando com .NET faz 1 mês, achei prudente fazer a prova antes de esquecer o que é um DataSet (eu juro que estou tentando...) :-)
Tive uma grande surpresa ao final da prova: além de passar na prova, minha nota foi 960 (1000 é o máximo), 9.6 numa escala de 1 a 10. Confesso que fiquei feliz e impressionado. Mas agora é que vem a melhor parte: Ninguém pode falar que eu só "aponto os defeitos" do .NET porque sou um programador C++ que não consegue enxergar além dessas APIs malucas. Com essa nota, eu posso falar mal (leia-se "apontar os defeitos") do .NET com autoridade. :-)
Achei a dificuldade da prova mediana. É preciso ter bons conhecimentos em ADO.NET, saber usar de forma correta o DataReader, saber exatamente como funciona o DataAdapter (e qual sua interação com o banco de dados e com o DataSet), saber usar eventos como OnRowUpdated, além de RowErrors e coisas assim. Se você usa ADO.NET como usava o ADO, você não passa na prova. Cai também gerenciamento de Assemblies (GAC, COM Interop, etc), deploy (usando XCOPY ou MSI), WinForms (cai coisas de help e assessibilidade, que a maioria das pessoas não usa), e Debug. No meu caso, a experiência com Visual C++ e com a plataforma Windows em geral ajudou bastante, principalmente em debug e deploy.
PS: Eu não odeio .NET. Só prefiro muito mais trabalhar com C++. Eu já escrevi um artigo sobre minhas opiniões quanto ao .NET.
Em 18/01/2005 11:17 - Comentários (11)
GMail e 7Zip: A evolução do software
Realmente não há limites para o software. Enquanto os programadores e engenheiros de sistemas continuarem tentando criar algo novo, nós sempre iremos nos surpreender. O mais interessante é que a evolução do software só depende de nós, não depende diretamente dos engenheiros de hardware. Na época que o Doom foi lançado, ninguém acreditava que um computador da época conseguiria rodar um jogo com aquela qualidade. Mas John Carmack foi lá, fez um algoritmo de "3D pero no mucho", aproveitando o máximo da capacidade dos computadores. E o mundo dos jogos nunca mais foi o mesmo.
Dois softwares me surpreenderam bastante nos últimos tempos: o GMail e o 7Zip. Um webmail e um software de compactação. Algo que existe desde que a web é web. Apesar disso, os dois software tem alguns diferenciais que os fazem se destacar no meio das dezenas de opções que temos.
Vamos ao primeiro: o GMail tem um conceito simplesmente fantástico, com um interface gráfica simplesmente maravilhosa. Tão maravilhosa que desde que eu comecei a usar o GMail eu abandonei o Outlook, acho o GMail muito mais ágil. E apesar de fantástica, a proposta deles é simples: uma boa interface, bastante espaço, um sistema de busca eficiente. Eles não inventaram nada, somente agruparam boas idéias e bons recursos em um conjunto coeso. E esse conjunto coeso fez os usuários exigirem mais qualidade de todo o mercado (de webmail), e elevou o nível de todos os softwares. Todo mundo está vendo a correria do Yahoo e do Hotmail para aumentar o espaço de armazenamento (para míseros 250 MBs) e colocar mais recursos.
O segundo: 7Zip. Um software de compactação que consegue compactar até 30% mais do que o WinRAR (que já é melhor do que o ZIP). Além do algoritmo melhor, o programador teve a ousadia (que eu não entendo porque não tiveram até hoje) de acreditar que o usuário não se importaria em esperar um pouco mais pela compactação para ter um resultado final bem melhor. Em um dos testes que eu fiz, compactei uma pasta com 42MBs de DLLs e PDBs. Nas suas respectivas configurações de compactação máxima, o WinRAR produziu um arquivo de 6.8 MB, enquanto o 7Zip produziu um com 4.8 MB. Além disso, o 7Zip é free e opensource, e o WinRAR abre os arquivos produzidos por ele (extensão 7zip).
Essas boas surpresas só me ajudam a acreditar cada vez mais no ramo de desenvolvimento de software. Você não precisa ter uma idéia genial para criar um software. Se você agrupar boas idéias em um software de qualidade, você estará fadado ao sucesso (a não ser que você dê muito ouvidos ao pessoal de marketing antes de terminar o produto). Idéias maravilhosas e inovadoras são difícieis de aparecer. Mas um software de qualidade e que resolva o problemas das pessoas e das empresas é (só um pouco) mais fácil. É só acreditar e ir em frente. Se as empresas que produzem softwares de má qualidade e as consultorias desonestas conseguem ter sucesso, por que um software de qualidade não conseguiria?
Em 29/01/2005 11:39 - Comentários (8)
Ode ao C++
Resolvi a uns dias atrás escrever um post sobre algo como "Por que C++?", e convidei meu amigo (e consultor particular em padrão C++) Wanderley Caloni Jr para ajudar. Não bastasse aceitar prontamente, ele também enviou-me um poético texto que rebatizei de "Ode ao C++":
/** * @title Porque C++ * @author Wanderley Caloni Jr * @date 31.01.2005 */ É natural que um programador tenha preferência por uma linguagem. Geralmente por motivos pessoais que se refletem nas características da linguagem. Eu, por exemplo, tenho vários motivos para amar essa linguagem: Linguagem C. Todas as vantagens da linguagem C estão embutidas em C++. E sem aquele papo erudito que deve-se programar em OO para ser C++. Por ser multiparadigma, a linguagem também suporta o melhor da programação procedural e estruturada. Popularidade. C++ é o que há. Linguagem unânime e reconhecida no mundo todo como de uso geral. Dificilmente você vai encontrar um algoritmo que não tenha representação em C++. Economia e Expressividade. Pode parecer bobagem, mas coisas como operador de incremento e valor em todas expressões permite que se faça muita coisa com poucas linhas. Isso a torna muito expressiva. Isso, em outras palavras, quer dizer que você pode juntar várias expressões numa só, e esse conjunto será também uma expressão. Liberdade. Em C++ você é o culpado de virtualmente qualquer coisa de bom e ruim que aconteça no seu programa, pois você tem que seguir poucas regras e tem que ser responsável no que faz. C++ não te ajuda a seguir um bom modelo de programação com restrições embutidas. Isso a torna difícil para iniciantes, mas conforme aumenta a experiência, maior o prazer em programar. Portabilidade. A possibilidade de compilar e rodar o seu código em vários ambientes - de compilação e execução - é uma característica útil e agradável. No meu caso é só agradável, pois dificilmente faço código portável, apesar das boas noções que tenho sobre o assunto. E são essas boas noções que me permitem afirmar que C++ suporta muito bem essa possibilidade. Rapidez. Pode não ser importante em muitos casos, mas já é do instinto do programador o desejo de eficiência no código. E nada como programar numa linguagem extremamente eficiente em tempo de execução para se sentir feliz de ver o código rodando.
Após ler esse texto, eu irei - emocionado - me dedicar a escrever um texto com a minha versão e minhas opiniões. E claro, colocarei também aquela "água mercadológica no feijão", para ajudar a esclarecer que a pergunta correta não é "Por que C++?" e sim "Por que algo que não C++?"
Em 02/02/2005 19:09 - Comentários (1)
Um bom exemplo de comparação de performance entre linguagens/runtimes
Vou reproduzir aqui um comentário que vi no Slashdot, em um post que falava de uma discussão sobre a segurança da JVM e do .NET, envolvendo o Don Box:
You're quite right that Java's speed is excellent these days (for non-GUI code, at least). I've spent a lot of time recently working with a large system that was first implemented in Java (by highly skilled developers) and then ported to C++ (by greenhorns). The C++ port is only 50-100% faster, which isn't worth the price in developer time that's been wasted on memory leaks and other forms of memory corruption that were never a factor in Java. Besides that, supporting multiple platforms with the C++ version is the #definition of pain. However, the C++ version uses only about 1/4 or 1/5 as much memory as the Java version, and starts up far more quickly. If a *desktop* application needs to be deployed on older machines, or if the application is so memory-intensive it taxes the limits of today's server hardware, Java still falls flat.
Grifei as partes que achei mais importantes. Ah, e antes que você vá procurar em um dicionário, eu já fiz - greenhorn quer dizer "iniciante".
Vamos aos fatos:
Uma aplicação feita por programadores experientes em Java, quando portada para C++ por programadores novatos e inexperientes ficou (só) 50-100% mais rápida. Ok, eu prometo que vou parar de ficar repetindo que o C++ é muito mais rápido que ambientes gerenciados. Mas eu juro que só faço isso porque existem pessoas (principalmente aqui no Brasil) que ainda teimam em dizer o contrário. Agora imagine uma aplicação portada por programadores experientes...
Mesmo com o ganho de performance não valeu a pena, já que os memory leaks e erros de memória corrompida nunca aconteceriam em Java. Concordo plenamente. Os ambientes gerenciados foram criados para não deixar que esses erros aconteçam. Quando a performance não é o mais importante, faça em Java/.NET. Um programador inexperiente Java/.NET vai fazer um aplicativo lento que consome muita memória. Um programador inexperiente C/C++ vai fazer um aplicativo que dá GPF por qualquer coisa.
A versão C++ consome de 1/4 a 1/5 da memória consumida pelo aplicativo Java e inicia muito mais rápido. Esse é um dos problemas dos ambiente gerenciados, o consumo de memória. Experimente usar a extensão SOS (Sons of Strike, para debug da CLR) do WinDbg, e faça um dump de todos os objetos no heap do Garbage Collector. Você vai entender... A grande vantagem é que, apesar do consumo médio de memória ser alto, ele tem um limite no decorrer da vida do aplicativo, já que o GC recolhe todos os objetos. Já em C/C++, se sua aplicação aloca bastante memória e não desaloca, uma hora ela esgota a memória da máquina. Como sempre, em C/C++, você tem que saber o que faz e fazer direito (mais do que em ambientes gerenciados).
Esse é o tipo de comparação de performance que eu acho válida. Faça um aplicativo, de no mínimo de médio porte, e compare. Comparar performance de "Hello World"s e outras coisas simples não indicam muita coisa útil. Um exemplo: a alocação de memória em ambiente com GC é mais rápido do que em C/C++, já que envolve somente uma soma de ponteiro. A alocação em C/C++ envolve algoritmos de heap, mais complicados e demorados. E isso não faz os ambientes gerenciados mais rápidos.
Resumindo: cada ferramenta tem seu propósito (eu já disse isso várias vezes, não é?). Se o aplicativo citado fosse feito por programadores C++ experientes, ele talvez seria 300% mais rápido e consumiria 1/10 de memória. Parece óbvio fazer em C++ não? Mas não é. Talvez a empresa gaste menos pagando programadores Java e comprando mais 3 servidores. Nem sempre performance e baixo consumo de memória é o foco. Se fosse, estaríamos usando DOS até hoje...
Em 07/02/2005 19:19 - Comentários (5)
Escovação de bits ao vivo e a cores
Nada como terminar uma quarta feira com um bom chopp Brahma e discutindo tecnologias, metodologias e outras "ias" mais. Fazendo valer nossa última frase antes de irmos embora ("isso merece um post!"), deixo aqui registrado o encontro "escova bit" que participei hoje: Alfred Myers, Fabio Galuppo, e a "minha pessoa".
Depois de discutirmos de C++ à PDCs, e de Datasets à gerenciamento de projetos, voltei para casa com a certeza de que encontros para discutir desenvolvimento de software - regados a um bom chopp - fazem muito bem para saúde e para o cérebro. Esses encontros além de divertidos são muito bons para trocar experiências. Pena que hoje em dia é difícil encontrar pessoas com nível técnico, bagagem e boa vontade suficiente para isso...
Em 09/02/2005 21:48 - Comentários (1)
Google: a Microsoft da web
A grande novidade no mundo do software é o Google. Pode não parecer tão óbvio para as pessoas, já que o software deles não roda diretamente nos computadores dos usuários. Quando você faz uma consulta no Google, um cluster de aproximadamente 100.000 PCs (isso mesmo, cem mil) é utilizado para procurar em bilhões de páginas, tudo isso em questão de milesegundos. E com milhões de usuários fazendo isso ao mesmo tempo.
Apesar de todo esse sucesso com seu carro chefe, o Google está deixando de ser "a empresa do mecanismo de buscas" para ser uma empresa de aplicações web. GMail, Orkut, Google Maps, Google Suggest, Google Desktop Search... E essa lista cresce a cada dia que passa.
E como eles estão fazendo isso? Conheço milhares de empresas que desenvolvem sistemas para web e continuam só desenvolvendo sistemas para Web... O segredo deles é que eles desenvolveram mais que uma aplicação de buscas, eles desenvolveram uma plataforma para desenvolvimento de software, um software para viabilizar mais softwares. Uma plataforma de computação em cluster especializada em rodar aplicações web. E agora eles estão usando essa plataforma para desenvolver softwares que têm as mesma necessidades do mecanismo de busca: atender milhões de usuários, ter petabytes de espaço para armazenamento e um tempo de resposta mínimo.
Essa plataforma do Google envolve gerenciamento do cluster, um FileSystem distribuído (o Google File System) que roda nesse cluster, entre outros. E o melhor é que as aplicações que são desenvolvidas nessa plataforma podem aproveitar sem muito esforço qualquer melhoria que nela for feita. Eles podem focar os profissionais mais competentes na melhoria dessa plataforma, e fazer pequenos ajustes nos softwares que rodam sobre ela. Quando alguém da equipe do Google tiver a idéia para um software web, é só desenvolver em cima dessa plataforma e pronto: milhões de usuários podem usar. Isso agiliza MUITO o desenvolvimento e permite que um novo produto seja lançado no mercado em muito menos tempo. Isso deixa a concorrência maluca, porque eles não conseguem acompanhar o ritmo e acabam fazendo alguma besteira no meio do caminho. A Microsoft usou bastante essa estratégia e derrubou líderes de mercado como o WordPerfect. É bom lembrar que a própria Microsoft começou fazendo uma plataforma para desenvolvimento de software: os compiladores de linguagem BASIC.
A Microsoft construiu uma base sólida para desenvolver seu aplicativos: seus sistemas operacionais. (ok, a base só é sólida a partir do Windows NT, o Windows 9x é pior que gelatina). Tudo que a Microsoft desenvolve é em cima dessa plataforma. Cada dia que passa ela agrega valor a essa plataforma desenvolvendo mais softwares para ela. E cada dia que passa ela melhora essa plataforma para poder construir software melhores sobre ela. O Google segue a mesma linha e tem tanta competência na sua plataforma quanto a Microsoft tem na dela.
Essa é uma ótima estratégia: gerar receita agregando valor a uma plataforma base muito bem construída. Se seu software exporta uma API, e você mesmo a usa para desenvolver alguma coisa, é um ótimo sinal. Você está usando o seu software para construir software. Por que você acha que as equipe da Microsoft mais respeitadas são as do Windows e a do Visual C++?
(Procurando sobre o Google File System, encontrei um post interessante sobre esse assunto, em um blog escrito por alguém que tem um pensamento parecido sobre o Google. Vale a leitura. E antes que você fale que o Orkut é uma porcaria, não se esqueça que ele é feito em ASP.NET e não roda nessa plataforma do Google, que é baseada em Linux)
Em 11/02/2005 20:05 - Comentários (3)
10 anos de Delphi (programadores WinForms, comemorem!)
O Delphi - ferramenta da Borland baseada em Pascal que nasceu para desbancar o VB - fez dez anos de vida no dia 14 de fevereiro. A Borland tentou com o Delphi (e talvez tenha conseguido) unir o poder do C++ e a facilidade do VB.
A Borland colocou no site uma entrevista com Anders Hjelsberg, Gary Whizin, e Zack Urlocker, como parte da comemoração do aniversário. Além da Borland, os programadores WinForms também tem que comemorar, afinal, a VCL do Delphi e seu recursos (como herança visual) foram as grandes inspirações para boa parte do que está contido em System.Windows.Forms. E parabéns ao Delphi!
Em 16/02/2005 18:14 - Comentários (0)
Olhe só quem está no orkut...
http://www.orkut.com/Profile.aspx?uid=7881279797765706622
E olhe só a lista de amiguinhos dele... Achei isso navegando entre as comunidades de programação e chegando à comunidade Windows Technical: Off Topic, da (nem tanto) famosa lista de discussão homônima.
Em 17/02/2005 23:04 - Comentários (0)
Como fazer drivers para Windows NT/2000/XP/2003, parte 2
Parte 2 = continuação da parte 1 :-)
Já leu os livros recomendados na parte 1? Eu sei que leu! Então vamos ao que mais precisamos para fazer um driver.
Driver Development Kit (DDK)
O DDK é o SDK para fazer drivers, ele contém os headers C e todas as ferramentas necessárias para todas as etapas do desenvolvimento de um driver. Quando eu digo "todas as ferramentas necessárias" é verdade, até o compilador é incluído no DDK. É possível compilar drivers usando o VC++ 6 ou superior, mas é altamente não recomendado. Essa configuração não é suportada pela Microsoft, e o pessoal do newsgroup de drivers da Microsoft geralmente se recusa a responder perguntas relativas a compilação quando o "perguntador" usa essa configuração.
Para obter o DDK você tem duas opções. A primeira é ter uma assinatura MSDN. Dessa forma é só entrar no "Subscriber Downloads" e baixá-lo. Para quem não tem uma assinatura MSDN, a opção é entrar no site do Windows DDK e pagar US$ 25,00 para que a Microsoft envie o DDK pelo correio.
O DDK também vem com vários samples para várias arquiteturas de drivers (USB, SCSI, NDIS, etc) e a documentação (que também pode ser encontrada na MSDN online). A maioria dos samples são muito bons e muito bem documentados. Além disso, em boa parte das arquiteturas é recomendável que você comece a fazer seu driver a partir de um sample (ao invés de começar do zero). Drivers WDM, por exemplo, devem gerenciar Plug'n'Play, e só essa parte do código tem umas 2000 linhas...
Existe somente uma categoria de drivers que não pode ser feita com o DDK: os drivers relacionados com File System (File Systems e filtros). Para esse tipo de driver é necessário comprar o IFS Kit (Installable File System Kit), que custa a bagatela de US$ 899,00 (um amigo meu costumava dizer que era o arquivo .h mais caro que ele conhecia. Até ele perguntar para o pessoal da OSR o preço do kit de File System deles...). Os antívirus com scan em tempo real, por exemplo, são implementados como filtros de File System.
É bom lembrar que, apesar da palavra driver ser quase sempre usada para denominar um software que controla um hardware (driver da placa de som, por exemplo), no Windows é comum chamar de driver todo software que roda em kernel mode, mesmo que ele não controle hardware. Firewalls e filtros de file system são exemplos de drivers que não controlam hardware. Mesmo assim, no Windows existem alguns drivers que rodam em user mode.
Editor de código C/C++
Apesar de ser possível escrever um driver usando o Bloco de Notas, é recomendável que você use um editor apropriado para isso. Eu costumo usar o Visual Studio.NET, usando o "MakeFile Project" para compilar o driver usando o compilador do DDK e não o Visual C++. Você pode usar o editor de sua preferência.
Em 18/02/2005 18:39 - Comentários (5)
Por que o meu Visual C++ está fazendo REBUILD toda hora?
Eu tenho um Solution do Visual C++ 7.1 que tem 12 projetos, entre COM/ATL e WTL, com algumas dependências entre eles. Entre essas dependências existe um header "spmain.h" que é incluído no "stdafx.h" de todos os projetos. Ontem eu adicionei algumas declarações nesse header, já consciente que todos os meus projetos seriam recompilados. Dois minutos depois tenho todos os projetos recompilados, e começo a escrever código em modo automático, até uma hora que eu não me lembro (só lembro que passava da meia noite). Depois desliguei o modo berserker e fui dormir.
Quando fui mexer no projeto hoje de novo (sim, eu programo as domingos), percebi que o Visual C++ fazia rebuild dos projetos toda vez que eu compilava. Se fosse um projeto pequeno tudo bem, mas 30 mil linhas de C++ em 12 projetos não compila lá muito rápido...
Procurando informações sobre esse problema, encontrei um artigo do KB da Microsoft para NMAKE e Visual C++ 5.0 que falava alguma coisa sobre problemas com arquivos na rede e com a data da instalação do Visual C++. Como meus arquivos não ficam em rede, só me restava verificar o problema da data.
Tiro e queda: verificando a data dos arquivos, percebi que o "spmain.h" estava com data do dia 21/02/2005 (detalhe: hoje ainda é dia 20/02). Abri o arquivo, adicionei um CRLF e fechei. Problema resolvido! Se você tiver um problema parecido (eu já passei por isso antes), já sabe como resolver.
Outro fato interessante: um projeto C# que eu estava mexendo ontem também estava com o mesmo problema, todos os arquivos estavam com data do dia 21/02. Mas como o build do C# é MUITO mais rápido que o build C++, eu acabei nem me dando conta...
Em 20/02/2005 19:44 - Comentários (6)
Mais um benchmark interessante
A Microsoft apresenta no site do Visual C++ um benchmark interessante. A proposta é verificar a performance de um backend para o mercado financeiro (uma bolsa asiática), baseado em Visual C++, MSMQ e SQL Server. Lá eles descrevem de forma acadêmica diversos fatores que foram levados em conta, desde configuração de discos, até servidores SQL federados com chaves em hash para diminuir a concorrência e o gargalo do banco.
O artigo apresenta boas dicas sobre performance para aplicações críticas e sobre metodologias para medição disso. Performance é algo complicado de medir, porque além de ser um conceito relativo, existem diversos fatores obscuros que podem distorcer um estudo - desde um design de uso de memória que aproveite o fator localidade para facilitar o trabalho do cache do processador, até a configuração do arquivo de paginação do Windows. Como Raymond Chen já explicou, otimização de performance não é algo tão óbvio quanto parece.
No final do artigo, o autor diz que a equipe reimplementou o aplicativo em C# para fazer uma comparação de performance de processamento de mensagens entre código gerenciado e não gerenciado. Esse é um dos primeiro benchmarks que eu vejo que serve de alguma coisa. Eu já escrevi aqui algumas dezenas de vezes que comparar duas linguagens testando um algortitmo simples em loop não leva a conclusão nenhuma. O que funciona é isso, pegar uma aplicação crítica e implementar em duas linguagens. Primeiro o autor apresenta o seguinte gráfico de comparação (maior é melhor):
.gif)
E depois faz umas considerações muito interessantes sobre como essa diferença absurda entre as duas linguagens deve ser interpretada. Ele cita um fato interessante que eu já citei aqui: de que a alocação de memória em ambientes gerenciados é eficiente e tão rápido quanto C++ (o que compensa um pouco a desalocação mais lenta feita pelo GC). Além disso eles explicam que, como eu também já disse, a medida que a tecnologia da VM .NET for evoluindo a implementação em C# se tornará mais rápida e eficiente. Só que, como eu também já disse, eu vivo no presente e não no futuro. :-)
Em 22/02/2005 07:59 - Comentários (0)
Aulas de C++: como ensinar?
Estou estudando uma proposta para dar aulas de C++, e estou pensando em uma didática interessante para as aulas. Tive uma conversa com o Wanderly Caloni sobre isso e quero deixar aqui registrado. Caso alguém tenha uma sugestão ou idéia sobre o assunto, coloque nos comentários desse post. Minha idéias ficaram bem claras nesse chat, o que dispensa maiores explicações. Vamos ao chat:
Today, 09:42 Rodrigo Strauss:
como assim aulas teóricas?
Today, 09:43 Wanderley:
vc falando e uma lousa
Today, 09:44 Rodrigo Strauss:
impossível ensinar programação assim.
Today, 09:44 Rodrigo Strauss:
Vai ser eu e um projetor, um aluno por micro
Today, 09:44 Wanderley:
mmmmmm...
Today, 09:44 Wanderley:
dai facilita MUITO
Today, 09:44 Wanderley:
ainda mais q o instrutor vai saber tirar duvidas eheheehheheh
Today, 09:44 Rodrigo Strauss:
sim, e vai ser assim
Today, 09:44 Rodrigo Strauss:
to pensando em adotar uma estratégia diferente
Today, 09:45 Rodrigo Strauss:
li uma coisa no comp.lang.c++.mod e fiquei pensativo
Today, 09:45 Rodrigo Strauss:
todo mundo q ensina C++ começa pela parte difícil
Today, 09:45 Rodrigo Strauss:
ponteiros, strcpy, etc
Today, 09:45 Rodrigo Strauss:
estou pensando em já começar usando std::string
Today, 09:45 Rodrigo Strauss:
e passando tudo por valor
Today, 09:48 Wanderley:
dai vai ser vb! =P
Today, 09:51 Rodrigo Strauss:
e qual o problema? Não é mais lógico ensinar primeiro a parte fácil e depois a
difícil?
Today, 09:59 Wanderley:
em ambas as formas existem vantagens e desvantagens. no caso de comecar pelo
mais facil, a desvantagem eh esconder desde o comeco detalhes essenciais para
programar em C
Today, 10:00 Rodrigo Strauss:
não é esconder, é só começar pelo mais fácil. E eu vou dar aulas de C++, vou
deixar claro pra eles que não é aula de C
Today, 10:02 Wanderley:
separar C de C++? mmmmmmmmmm... =P
Today, 10:03 Rodrigo Strauss:
vou explicar as diferenças e similaridades e dizer que linguagem C é mais
específica
Today, 10:04 Wanderley:
seilah. penso q sao coisas indivisiveis pq uma eh parte do todo
Today, 10:04 Rodrigo Strauss:
sim... mas como vc mesmo já disse, nós não sabemos programar em C. O C tem
várias limitações e diferenças q não estamos acostumados
Today, 10:06 Rodrigo Strauss:
essas aulas vão ser muito boas pra mim, pq vão me fazer estudar mais coisas e
mais termos. Se vc me perguntar o q é polimorfismo eu não sei explicar
Today, 10:06 Rodrigo Strauss:
vou ter q comprar o livro do Stroustrup urgente
Today, 10:06 Wanderley:
geralmente a pratica acaba sendo mais fixada na mente de quem realmente
programa =P
Today, 10:07 Rodrigo Strauss:
EU CONSEGUI! Escrevi Stroustrup certo sem consultar! Stroustrup,
Stroustrup, Stroustrup!
Today, 10:07 Rodrigo Strauss:
Bjarne Stroustrup
Today, 10:07 Rodrigo Strauss:
Bjarne Stroustrup
Today, 10:07 Rodrigo Strauss:
Bjarne Stroustrup
Today, 10:07 Rodrigo Strauss:
![]()
Today, 10:09 Rodrigo Strauss:
o seu Stroustrup é em portuga, né?
Today, 10:16 Wanderley:
eiuaheiuahieuaeihauhiauehiaueaiehiahuei
eh, sim
ta afim?
Today, 10:16 Rodrigo Strauss:
mais um clique na amazon e eu compro o meu ![]()
Today, 10:17 Rodrigo Strauss:
e to pensando em comprar esse tb:
Today, 10:17 Rodrigo Strauss:
http://www.amazon.com/exec/obidos/tg/detail/-/0201749629
Today, 10:21 Wanderley:
q baum!! =D
Today, 10:22 Rodrigo Strauss:
to quase comprando... mas eu tenho gasto uma puta grana com livros ultimamente
Today, 10:22 Rodrigo Strauss:
é sempre um bom gasto, mas é um gasto. E o bom é que livros de C++ nunca ficam
desatualizados
Today, 10:27 Wanderley:
=D
Today, 10:28 Rodrigo Strauss:
vc já leu o blog do thiago adams?
Today, 10:29 Wanderley:
naum. qual o link?
Today, 10:33 Rodrigo Strauss:
http://planeta.terra.com.br/informatica/thiago_adams/codigo.htm
Today, 10:33 Rodrigo Strauss:
pena q não tem RSS
Today, 14:13 Wanderley:
onde vc viu a msg sobre ensinar c++ comecando pelo mais facil?
Today, 14:14 Rodrigo Strauss:
eu li uma mensagem no comp.lang.c++.moderated sobre um cara dizendo q o
problema é q em C++ as pessoas começar pelo contrário, pelas coisas mais
difíceis
Today, 14:14 Rodrigo Strauss:
vc não acha q ponteiro é uma ferramenta muito poderosa pra dar nas primeiras
aulas?
Today, 14:15 Wanderley:
acho
Today, 14:15 Wanderley:
na primeira aula se dá variaveis e construções simples de programação
Today, 14:15 Rodrigo Strauss:
não é melhor que o cara que está começando use std::string ao invés de fazer um
buffer overflow esperando pra acontecer?
Today, 14:16 Wanderley:
nao enquanto ele nao entender o funcionamento e os riscos de um buffer overflow
Today, 14:17 Rodrigo Strauss:
sim, mas acho q isso pode ser ensinado depois
Today, 14:17 Wanderley:
mas a lista do c++.moderated eh enorme ![]()
vc nao tem o link?
Today, 14:17 Rodrigo Strauss:
a maioria usa char* e não sabe o q é um buffer overflow
Today, 14:18 Rodrigo Strauss:
eu li ontem num post sobre c#, mas não lembro onde
Today, 14:18 Rodrigo Strauss:
esse cara não vai saber o q é um buffer overflow, mas pelo menos ele vai correr
menos riscos
Today, 14:18 Wanderley:
a maioria faz isso pq nao aprendeu todos os conceitos. soh os necessarios pra
sair programando...
Today, 14:19 Wanderley:
por isso q eu disse q eh vblizar o aprendizado: evitando riscos escondendo
perigos ![]()
Today, 14:20 Rodrigo Strauss:
eu acho q é jogar o cara no fosso com leões só depois que ele conseguir matar
um cachorro.
Today, 14:21 Wanderley:
qualquer abordagem eh valida qdo se trata de ensinar C ou C++ (ja li isso em
algum livro eheheeh). mas existem vantagens e desvantagens em todas. eh
vivendo, programando e aprendendo
Today, 14:22 Rodrigo Strauss:
minha experiência tem dito que fazer coisa low-level a toda hora por qualquer
coisa prejudica o desenvolvimento. "Humble thyself, reuse".
Today, 14:23 Rodrigo Strauss:
se eu usar std::string não vou perder tempo com corrupção de memória. E SE
FICAR LENTO, eu otimizo
Today, 14:24 Wanderley:
eu entendi. funciona. mas vc nao pode dizer q uma pessoa sabe c++ se ela nao
consegue explicar o que eh uma string em C
Today, 14:39 Rodrigo Strauss:
claro, isso eu concordo
Today, 14:39 Rodrigo Strauss:
meu ponto é só que ela deve começar pelo mais fácil
Today, 14:47 Wanderley:
isso eh questao de gosto
Today, 14:47 Wanderley:
de objetivo tb
Today, 14:47 Wanderley:
ja q eles vao mexer com mfc, eh bom q se acostumem com a ideia de classe
string, por ex
Today, 14:47 Rodrigo Strauss:
eu acho q é questão de didática e motivação
Today, 14:47 Rodrigo Strauss:
eu acho C difícil, imagina pra quem não sabe programar
Today, 14:48 Rodrigo Strauss:
é muito mais fácil alguém q nunca programou entender um
cout << "numero " << 5 << endl;
do que
printf("numero %d\r\n",5);
Today, 14:49 Wanderley:
o Ritchie ensina muito bem as nuances da linguagem em seu livro. eh claro q a
pessoa ja tem q ter um minimo de conceitos
Today, 14:49 Wanderley:
muito mais facil entender intuitivamente. mas nao tecnicamente ![]()
Today, 14:50 Rodrigo Strauss:
as pessoas tem uma visão distorcida de C++, acham q é muito complicado. Se usar
STL não é muito complicado.
Today, 14:51 Wanderley:
nao se nao der erro ![]()
Today, 14:52 Rodrigo Strauss:
sim... e algumas coisas no STL tb são phoda. como tempo de vida de um interator
Today, 14:54 Wanderley:
mas, claro, se vc usa religiosamente como manda o figurino, tudo funciona
Today, 14:56 Rodrigo Strauss:
se vc usar char* como manda o figurino nunca dá buffer overflow
Today, 14:59 Wanderley:
aih q entra o grau de dificildade =P
Today, 15:00 Rodrigo Strauss:
sim. como é mais fácil usar o std::string sem fazer besteira me parece mais
óbvio ensinar isso primeiro
Today, 15:00 Rodrigo Strauss:
do mesmo jeito que eu recomendo VB para iniciantes por ser mais fácil
Today, 15:00 Wanderley:
pior q nao eh. depende do gosto e/ou objetivo
eu recomendo basicao ![]()
Today, 15:01 Rodrigo Strauss:
eu vou pensar bastante nisso. Quero criar uma geração que não use C só por
costume (como a gente faz), e use realmente C++ e STL sempre (como eu quero
fazer daqui pra frente)
Today, 15:02 Wanderley:
ohhhhhhhhhh ![]()
nisso eu apoio. leia o livro do Stroustrup. ele eh um categorico dessa ideia
Today, 15:04 Rodrigo Strauss:
sim... no site dele ele diz que um livro de C++ que começa com printf já começa
mal...
Today, 15:05 Wanderley:
ehehehehhehehehehhe. o legal eh q ele eh categorico, mas nao eh xiita, q fala q
C++ deve ser usado soh com orientacao a objetos. eh o criador, neh. dai eh
outra coisa ![]()
Today, 15:09 Rodrigo Strauss:
O Criador... ![]()
Today, 15:09 Wanderley:
ehehehehhehehehehheh
Today, 15:15 Rodrigo Strauss:
comprei o Stroustrup!
Today, 15:15 Wanderley:
=D
Today, 15:15 Rodrigo Strauss:
Esse chat merece um post. Autoriza?
Today, 15:15 Wanderley:
agora vc ouvirah a palavra tb. e logo estara pregando a palavra =P
Today, 15:16 Wanderley:
se vc acha q merece, vai la ![]()
Today, 15:16 Rodrigo Strauss:
A palavra do Criador, sem apóstulos, sem intermediários. É como se "God
himself" tivesse escrito a Bíblia ![]()
Today, 15:17 Wanderley:
eiuhaieuhaiuehiauheiauhieua eh vero. sem interpretacoes erroneas.
eh o proprio!
Em 23/02/2005 14:36 - Comentários (3)
MandrakeSoft compra a Conectiva
Direto do Slashdot: A européia Mandrakesoft, responsável pelo famoso "Mandrake Linux", comprou a brasileira Conectiva.
Esse é sem dúvida um evento muito importante para o mercado de software brasileiro. E com tamanho interesse do governo brasileiro pelo Linux, era mesmo de se esperar que alguma empresa estrangeira do setor arrumasse uma boa forma de entrar no nosso mercado.
Em 24/02/2005 13:41 - Comentários (0)
Otimização e Pessimização
Eu li em algum lugar que "otimização precoce é pior do que nenhuma otimização", e a cada dia que passa eu tenho visto que isso é realmente verdade. Qual o motivo de otimizar um programa que você nem terminou? Na verdade você não sabe exatamente o que vai trazer problemas de desempenho. Então, na realidade, você não está fazendo uma otimização, e sim uma pessimização. Existem alguns conceitos básicos de desempenho que devemos seguir, mas não é justificável levarmos duas vezes mais tempo para fazer algo porque queremos bom desempenho. Faça primeiro, do modo mais rápido e correto possível, com o código simples e claro, e deixe para otimizar somente a parte problemática, se existir uma. Não tente resolver um problema que ainda não existe.
É muito comum programadores C++ terem preocupações excessivas com otimizações precoces e poucas preocupações em fazer um código seguro, que funcione, e feito em tempo hábil. Por isso que temos tantos buffer overflows e coisas assim. Não seria melhor usarmos std::string para tudo e parar de nos importar se ela faz uma (ou duas) cópias da string no retorno? Nós vivemos no mundo das VMs, do .NET e das linguagens script. Um código C++ que copia uma string desnecessariamente ainda será dezenas de vezes mais rápido do que tudo que existe por aí. E você ainda poderá otimizar se quiser (eles não).
Faça um programa que funcione, de uma maneira simples e com um código claro. Depois que tudo estiver funcionando, otimize o que ficou mais lento. Se você faz uma otimização precoce (usando ponteiros e memcpy irresponsavelmente, por exemplo), existe uma possibilidade de, além de não ficar tão mais rápido, você criar um buffer overflow esperando para acontecer. Se você escrever um código simples e PSICOLOGICAMENTE lento, você pode fazer a otimização depois, e testar especificamente aquele memcpy para se certificar que nada de errado vai acontecer. Com a otimização precoce, o seu memcpy suicida será testado junto com o resto do software, e não receberá a devida atenção. Mas o teste que será feito depois da otimização será específico para esse memcpy, e é muito mais provável que os erros sejam encontrados.
Hoje a velocidade os processadores é da ordem de gigahertz, podemos nos dar ao luxo de nos preocupar em otimizar as partes interessantes e fazer de forma simples e clara as partes menos interessantes. Mas não esqueça: já que não vai otimizar e está disposto a queimar alguns nanosegundos a mais, pelo menos faça o código de forma clara. Se seu medo é que o próximo programador a mexer no código fale que você faz código lento, coloque um comentário explicando que você tem mais o que fazer do que otimizar uma função que lê do registro e só é chamada uma vez...
PS: Sim, eu sou um programador C++.
Em 25/02/2005 23:43 - Comentários (7)
Testando o ASP.NET 2.0
Essa é para os interessados em teste de software (ou para os que tem inveja de equipes que tem infraestrutura de testes). Scott Watermasysk, um membro da equipe do ASP.NET, fez um post explicando com um bom nível de detalhamento como são feitos os testes do ASP.NET 2.0. Lá ele descreve o software para gerenciamento de testes que eles desenvolveram (que inveja...) e o software para controle de bugs. O software de testes gerencia os casos e cenários a serem testados e o ambiente de teste, incluindo instalação automática de software para montagem dos ambientes.
Esse post me fez lembrar uma coisa: quando eu fiz entrevista para trabalhar na Microsoft US (um dia eu conto essa história aqui), eu descobri que a Microsoft é uma das poucas empresas que tem desenvolvedores especializados em testes (eles chamam de Software Design Engineer in Test). São desenvolvedores 100% dedicados a fazer softwares para testar softwares, e para produzir maravilhas como essa que testa o ASP.NET 2.0.
Além desse post, existem alguns vídeos da Sara Ford no Channel9 Developers Division.
Em 01/03/2005 19:11 - Comentários (0)
Cante comigo
Imagine (with apologies to John Lennon)
Imagine there's no requirements. It's easy if you try
Just a bunch of coders, reachin' for the sky
Imagine all the people, coding for today
Imagine there's no schedules. It isn't hard to do
No silly project deadlines, no one supervising you
Imagine all the people, coding hand in hand
You may say I'm an extremer but I'm not the only one
I hope someday you'll join us and make coding lots more fun.
Imagine oral documentation. I wonder if you can
No need for UML diagrams. Just words passed, man to man
Imagine just refactoring, playing in the sand
You may say I'm an extremer, but I'm not the only one
I hope someday you'll join us and make coding lots more fun.
Mais uma paródia de Imagine, retirada do artigo da Wikipedia sobre Agile Software Development. Mande isso para aquele seu gerente dilbertiano que acha que RUP é a oitava maravilha do universo. Você pode dar sorte e ele ter um enfarte. :-)
Em 03/03/2005 09:01 - Comentários (0)
Mark Lucovsky vai para o Google
Pode parecer só mais um grande engenheiro de software sendo contratado pelo Google, mas para mim significa o início de uma nova era. Para quem não sabe, Lucovsky é um dos engenheiros originais do Windows NT, que veio da DEC junto com Dave Cutler para desenvolver o novo sistema operacional da Microsoft. Naquela época (1989) o projeto era fazer um kernel modular (e não um micro kernel como alguns dizem) que rodasse em um protótipo de processador da Intel (o N10) e suportasse basicamente a API do Presentation Manager do IBM OS/2. Depois de um tempo, esse novo sistema operacional (já batizado de NT, sem o "Windows" antes) foi portado para plataforma Intel e Alpha. Além disso, a API do Presentation Manager foi substituída pela API Win32, que foi criada para aproveitar o boom do Windows 3.0.
Muitos dos componentes do kernel do Windows NT/2000/XP/2003 foram feitos por Lucovsky. Na verdade toda vez que você executa um programa, você está rodando um código feito por ele (ele foi responsável pela parte do kernel que gerencia processos e threads). Ele foi responsável também pelo gerenciamento do controle de versão desses projetos gigantescos (como ele explica nessa apresentação). Mais algum dúvida sobre a importância dele para Microsoft?
Vamos agora à explicação do porquê eu acho que estamos no início (sim, no início) de uma nova era. Lucovsky escreveu um post mês passado sobre como a Microsoft não é mais a melhor em fazer, entregar e distribuir software. E a visão dele é muito interessante: quando alguém na Amazon (ou no Google) faz uma modificação no software deles, milhões de pessoas têm acesso a essa modificação na mesma hora. Quando a Microsoft faz uma modificação, esse modificação precisa de um download, muitas vezes da instalação de uma runtime (.NET), precisa que o usuário aceite um contrato, faça ativação, etc.
Lembra quando eu falei sobre a "Plataforma Google"? O Google mostra cada vez mais que está investindo nessa plataforma e ela é realmente o core da empresa. O mecanismo de buscas é, na realidade, o software mais importante que roda sobre essa plataforma.
As contratações do Google são todas na direção do que a empresa já faz, e não na criação de algo revolucionariamente novo. Contratando especialistas em sistemas operacionais (como Lucovsky e Pike) não significa que eles irão lançar um sistema operacional. Contratando especialistas em browsers (como Goodger, do Firefox) não significa que eles NECESSARIAMENTE lançarão um browser (Só mesmo o bobinho e inocente John "idéias não-tão-geniais" Dvorak para pensar assim). Essas são as plataformas que eles usam (o cluster Linux e Ajax), quanto mais eles entenderem delas mais sucesso eles terão. Se uma fábrica de automóveis contrata especialistas em aço, não significa que ela necessariamente vai entrar no ramo de siderurgia...
Em 04/03/2005 10:16 - Comentários (4)
Lista de libs C++, GCC-XML e divagações sobre computação distribuída
Encontrei duas coisas interessantes sobre C++ hoje. A primeira foi uma página com uma lista de libs C++ disponíveis. Esse lista contém links para dezenas de libs, desde as mais conhecidas (como a ACE) até libs para sequenciamento biomolecular (!?). Vale a pena perder um tempinho navegando na lista.
A segunda é o GCC-XML, uma versão (talvez "versão" não seja o termo correto) do GCC que ao invés de compilar o programa, gera um XML com a estrutura do programa. Estou desenvolvendo um framework para computação distribuída nas horas vagas, e nas últimas semanas "criei" um formato de IDL em XML. Basicamente você cria uma arquivo XML com as definições das interfaces e seus métodos, e um programinha (feito em C#) gera o código C++ para proxy/stub. Eu podia usar DCOM, mas minha infra-estrutura precisa ser flexível e extensível (e multiplataforma se possível). Isso envolve comunicação de diversas formas (TCP/IP, MSMQ, MQSeries, FileMapping, ISAPI, etc) e não ter problemas com firewall. Pode parecer que eu estou refazendo a roda (refazendo o DCOM mais precisamente), mas acho que esse framework se parecerá mais com o Indigo.
Voltando à IDL em XML: eu cheguei a pensar em usar YACC/LEX para gerar um parser para MS-IDL, mas achei que seria muito trabalhoso. No final das contas, cheguei à conclusão que um formato XML seria bem mais interessante, pois me permitiria colocar informações extras na IDL/XML (como comentários e links para documentação) sem alterar a estrutura do programa gerador - que nada mais faz do que carregar um XmlDocument e usar XPath para encontrar as interfaces e métodos. Além disso, seria mais fácil manter compatibilidade com os geradores antigos, já que usando XPath eu automaticamente ignoro qualquer propriedade ou entidade que eu não conheça.
Usando o GCC-XML eu posso até gerar o XML diretamente de uma classe C++, e "passá-lo" por um XSLT para gerar um XML no formato do meu gerador. Com isso eu poderia colocar os metadados das classes (inclusive sobre variáveis privadas) dentro do programa, e ter informações precisas em run-time, exatamente como em managed code. Seria possível até fazer um marshal-by-value automático, como acontece com as classes [Serializable] em .NET. Isso funcionaria como um TypeLibrary COM vitaminado, com informações extensas sobre as classes e dados que elas encapsulam.
Eu poderia também fazer um Attribute Provider para o Visual C++ 7.1. Eu também poderia fazer um compilador e criar uma runtime. Ah, e eu poderia ... mmmm ... esquece... Eu sou um programador solitário, e essas divagações - apesar de interessantes - levam bastante tempo para implementar...
Em 07/03/2005 16:53 - Comentários (3)
Artigo sobre WinDbg parte 3: a missão
Já está no ar a terceira parte da minha série de artigos sobre o WinDbg. Nessa parte eu explico o que são os symbols, para que servem, e porque eles facilitam tanto as nossas vidas.
Em 13/03/2005 23:23 - Comentários (0)
Algumas coisas deveriam funcionar, mas não funcionam
O trecho a seguir foi retirado do documento "MSMQ Best Practices":
Asynchronous notifications using WithEvents in Visual Basic can be a powerful feature. The idea of running code only in response to an event is quite attractive. However, note the following:
- Events can get lost, and you should periodically reenable notification.
- Multiple clients will be notified in the event of a single message. This problem is common; the application ceases to respond to user input. To fix this, ensure that all subsequent receives have timeouts set for the MQReceiveMessage function.
Note como o documento é bem específico. Eu traduziria esse trecho assim: "Os eventos podem se perder de acordo com a fase lunar, é prudente reabilitar as notificações em um intervalo que você se sinta confortável, de acordo com a sua intuição".
Em 15/03/2005 08:48 - Comentários (1)
Alguém ainda procura convites para o GMail?
Achei um site que tem +-500 mil convites do Gmail para doação. Eu testei, realmente funciona e você recebe o convite na hora. Apesar de estar quase abrindo para o povão, uma conta do GMail agora cai bem, nem que seja para usá-la como um disco virtual de 1 GB.
Em 15/03/2005 22:11 - Comentários (4)
Não tem jeito, a Microsoft não respeita os programadores VB
O suporte "standard" da Microsoft para o VB6 está chegando ao fim. Considerando a quase total incompatibilidade entre o VB6 e o VB.NET, a comunidade VB está se mobilizando (de forma tardia) para tentar reverter a situação, inclusive tentando que a Microsoft suporte o VB6 (que eles chamam de "Classic Visual Basic") e faça atualizações para ele. Foi criada uma petição, que pode ser assinada no site classicvb.org.
Até agora, a petição foi assinada por mais de 2300 desenvolvedores, incluindo 224 MVPs. O mais engraçado que é não valeu nada, a Microsoft não fez nada. Se 1 MVP tem tanta importância como ele dizem, porque 200 deles não valem nada? Não estou dizendo que a Microsoft deveria simplesmente criar o "Classic Visual Basic", mas acredito que eles mereciam mais atenção. A única reação da Microsoft foi uma entrevista que o Somasegar (cujo cargo é "Corporate Vice President - Developer Division") deu ao CNET. Achei as considerações do Somasegar ridículas e as desculpas completamente esfarrapadas:
- A Microsoft não pretende atualizar ou lançar uma nova versão do "migration wizard". Isso realmente é uma questão de (falta de) respeito.
- Fazer com que o "Classic Visual Basic" rode na IDE do VS.NET é "tecnicamente não plausível". Espero que isso queira dizer um "nós não queremos fazer", porque se isso significa dificuldade técnica, a Microsoft já não é mais a mesma.
- O Visual Basic 8 (VS 2005) será muito melhor em RAD (Rapid Application Development). Será que ele realmente entendeu do que se trata ou está mesmo fugindo do assunto? RAD por RAD, os programadores VB6 podem muito bem mudar para o Delphi, já que ele tem um RAD ótimo. Do que adianta ficar desenhando formulários multicoloridos em tempo recorde se a linguagem é incompatível? Estamos falando em compatibilidade com os milhões de sistemas desenvolvidos em VB6 até hoje.
- No Visual Studio 2005, recursos conhecidos do VB6 serão trazidos de volta, como o "Edit and Continue". Mais uma consideração ridícula. Tiraram esse recurso do VB e agora estão jogando confete por colocar de volta. É como roubar algo de alguém e devolver como um presente, 4 anos depois.
Mesmo que muitas pessoas considerem o VB6 "feio" e limitado, ele era (não sei se ainda é) a ferramenta de programação Microsoft mais usada. Existem milhões de linhas de código em VB pelo mundo, e elas ficaram estagnadas para sempre. Tudo isso porque a Microsoft está dando importância ao "puritanismo técnico" típico de programadores C++ ao invés de ouvir os clientes. "Eu devo dar o peixe ou ensinar a pescar? Achamos melhor direcionar nosso esforços para trazer os clientes para o 'novo mundo'", disse o Somasegar. Na boa, esse é um bom método para tratar crianças, não milhões de programadores. Acho que está na hora do pessoal do VB aprender com o pessoal do FoxPro como fazer para ganhar o respeito da Microsoft sem ser programador C, C++ ou C#...
Não estou dizendo que a Microsoft deveria simplesmente fazer o que esses 230 MVPs querem (ou deveria?). Só acho que ela deveria dar mais atenção à reivindicação, e tentar arrumar a situação. Eles não são usuários domésticos, são programadores que mantêm sistemas de bancos, instituições financeiras e empresas gigantescas. Será que a Microsoft pode se dar ao luxo de tratá-los como moleques que não sabem o que querem? Ah, apesar de dar a entrevista, o Somasegar não escreveu uma palavra sobre isso no blog dele.
[Atualização 17/03/2005: O Somasegar resolveu se mexer, e escreveu um post sobre isso. Repetindo que a grande resposta da MS ao assunto será criar um "VB Upgrade Center" na MSDN...]
Em 16/03/2005 22:50 - Comentários (9)
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 23/03/2005 21:50 - Comentários (0)
Eu acho que sei C++
Eu sempre achei que conhecia bem C++, afinal, trabalho com isso faz vários anos. Já fiz drivers (sim, usando C++), programas em WTL, uso bastante ATL, etc. Sempre me considerei "fluente" em C++. Meu interesse em C++ tem crescido mais e mais ultimamente, e tenho buscado ampliar meus horizontes. Com esse objetivo, comprei dois livros do Herb Sutter ( Exceptional C++ e More Exceptional C++, muito bons), o livro do Stroustrup, tenho usado muito STL, estudado Boost e generic programming. Foi então que eu descobri que o C++ moderno está um pouco longe do que eu aprendi a 7 anos atrás, e apesar de fluente em C++, eu ainda tenho muita coisa para aprender.
Se você é programador C++, faça um teste. Dê uma lida no comp.lang.c++.moderated e veja se você consegue entender as discussões. Dê uma olhada no blog do Thiago Adams e veja se você compreende tudo que ele escreve. Se você entende tudo, você realmente entende de C++. Eu até entendo tudo isso, mas programar "C++ moderno" só está virando parte do meu cotidiano agora. Mesmo assim, eu não tenho experiência nem conhecimento para implementar muitas das libs que fazem parte do Boost. Foi tão mais fácil conhecer tudo de VB6... :-)
(Para quem não sabe o que é Boost: é uma espécie de extensão extra-oficial para a Standard Template Library do C++. É formada por libs que podem ser propostas por qualquer um, é só passar pelo crivo da lista de discussões do Boost. Dez libs do Boost serão incluídas no próximo padrão C++.)
Outra coisa que eu acabei percebendo é que, apesar de o C# e o Java serem baseados em C++, eles estão muito distantes do C++ moderno. É só dar uma olhada em alguma lib do Boost e isso que eu estou falando ficará muito claro. É possível que elas se aproximem um pouco mais com a implementação de generics, mas só o tempo vai dizer. Essas linguagens são baseadas no C++ de 10 anos atrás.
Eu vou começar a dar aulas de C++ in company semana que vem. Uma das coisas que eu pretendo fazer com as minhas aulas é formar alunos que não tenham o vício que eu (nós) sempre tive(mos): usar o C++ como um C melhorado. Como eu já escrevi em post anteriores, não é preciso fazer programação low level só porque se sabe como fazer. É como usar um canhão para matar moscas. Da mesma forma que eu recorro ao C# para tarefas que ele é melhor do que o C++ (XML, por exemplo), devemos saber reusar as coisas que já estão feitas e deixar de lado o "eu não sei direito como isso funciona, não fui eu que fiz". Quantas vezes eu não fiz um thin wrapper para alguma coisa em Win32, só para descobrir depois que já tinha uma classe igual na ATL...
Isso me fez lembrar de uma coisa muito interessante: a STL ajuda muito a resolver o problema do "não fui eu que fiz". Como os containers são intercambiáveis entre si, é possível usar usar um std::map hoje, e depois trocá-lo por um hash map do Google, ou até mesmo implementar um. O padrão de interface/implementação disponível em Java/COM/CORBA/.NET ajuda nesse sentido, mas tem o problema de ser amarrado ao tipo do dado (ou boxing/unboxing desenfreado). Como a STL é toda baseada em templates e generic programming, esse problema quase some.
Bom, chega de divagações de sábado a noite...
Em 26/03/2005 23:37 - Comentários (0)
C++ com sanidade: fazendo a IDE do Visual Studio.NET trabalhar para você
Uma das coisas mais irritantes que acontecem durante o DEBUG de uma aplicação ATL, é o fato do VS.NET insistir em fazer debug das sobrecargas de operadores dos "SmartTypes" do ATL. Quando você usa "Step Into" (F11) para fazer debug de uma função, você é obrigado a passar por todas as sobrecargas de operadores antes de chegar na função. Como um pedaço de código fonte vale mais do que (e*pi)^3 palavras, vamos ao que interessa:
HRESULT DoTheFlufflers(BSTR str, VARIANT v, IUnknown* pUnk)
{
MessageBox(NULL, str, L"BSTR", MB_OK);
if(v.vt == VT_BSTR)
MessageBox(NULL, v.bstrVal, L"VARIANT", MB_OK);
else
{
MessageBox(NULL,
L"Será que você poderia, por obséqio, colocar uma string nessa Variant?",
L"VARIANT",
MB_OK);
return E_UNEXPECTED;
}
//
// dã!
//
pUnk->AddRef();
pUnk->Release();
return S_OK;
}
int main()
{
HRESULT hr;
CComBSTR str;
CComVariant v;
CComPtr pUnk;
str = L"Eu sou uma string legal, podemos ser amigos?";
v = 0xDEADBEEF;
hr = CoCreateInstance(CLSID_FLUFFLERS, NULL, CLSCTX_ALL, IID_IUnknown, (void**)&pUnk);
if(FAILED(hr))
{
OutputDebugString(L"Eu desisto...");
//
// pena que não funciona em UserMode...
//
// KeBugCheckEx(0xFFFFFFFF,0,0,0,0);
return hr;
}
DoTheFlufflers(str, v, pUnk); // <<-- Muito chato fazer Step Into nessa função...
return 0;
}
Quando você usar o F11 sobre a instrução "DoTheFlufflers(str, v, pUnk);", o VS.NET vai entrar primeiro em "ComPtrBase::operator T*()", depois em "CComBSTR::operator BSTR()", e só depois em "DoTheFlufflers". Se essa função fosse de um objeto COM (algo como "pUnk->DoTheFlufferization(str, v, pUnk)"), você ainda teria chamada de "ComPtrBase::operator ->" antes das outras. Isso realmente é muito chato.
Mas há uma solução para esse problema no VS.NET: Existe a chave [HKEY_CURRENT_USER\\Software\\Microsoft\\VisualStudio7.1\\NativeDE\\StepOver], onde você pode colocar nomes de funções que não terão StepInto. É só criar valores string com um id numérico e com valor "um_regular_expression=NoStepInto". Para ignorar todos os métodos de CComPtr, use algo como ".+CComPtr.+=NoStepInto". A minha configuração por enquanto é essa:
Windows Registry Editor Version 5.00 [HKEY_CURRENT_USER\\Software\\Microsoft\\VisualStudio7.1\\NativeDE\\StepOver] "100"=".+CCom.*Ptr.+=NoStepInto" "99"=".+CComBSTR.+=NoStepInfo" "98"=".+CComVariant.+=NoStepInfo" "97"=".+CAtlMap.*=NoStepInfo" "96"=".+CAutoPtr.+=NoStepInto"
Os valores são avaliados em ordem inversa. Essa configuração pode ser modificada sem reiniciar o VS.NET, parece que ela é recarregada a cada sessão de debug. Para maiores informações sobre esse assunto, dê uma olhada nessa mensagem de alguém da equipe do C#, que mandou um CTRL+C, CTRL+V da única documentação que existe sobre esse recurso: o código fonte da IDE do Visual Studio.NET.
Em 30/03/2005 22:56 - Comentários (3)
Nova mudança de emprego
Depois de pensar e ponderar bastante, resolvi aceitar a proposta de emprego que recebi no começo do mês: uma oportunidade para trabalhar como Arquiteto de Sistemas, em um grande banco brasileiro (não posso revelar o nome ainda). Meu trabalho será integrar e melhorar a arquitetura dos diversos sistemas COBOL existentes na empresa, além de "mentoring" para os novos desenvolvedores. A intenção do banco é montar uma equipe com uma nova geração de desenvolvedores e arquitetos COBOL, todos antenados nas novas tecnologias e sabendo usar como ninguém os novos paradigmas e best practices na área de desenvolvimento de sistemas.
Além da renumeração muito boa, a oportunidade me interessou principalmente pelo grau de desafio: trazer novas tecnologias (como generic programming, DataSets e WebServices) para o mundo COBOL, revitalizando o mainframe como parte essencial na lógica de negócios da empresa. Isso incluirá a construção de alguns drivers para mainframes (escritos em COBOL), coisa inédita no Brasil e que ajudará bastante a enriquecer o meu curriculum. Outra coisa que interessou muito é que eu terei total autonomia para fazer pesquisas e testes nessa área, já que eles acreditam que isso pode gerar muitos dividendos para banco, tanto financeiros como na parte de eficiência no atendimento e nas operações.
Pretendo contar minhas experiências nessa nova empreitada aqui no blog, o que talvez signifique uma redução na quantidade de posts com os assuntos mais comuns (C++ e mercado de software). Mas acredito que os novos assuntos agregarão muito mais informação a todos que lêem esse blog, já que provarão que qualquer tecnologia existente pode se adaptar aos paradigmas modernos.
Em 01/04/2005 13:15 - Comentários (2)
Mais libs C++, agora vindas do Google e da Adobe
O Google e a Adobe resolveram disponibilizar algumas de suas libs C++ sob licenças open source. As duas libs são compatíveis com STL, o que faz com elas possam ser facilmente integradas com a maioria das aplicações C++.
O Google disponibilizou projetos em diversas áreas, incluindo medição de performance e debug. Mas o que realmente me interessou foram os hash maps que eles fizeram. Eles são especializações (no sentido de funcionamento, não de polimorfismo) do std::map, e têm as mesmas assinaturas. Os mapas foram criados para terem vantagens em campos específicos quando comparados com o std::map. O sparse_hash_map, por exemplo, é um pouco mais lento do que o std::map, mas consome 1/3 de memória. O dense_hash_map consome 10% mais memória do que o std::map, mas é entre 5 e 10 vezes mais rápido! E como as funções são as mesmas do std::map, é fácil trocá-lo pelos mapas especializados de acordo com a necessidade, um typedef deve resolver. Dê uma olhada na página que compara a performance dos mapas, é muito interessante.
Já a Adobe disponibilizou uma biblioteca C++ razoávelmente grande. Podemos encontrar desde um mini framework para relacionamento entre entidades (descrição muito vaga, para mais detalhes veja a página do projeto) até alguns containers STL muito úteis ou interessantes (como um container forest). Tem também um template que encapsula variáveis de diversos tipos, o adobe::value_t - que é milhares de vezes mais seguro que um void pointer e "mais C++" do que um VARIANT. Com ele é possível ter um std::list que contém ao mesmo tempo strings, inteiros e tipos definidos pelo usuário.
Em 04/04/2005 16:51 - Comentários (0)
C++ com sanidade: usando ATL em aplicações, parte 2
A ATL - como eu já disse antes - cobre diversas áreas da programação Win32, não somente COM. Continuando com a minha série "C++ com sanidade", vou mostrar aqui o acesso ao registro usando ATL. Esse pequeno programa mostra um MessageBox com os HotFixes que estão instalados, lendo essas informações do registro.
#define UNICODE
#define _UNICODE
#include <atlbase.h>
#include <atlstr.h>
int main()
{
LONG l;
ATL::CRegKey regKey;
ATL::CString strKey, strBuffer;
DWORD dwLen;
static const wchar_t* wzRegPath =
L"SOFTWARE\Microsoft\Windows NT\CurrentVersion\HotFix";
l = regKey.Open(HKEY_LOCAL_MACHINE, wzRegPath, KEY_READ);
if(l != ERROR_SUCCESS)
return HRESULT_FROM_WIN32(l);
strBuffer = L"HotFixes instalados:\r\n\r\n";
for(DWORD dwCurrentKey = 0 ; ; ++dwCurrentKey)
{
ATL::CRegKey regSubKey;
ATL::CString strFixDescription, str;
dwLen = MAX_PATH;
l = regKey.EnumKey(dwCurrentKey, strKey.GetBuffer(dwLen), &dwLen);
strKey.ReleaseBuffer();
if(l != ERROR_SUCCESS)
break;
//
// agora que pegamos o nome da chave, vamos pegar o valor "Fix Description"
//
str.Format(L"%s%s", wzRegPath, strKey.GetString());
l = regSubKey.Open(HKEY_LOCAL_MACHINE,
str,
KEY_READ);
//
// se o Windows falou que existe, tem que existir. A não ser que o usuário
// seja muito rápido e consiga apagar a chave no meio da enumeração :-)
//
ATLASSERT(l == ERROR_SUCCESS);
if(l != ERROR_SUCCESS)
continue;
//
// primeiro vamos saber qual o tamanho da string
//
dwLen = 0;
l = regSubKey.QueryStringValue(L"Fix Description", NULL, &dwLen);
//
// se não tem "fix description", vamos ignorar
//
if(l != ERROR_SUCCESS && l != ERROR_MORE_DATA)
continue;
l = regSubKey.QueryStringValue(L"Fix Description",
strFixDescription.GetBuffer(dwLen),
&dwLen);
strFixDescription.ReleaseBuffer();
if(l != ERROR_SUCCESS)
continue; // xi... vamos ignorar e passar para o próximo
strBuffer.AppendFormat(L"%s - "%s"\r\n",
strKey,
strFixDescription.GetString());
}
MessageBox(NULL, strBuffer, L"Windows HotFixes", MB_ICONINFORMATION);
}
Para compilar esse código no Visual C++, use um projeto "Win32 Console Project", e não um "ATL Project". Você pode usar as classes da ATL em qualquer programa, é só adicionar os headers (no caso do ATL::CRegKey, só o atlbase.h é suficiente).
Não se esqueça que minha intenção não é fazer um tutorial sobre as classes da ATL, e sim, mostrar que essas classes existem e dar exemplos práticos de como elas podem facilitar a sua vida, ajudando-o a escrever um código mais claro e menos sujeito à erros. Para mais informações, RTFM
Em 05/04/2005 22:57 - Comentários (0)
Tinha um bug no caminho, no caminho tinha um bug
O código C++ abaixo contém diversos bugs, e se comporta de forma estranha durante a execução (faça o teste em DEBUG). Quais são os bugs e por que eles acontecem?
//
// coloque esses include's no stdafx.h, se preferir
//
#include <iostream>
#include <vector>
//
// não consigo fugir do meu vício de programação Windows...
//
#ifndef DWORD
#define DWORD unsigned int
#endif
//
// vamos usar uma classe para facilitar a mudança
//
class CTest1
{
public:
DWORD dwValue;
std::string strValue;
};
class CTest2
{
private:
CTest1* m_pTest1;
public:
CTest2(DWORD dw, const std::string& str)
{
m_pTest1 = new CTest1();
m_pTest1->dwValue = dw;
m_pTest1->strValue = str;
}
~CTest2()
{
delete m_pTest1;
}
CTest1* GetTest1() const
{
return m_pTest1;
}
};
int main()
{
std::vector vecTest2;
//
// vamos colocar um CTest2 no vetor, passando
// os valores para o construtor
//
vecTest2.push_back(CTest2(100, "1bit"));
//
// agora vamos pegá-lo e ver os valores
//
std::cout << "dwValue = " << vecTest2[0].GetTest1()->dwValue << std::endl;
std::cout << "strValue = " << vecTest2[0].GetTest1()->strValue << std::endl;
return 0;
}
No próximo post eu explico o bug. E em posts posteriores vou sugerir algumas formas de resolver o problema (sendo uma delas usando ATL, é claro!).
Em 06/04/2005 10:17 - Comentários (0)
Eu não acredito...
Dá pra acreditar? Será que nunca mais precisaremos responder (e perguntar) nos fóruns e listas de discussão? :-)
Em 07/04/2005 23:00 - Comentários (1)
Por que o bug?
Nós tínhamos um bug, que acontecia quando inseríamos (push_back) um objeto de uma determinada classe dentro de um container STL. Quando líamos o valor da variável, ela não correspondia ao valor do objeto inserido no container, e a runtime do C++ gerava um assert dizendo que estávamos chamando delete para um objeto mais de uma vez.
O problema nesse caso, foi causado por algo que o C++ não costuma fazer: um código gerado pelo compilador, algo que não foi você que fez. Nesse caso, o copy constructor. O copy constructor é um construtor especial, que é chamado quando um objeto é copiado. Isso acontece quando você atribui um objeto a outro, retorna um objeto de uma função, ou passa um objeto para uma função como valor. Um trecho de código vale mais que (pi^10) palavras:
class X
{
public:
int i;
};
X func(X obj)
{
X localx;
// mais uma cópia
localx = obj;
localx.i = obj.i;
// oh, estamos copiando novamente!
return localx;
}
int main()
{
X x1, x2;
x2.i = 10;
// copiando...
x1 = func(x2);
return 0;
}
Na função "func" do exemplo acima, existem 3 operações de cópia: uma quando passamos x2 como parâmetro, outra quando atribuimos o parâmetro obj a localx, e outra na hora de retornar localx. Nessas situações, o copy constructor é chamado para copiar o objeto em questão. Como no nosso exemplo não temos um copy constructor definido, o compilador gera um automaticamente. Olhe como fica a nossa classe X com um copy constructor, equivalente ao que é gerado pelo compilador:
class X
{
public:
//
// se definirmos um copy constructor, o compilador não gerará mais
// o construtor default. Então vamos fazê-lo
//
X()
{}
//
// copy constructor, que tem a sintaxe [tipo(const tipo& param)]
// esse copy constructor é equivalente ao gerado pelo compilador
//
X(const x& v)
{
i = v.i;
}
int i;
};
Para nossa classe X, o copy constructor não gera problemas. Agora, vamos ver o copy constructor equivalente ao gerado pelo compilador para nossa classe com bug:
class CTest2
{
private:
CTest1* m_pTest1;
public:
...
//
// copy constructor equivalente ao gerado pelo compilador
//
CTest2(const CTest2& v)
{
m_pTest1 = v.m_pTest1;
}
...
~CTest2()
{
delete m_pTest1;
}
};
Note que m_pTest1 é a única variável membro de CTest2. Então a única coisa que é feita é copiar o valor dessa variável (que é um ponteiro). Note que - isso é importante - o construtor não é rodado no caso de cópia de objeto. Sendo assim, o objeto cópia não terá um ponteiro alocado com new, mas sim, a cópia do ponteiro do objeto do qual ele foi copiado. Assim, tentaremos chamar delete para o mesmo ponteiro, mas nas duas instâncias de CTest2 - o que gera o assert que falei.
Se você está se perguntando onde é feita a cópia no código do exemplo do bug, repare que eu criei um objeto temporário diretamente ao invés de criar um objeto:// // criamos um objeto temporário do tipo CTest2, chamando // o construtor para inicializá-lo // vecTest2.push_back(CTest2(100, "1bit"));
O construtor do nosso objeto temporário é executado logo antes da chamada da função (push_back), e o destrutor é chamado logo após o retorno da função. A função push_back espera uma referência para o objeto (const CTest2&), então não é feita a cópia durante a passagem de parâmetros. Mas o objeto é copiado ao ser inserido no vector<>, o que faz com que o copy constructor gerado seja chamado, e copie o valor do ponteiro.
Uma das possíveis soluções é criarmos um copy constructor para nossa classe com bug, fazendo com que um novo objeto CTest1 seja criado durante a cópia. Assim, cada classe pode chamar delete para o seu ponteiro. Nossa classe ficaria assim:
class CTest2
{
private:
CTest1* m_pTest1;
public:
...
CTest2(const CTest2& v)
{
m_pTest1 = new CTest1();
//
// por falar em copy constructor, essa instrução chamará o copy constructor
// da classe CTest1, copiando todos os membros
//
*m_pTest1 = v.m_pTest1;
}
...
~CTest2()
{
delete m_pTest1;
}
};
Nossa solução é eficaz nesse caso. Mas e se precisássemos que as duas cópias usassem o mesmo ponteiro? Aguarde os próximos posts.
Em 09/04/2005 12:43 - Comentários (4)
Mais explicações sobre copy constructors
Aquele post sobre copy constructors gerou para mim uma dúvida existencial: por que o compilador os gera automaticamente? Não é lá muito comum que os compiladores C++ gerem código.
Depois procurar no FAQ do Stroustrup e não encontrar, resolvi perguntar aos gurus do comp.lang.c++.moderated. Se eles não soubessem, nem o próprio Stroustrup saberia, e eu continuaria até o fim dos meus dias com o peso da dúvida sobre os ombros. As respostas foram muito interessantes.
Em 11/04/2005 16:35 - Comentários (3)
Alguém pode me explicar o que é isso nas estatísticas do meu site?
| |||||||||||||||||||||||||
CP/M???? Alguém anda usando CP-500 para acessar meu site?? :-)

Em 11/04/2005 19:49 - Comentários (8)
Essa estatística é mais do que compreensível
| ||||||||||||||||||||||||||||||||||||||||||||||
Eu achei que essa grande quantidade de acessos usando Firefox era isolada, mas essa porcentagem vem crescendo a cada mês. Eu sei que meu site é direcionado para um público mais técnico, mas mesmo assim fico feliz. Sou usuário do Firefox desde a versão 0.1, quando ele ainda se chamava Phoenix.
Mesmo os microsoftianos mais fanáticos que se recusam a largar seu browser fraquinho devem agradecer muito à equipe do Firefox. Foram eles que conseguiram fazer a Microsoft se mexer e ressuscitar a equipe do IE (mesmo que a nova equipe tenha uns caras de pau).
Em 12/04/2005 22:45 - Comentários (0)
Por que um programador explica teoria musical melhor do que um músico?
Eu já estudei teoria musical (com algum esforço eu leio uma partitura) e toco violão, guitarra e bateria. Já li várias coisas sobre musicalidade e teoria musical, mas nada tão claro e bem explicado quanto a explicação do Eric Lippert.
(Eric Lippert é um programador da Microsoft que já apareceu em vários vídeos do Channel9 e trabalhou na equipe do VBScript)Por que um programador explica teoria musical melhor do que um músico? Ou será que eu entendo melhor por ser um programador, e pelo fato dele explicar música como um programador?
Em 13/04/2005 16:52 - Comentários (0)
Adobe compra a Macromedia
Adobe compra a Macromedia por US$ 3,4 bilhões.
Traduzindo: A empresa líder no ramo de software para mídia tradicional (Acrobat [Reader], PhotoShop, Illustrator, etc) compra a empresa líder no ramo de software para mídia online (Flash, Shockwave, DreamWeaver, Fireworks). Resta saber o que será feito com os softwares que "fazem as mesmas coisas", como GoLive e Fireworks, Illustrator e FreeHand.
Em 18/04/2005 13:55 - Comentários (3)
Trabalhando como PJ ou como CLT
Eu trabalho atualmente como PJ (pessoa jurídica, emitindo nota fiscal), mas já trabalhei como CLT. A maioria das pessoas costuma discutir as vantagens e desvantagens das duas modalidades, muitas vezes sem saber a real implicação de cada uma. Vou mostrar alguns fatos sobre as duas modalidades, mas nada que esgote todos os detalhes do assunto.
PJ
- Custo para empresa: somente o custo da nota fiscal e mais algum benefício que ela resolver dar. Eu conheço uma empresa que contrata como PJ, mas oferece férias remuneradas (você emite uma nota mas não trabalha) e 13º (você emite uma nota com o dobro do valor em dezembro). Eu tenho férias remuneradas, mas não tenho 13º, e isso muda de empresa para empresa. A maioria das consultorias (cuidado com elas) não oferece nada.
- Custos para o "funcionário": O custo é de 13,33% por nota fiscal emitida (IRRF (4,80%), COFINS (3%), PIS (0,65%), CSLL (2,88%), ISS para empresa de software em São Paulo (2%)) mais o custo do contador (entre R$ 100,00 e R$ 260,00 por mês), para uma empresa LTDA. Alguns impostos são recolhidos mensalmente (como o ISS) e outros trimestralmente. Uma parte dos impostos trimestrais são retidos pela empresa pagadora de acordo com o valor da nota, senão você mesmo paga. Resumindo: é uma bagunça generalizada. Não vou começar um discurso criticando esse modelo tributário estúpido, remendado e sem sentido porque eu prometi para mim mesmo que não falaria de política no blog. Arrume um bom contador (de preferência por indicação) que resolva isso para você.
- Salário: Geralmente maior do que quando se é CLT. Uma parte do que a empresa (note que eu disse uma parte) economiza com encargos é repassado ao salário. Varia entre 20% e 100% maior do que CLT.
- Benefícios: Quase nada. Ao invés de ter o governo como um pai, dizendo o que você deve fazer com o que você ganha, você recebe tudo em dinheiro. Fica por sua conta fazer uma previdência privada, pagar plano de saúde, pagar sua alimentação, etc. Fazer uma previdência privada e ter dinheiro guardado são duas coisas muito importantes para quem trabalha como PJ. Se você não sabe administrar seu dinheiro, talvez seja melhor ser CLT e deixar o governo cuidar dele. Afinal, o governo é especialista em cuidar do nosso dinheiro (e pegar uma boa parte dele).
- Garantias: Você tem as garantias que o contrato de prestação de serviço te dá. Não tem garantias da CLT como seguro desemprego, multas rescisórias, indenizações, aviso prévio etc. Geralmente é algo muito mais simples do que a mão pesada da CLT: "eu trabalho, você me paga, e só". Você pode ter desde nenhuma garantia, até 3 meses de notificação para cancelar o contrato. Se no contrato não diz nada sobre tempo de notificação para rescisão, a empresa pode te demitir hoje, dizendo que amanhã você não precisa mais aparecer. Mas, da mesma forma, você pode arrumar um emprego melhor e dizer que você pode começar amanhã (na prática costuma-se dar uma ou duas semanas de notificação). É recomendado pedir ajuda de um advogado para interpretar e ajustar o contrato.
- Liberdades: Assim como as garantias, depende do contrato, mas geralmente são maiores do que o regime CLT - tanto para o "funcionário" quanto para o contratante. Você também tem a liberdade de ter a previdência e o plano de saúde que você quer. No caso da previdência, além das previdências privadas serem bem mais baratas, você pode pagar para ter um benefício maior do que o limite de R$ 2400,00 do INSS. Nesse regime a empresa tem facilidade para contratar e facilidade para demitir. Esse é um dos motivos pelos quais os profissionais desatualizados (e sindicalistas) não gostam do regime PJ, é mais fácil ser demitido por incompetência ou incapacidade. Mas também é muito mais fácil sair da empresa, pois não é preciso se preocupar com todas as burocracias da CLT (aviso prévio, homologação, exame médico, etc). Em um mercado dinâmico como o nosso eu acho isso importante. Conheço programadores que fecham projetos de 3 a 6 meses, a burocracia disso pela CLT seria um inferno. Como um PJ ganha por hora trabalhada, não existe o desconto do descanso remunerado. Quando você falta, deixa de receber somente aquelas horas, que podem ser compensadas outro dia.
CLT
- Custo para empresa: Entre 130% e 230% do valor do seu salário. Isso mesmo, até 230% do seu salário! Por isso que as empresas relutam em contratar, porque o custo é excessivamente alto e a burocracia também. Como a burocracia é alta, a empresa também tem um alto custo administrativo.
- Custos para o funcionário: Eu fiz uma simplificação da fórmula para calcular o salário líquido para quem ganhar mais que o limite do IR (2.326,00 e paga 27,5% de IR). A fórmula é (0,725 * salário bruto) + 238,00, e ela dá uma diferença de até R$ 10,00 para mais ou para menos. Mas é ótima para dar uma idéia do valor do salário e suficientemente simples para ser decorada. Pelo modo normal você tem que calcular INSS, limite de INSS, IR, etc. Note que isso não conta o IR que for restituído na declaração e que, além os descontos previstos nessa fórmula, a empresa pode descontar vale-transporte, vale-refeição e o plano de saúde.
- Salário: Geralmente menor do que quando se é PJ, já que a empresa gasta bastante dinheiro com impostos e benefícios. Além do salário em dinheiro, esses benefícios devem ser levados em conta na hora de calcular o salário.
- Benefícios: Geralmente muitos, a empresa passa a ser praticamente um pai. Você é obrigado a pagar previdência (o que seria bom se o custo/benefício da previdência do governo não fosse ruim), e muitas vezes recebe vale transporte, vale refeição, plano de saúde, etc. Apesar de ser aparentemente muito bom para o funcionário, isso aumenta bastante o seu custo e não permite o remanejamento desse dinheiro. Por exemplo, um funcionário que vai almoçar em casa não pode receber vale refeição em dinheiro, e um funcionário que já tem plano de saúde porque está como dependente do pai também não pode receber o valor do plano de saúde da empresa em dinheiro.
- Garantias: Um mês de aviso prévio antes de ser demitido, a empresa é obrigada a pagar 15 dias do seu salário em caso de acidente (o resto é por conta da previdência). Você tem direito ao FGTS (que pode ser usado para compra de um imóvel), seguro desemprego, licença saúde e licença maternidade. Esses seguros são úteis para quem consegue pagar suas contas com o limite do benefício do INSS (R$ 2400,00). A garantia de emprego por ser CLT é uma ilusão, a empresa pode demitir da mesma forma. Como a burocracia e os custos para demissão são altos, a empresa evita contratar porque ela sabe que quando precisar demitir precisará passar por tudo isso.
- Liberdades: Você tem o direito de trabalhar :-).
Note que não existe um regime melhor do que o outro, tudo depende do caso e da situação. Existem empresas que contratam como CLT e você recebe 17 salários por ano. O salário de um PJ é quase sempre maior do que um CLT, e você tem mais liberdade. É necessário fazer as contas e ver o que vale mais a pena.
Eu prefiro trabalhar como PJ porque acho importante ter liberdade, e prefiro pagar meu próprio plano de saúde e pagar minha própria previdência. Esse regime está longe do ideal, mas ainda acho o menos pior. Mesmo assim, se eu recebesse uma proposta CLT que fosse muito boa eu aceitaria. Tudo depende das condições e do mercado. Essa é a minha opinião pessoal, e não vale para todas a pessoas. Lembre-se que eu falei que alguém que trabalha como PJ deve ser razoavelmente organizado, e pagar sua própria previdência e plano de saúde. A CLT tem garantias muito importantes (exames médicos e seguros para o caso de doença), mas a tamanha burocracia dificulta muito as contratações. Chegamos a um ponto em que, apesar do imposto para PJ ser alto, ele ainda é menor do que o da CLT. Esse é o retrato do absurdo: é mais barato ter uma empresa do que ser um funcionário.
Não se esqueça que eu sou só um programador. Confirme esses dados com seu advogado ou contador antes de tomar alguma decisão.
Em 19/04/2005 15:53 - Comentários (63)
Resolvendo o bug usando um smart pointer feito em casa
Lembra do bug? Solucionei o problema criando um copy constructor (construtor chamado quando um objeto é inicializado com o valor de outro) para a nossa classe CTest2, de forma que em caso de cópia um novo objeto fosse criado. Isso resolveu o nosso problema para essa classe específica.
Minha segunda solução é criar um smart pointer (template que se comporta exatamente com o ponteiro original) que faça a cópia. Assim, não é mais necessário implementar o copy constructor só porque a classe tem um ponteiro como membro. Se o objeto apontado por esse ponteiro deve ter o tempo de vida igual ao do objeto que o contém (o que é o nosso caso), isso funciona como um luva.
Nosso smart pointer além de gerenciar cópia, ainda desaloca o objeto automaticamente. Sim, a mesma coisa que muitas runtimes fazem ao custo do seu programa ficar muito mais lento... Bom, vamos ao código, porque ele sempre vale mais do que 6378 palavras:
#include <iostream>
#include <vector>
#include <string>
#ifndef DWORD
#define DWORD unsigned int
#endif
//
// nosso template para copiar o objeto apontado
//
template <typename T>
class CopyPointer
{
public:
T* p;
CopyPointer()
{
p = NULL;
}
~CopyPointer()
{
Free();
}
void Alloc()
{
Free();
p = new T();
}
void Free()
{
if(p)
{
delete p;
p = NULL;
}
}
void Attach(T* pT)
{
if(pT == p)
return;
Free();
p = pT;
}
T* Detach()
{
T* tempp = p;
p = NULL;
return tempp;
}
//
// copy constructor. Quando for copiado dessa forma,
// vamos copiar o objeto ao invés de copiar o ponteiro
//
CopyPointer(const CopyPointer<T>& c)
{
//
// isso vai chamar o copy constructor de T
//
p = new T(*c.p);
}
//
// isso permite que haja cópia a partir de um ponteiro raw, não
// só pelo nosso smart pointer
//
CopyPointer(const T* pT)
{
p = new T(*pT);
}
CopyPointer& operator=(T* pT)
{
if(p == pT)
return *this;
if(p)
*p = *pT;
else
p = new T(*pT);
return *this;
}
CopyPointer& operator=(const CopyPointer<T>& pT)
{
if(p == pT.p)
return *this;
if(p)
*p = *pT.p;
else
p = new T(*pT.p);
return *this;
}
operator T*() const
{
return p;
}
T* operator->() const
{
return p;
}
bool operator!() const
{
return (p == NULL);
}
bool operator<(T* pT) const
{
return p < pT;
}
bool operator==(T* pT) const
{
return p == pT;
}
};
class CTest1
{
public:
CTest1() : dwValue(0)
{}
DWORD dwValue;
std::string strValue;
};
class CTest2
{
private:
CopyPointer<CTest1> m_pTest1;
public:
CTest2()
{
m_pTest1.Alloc();
}
//
// Não preciso mais de um destrutor para desalocar o ponteiro.
// E nem precisei usar um linguagem mais limitada ou uma runtime lenta
//
CTest2(DWORD dw, const std::string& str)
{
m_pTest1.Alloc();
m_pTest1->dwValue = dw;
m_pTest1->strValue = str;
}
CTest1* GetTest1() const
{
return m_pTest1;
}
};
int main(int argc, char* argv[])
{
std::vector<CTest2> vecTest2;
CTest2 t1, t2;
t1.GetTest1()->dwValue = 50;
t1.GetTest1()->strValue = "baba";
//
// chamando o copy constructor
//
CTest2 t3 = t1;
//
// chamando operator=
//
t2 = t3;
//
// vamos colocar um CTest2 no vetor. Isso faz uma cópia
//
vecTest2.push_back(CTest2(100, "1bit"));
//
// agora vamos pegá-lo e ver o seu valor
//
std::cout << "dwValue = " << vecTest2[0].GetTest1()->dwValue << std::endl;
std::cout << "strValue = " << vecTest2[0].GetTest1()->strValue << std::endl;
return 0;
}
Só não tenho certeza do "const correctness" do meu smart pointer. Alguém se habilita?
Em 01/05/2005 19:54 - Comentários (1)
Trabalhamos no ambiente correto?
Minha profissão é "Desenvolvedor de Software", "Analista Programador" - ou programador mesmo, no coloquial. Sim, no coloquial, porque minha profissão envolve muito mais do que programar um computador. Meu trabalho envolve fazer reuniões para definição de projetos, reuniões para resolver problemas em servidores, procurar soluções para os mais diversos problemas e estudar sobre tecnologias que podem ser usadas para resolver esses diversos problemas. Além disso, envolve transformar todos os meus estudos e conhecimentos em linguagens e tecnologias em uma solução. Dessas várias atribuições que eu falei, só as reuniões envolvem várias pessoas interagindo e dialogando. Todas envolvem pensar e resolver problemas. Ou seja: a grande maioria do meu trabalho envolve raciocínio, e conseqüentemente, concentração.
Em todas as bibliotecas (de livros, não de software) que eu entrei até hoje, era proibido conversar e fazer barulho. Tudo isso porque os freqüentadores estavam lá para ler, estudar ou resolver problemas. Não é exatamente isso que eu faço no dia-a-dia? E por que a biblioteca é silenciosa e todos os lugares que eu trabalhei até hoje eram mais barulhentos do que um galinheiro? TODOS os lugares que eu trabalhei eram barulhentos, alguns mais, outros menos. Já trabalhei em empresas de software, provedores de Internet, bancos, bolsas de valores. Além disso já fiz entrevista em várias empresas e pude ver como era o ambiente. A coisa mais evoluída que eu vi foi separar os desenvolvedores do pessoal de suporte telefônico. Mesmo assim, todos os desenvolvedores ficavam amontoados na mesma sala. Em algumas empresas, a mesa de reuniões era NA MESMA SALA do desenvolvimento. Se houvesse uma reunião do seu lado, paciência. Minha única solução sempre foi a que a maioria usa: fones de ouvido e música.
Será que nossa mesa minúscula (muitas vezes compartilhada) com um computador é o melhor lugar para fazer o que nós fazemos? Por que em Universidades conceituadas (não sei como é nas UNICACAs) cada professor tem sua sala? Qual a diferença de necessidade de concentração entre um professor da USP e um desenvolvedor tentando fazer debug de um algoritmo de load balance? As empresas geralmente organizam as mesas dos desenvolvedores da mesma forma que organizam as mesas dos auxiliares administrativos. E o gerente que solta a pérola "Nosso software deve ser portado para Linux nem que isso leve 15 dias" tem uma sala exclusiva. Os gerentes - que geralmente são os que menos trabalham - são os que geralmente têm sala exclusivas. Será que isso está certo?
Quem assiste o Channel9 da Microsoft ou lê sobre as condições de trabalho lá deve ter visto que eles dão UMA SALA PARA CADA DESENVOLVEDOR. Será que esse é um dos motivos pelos quais eles são a Microsoft e as outras empresas de software não passam de outras empresas de software? Tudo que eu queria era uma sala só para mim, com um sofá de 3 lugares para poder deitar e pensar (ou até dormir um pouco...). É muito difícil pensar na reengenharia de um cluster sentado em uma cadeira desconfortável e com uma mesa minúscula. Uma lousa e um pouco de silêncio seriam muito bem vindos.
Bom, enquanto eu não abro minha empresa de software, continuo com meu fone companheiro...
Em 04/05/2005 22:01 - Comentários (13)
WinDbg Live Programming: Fazendo um log das chamadas à MessageBox
Nesse exemplo, nós faremos uma espécie de log de todas as chamadas para MessageBox que um processo fizer. Toda vez que um MessageBox for chamado, a string passada será passada também para OutputDebugString. Dessa forma, é possível usar o DebugView da Sysinternals para salvar isso em um arquivo (ou somente ver no WinDbg mesmo).
Para fazer isso, vamos criar uma "função" em tempo real (em assembly), e redirecionar o fluxo do programa para ela toda vez que o MessageBoxExW for chamado. No Windows NT (NT/2000/XP/2003), a função MessageBox nada mais faz do que chamar MessageBoxEx, que é quem realmente faz o trabalho. Além disso, quando chamamos MessageBoxA (quando você compila seu programa em ANSI, MessageBox é um define para MessageBoxA), ela só "traduz" sua string para UNICODE e repasa para versão W. Sendo assim, fazendo nosso hook em MessageBoxExW vamos pegar todas as variantes.
Chega de teoria e vamos à escovação de bits:
A primeira coisa que precisamos fazer é alocar memória para a nossa "função". Isso pode ser feito usando o comando ".dvalloc" do WinDbg, que aloca memória no espaço de endereçamento do processo. Vamos alocar 1kb de memória:
0:000> .dvalloc 1000 Allocated 1000 bytes starting at 00230000
Agora temos a nossa memória. Vamos salvar o endereço dela no pseudo-registrador $t0 do WinDbg. O WinDbg possui 20 pseudo-registradores ($t0 até $t19) para usos como esse. Para isso, usaremos o comando "r", que altera o valor de um registrador:
0:000> r $t0 = 0x00230000
Como as strings enviadas para o MessageBox não necessariamente são terminadas com CRLF, vamos colocar um na nossa memória para podermos dar uma quebra de linha na string que enviaremos ao OutputDebugString. Fazemos isso usando o comando "ezu" para gravar uma string UNICODE na nossa memória (cujo endereço está em $t0). Depois de fazer isso, vamos usar o comando "db" para ver a memória, pasando L0xF no final para dizer que só queremos ver 0xF bytes:
0:000> ezu $t0 "\r\n" 0:000> db $t0 L0xF 00230000 0d 00 0a 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
Agora que já temos nosso "ENTER" na memória, vamos à parte que interessa: escrever o código. Vamos escrever o código logo depois da string que acabamos de gravar. Como a string é UNICODE, seu tamanho em bytes é 6 (dois caracteres UNICODE mais o 00 00 no final). Vamos gravar o início do nosso código no pseudo registrador $t1 e escrevê-lo para chamar o OutputDebugString, passando o ponteiro da string que veio em EAX como parâmetro. Aqui vamos usar o comando "A" para começar a escrever o código assembly e depois usaremos o comando "U" para verificar se o disassembly ficou como queríamos:
0:000> r $t1 = $t0 + 0x6 0:000> a $t1 00230006 push @eax push @eax 00230007 call kernel32!OutputDebugStringW call kernel32!OutputDebugStringW 0023000c push 0x00230000 push 0x00230000 00230011 call kernel32!OutputDebugStringW call kernel32!OutputDebugStringW 00230016 int 3 int 3 00230017 0:000> u $t1 00230006 50 push eax 00230007 e8aaf54f79 call KERNEL32!OutputDebugStringW (7972f5b6) 0023000c 6800002300 push 0x230000 00230011 e8a0f54f79 call KERNEL32!OutputDebugStringW (7972f5b6) 00230016 cc int 3 00230017 0000 add [eax],al 00230019 0000 add [eax],al 0023001b 0000 add [eax],al
Duas coisas devem ser notadas no trecho acima. A primeira é que vamos chamar o OutputDebugString duas vezes, uma para string recebida em EAX e outra para o nosso CRLF. O ideal seria concatenar isso em um novo buffer, mas para uma aplicação single threaded isso funciona sem problemas. A segunda coisa é que coloquei um "int 3" no final do código. Isso é um breakpoint, e caso o processador passe do meu código (eu vou redirecionar isso antes com um BP), ele vai parar no breakpoint forçado e eu posso resolver o problema. O código depois do "int 3" deve ser ignorado, é o disassembly de "00 00 00 00".
Nosso próximo passo é fazer o WinDbg redicionar o fluxo do programa para a nossa função toda vez que o MessageBoxExW for chamado. Para isso vamos usar o suporte que o BP (comando para breakpoint) nos dá para executar comandos toda vez que um breakpoint for atingido. Vou mostrar o comando primeiro e explicar depois:
0:000> bp user32!MessageBoxExW "r $t2 = @eip ; r eax = poi(@esp+8) ; r eip = $t1 ; g"
Os comandos na string depois do BP serão executados assim que o breakpoint for atingido. Note que são vários comandos separados por ";". Vamos à explicação:
- r $t2 = @eip: Vamos salvar o ponteiro de instrução do processador (EIP) em $t2. Tem um "@" antes para dizer ao WinDbg para interpretar isso como um registrador, e não tentar procurar symbols para isso;
- r eax = poi(@esp+8): Esse é fácil :-) Vamos colocar o apontado do segundo parâmetro da pilha no registrador EAX. Quando chegamos numa função, o primero parâmetro está em ESP+0x4, o segundo em ESP+0x8, etc. Dessa forma estaremos colocando em EAX o ponteiro para a string que foi passada no segundo parâmetro da MessageBoxEx;
- r eip = $t1: Aqui vamos colocar o endereço da nossa "função" em EIP. Isso faz com que o processador comece a executar as instruções que estão na nossa "função".
- g: Hey, Ho, Let's Go!
Resumindo: Quando chegarmos em MessageBoxExW, vamos colocar a string em EAX, salvar a instrução atual em $t2 e mandar o processador para a nossa "função".
Agora que já fizemos o redirecionamento para nossa "função", precisamos fazer com que o processador volte para a MessageBoxExW depois de executar nosso código, fazendo com que o programa siga seu fluxo normalmente. Para isso, vamos usar a mesma técnica que usamos no primeiro breakpoint, modificar o EIP:
0:000> bp $t0 + 0x16 "r eip = $t2 ; g"
Se você chamar um "U $t0 + 0x16", vai ver que esse é o endereço do nosso "int 3", que vem logo depois do nosso código. Aqui nós estamos colocando um breakpoint que será atigindo logo depois da segunda chamada à OutputDebugString. A única coisa que temos que fazer nesse momento é restaurar o EIP usando o conteúdo antigo dele que salvamos em $t2 e deixar o programa seguir seu curso. Com isso teremos o nosso log.
Pronto, isso deve funcionar. Abra no WinDbg qualquer programa que chame um MessageBox, siga os passos acima, e veja as mensagens mostradas no prompt do WinDbg. Teste também a visualização com o DebugView.
Isso tudo funcionou porque OutputDebugString é __stdcall (ou seja, a função chamada que restaura a pilha). Se a função fosse __cdecl (quem chamou restaura a pilha), o nosso assembly ficaria um pouco maior. A única API Win32 que eu sei que é __cdecl é a wsprintf, porque ela recebe parâmetros dinamicamente.
Segue o log completo dos comandos usados para isso:
0:000> .dvalloc 1000 Allocated 1000 bytes starting at 00230000 0:000> r $t0 = 0x00230000 0:000> ezu $t0 "rn" 0:000> db $t0 L0xF 00230000 0d 00 0a 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 0:000> r $t1 = $t0 + 0x6 0:000> a $t1 00230006 push @eax push @eax 00230007 call kernel32!OutputDebugStringW call kernel32!OutputDebugStringW 0023000c push 0x00230000 push 0x00230000 00230011 call kernel32!OutputDebugStringW call kernel32!OutputDebugStringW 00230016 int 3 int 3 00230017 0:000> u $t1 00230006 50 push eax 00230007 e8aaf54f79 call KERNEL32!OutputDebugStringW (7972f5b6) 0023000c 6800002300 push 0x230000 00230011 e8a0f54f79 call KERNEL32!OutputDebugStringW (7972f5b6) 00230016 cc int 3 00230017 0000 add [eax],al 00230019 0000 add [eax],al 0023001b 0000 add [eax],al 0:000> db 0x230000 00230000 0d 00 0a 00 00 00 50 e8-aa f5 4f 79 68 00 00 23 ......P...Oyh..# 00230010 00 e8 a0 f5 4f 79 00 00-00 00 00 00 00 00 00 00 ....Oy.......... 00230020 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 00230030 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 00230040 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 00230050 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 00230060 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 00230070 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 0:000> bp user32!MessageBoxExW "r $t2 = @eip ; r eax = poi(@esp+8) ; r eip = $t1 ; g" 0:000> bp $t0 + 0x16 "r eip = $t2 ; g"
E aqui vai o fonte do programa simples que eu fiz para testar:
#define WIN32_LEAN_AND_MEAN
#define UNICODE
#define _UNICODE
#include <windows.h>
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
wchar_t wzBuffer[128];
DWORD dwInterval = 1000, dwCount = 10;
for(DWORD a = 0 ; a < dwCount ; a++)
{
wsprintf(wzBuffer, L"mensagem %d", a);
MessageBox(NULL, wzBuffer, L"LOG", MB_OK);
Sleep(dwInterval);
}
return 0;
}
Para maiores informações veja o help do WinDbg (RTFM). Boa escovação de bits!
Em 06/05/2005 11:42 - Comentários (2)
Série sobre programação de Drivers no CodeProject
Um programador de drivers com boa alma escreveu uma série de artigos sobre o assunto no Code Project. Aos interessados:
Driver Development Part 1: Introduction to Drivers
Driver Development Part 2: Introduction to Implementing IOCTLs
Driver Development Part 3: Introduction to driver contexts
Driver Development Part 4: Introduction to device stacks
Driver Development Part 5: Introduction to the Transport Device Interface
Destaque para a parte 5, que explica como fazer um cliente TDI. TDI (Transport Device Interface) é a interface usada por drivers para fazer comunicação via rede (equivalente ao WinSock, só que em kernel mode). Eu já fiz um filtro de TDI, e descobri da pior forma que TDI é complicado e tedioso. Não bastasse isso, a explicação da MSDN deixa bem a desejar...
Em 10/05/2005 12:46 - Comentários (1)
Os códigos que eu tenho que aguentar
Em todas as empresas que eu já trabalhei, tive que dar manutenção em diversos sistemas, muitas vezes feitos por pessoas que nem trabalham mais na empresa. Eu já passei infinitas horas tentando entender o que foi feito, quase sempre em um código confuso e com nenhum comentário. Agora que eu estou trabalhando com otimização de performance em componentes já existentes, minha situação piorou. Eu preciso antes entender COMPLETAMENTE o que o componente faz, ao invés de entender somente a parte que eu preciso modificar.
Meu amigo Gilberto já passou por mais empresas do que eu, porque ele aceitava [se sujeitava a] pegar projetos com 4 meses de duração. Depois de algumas discussões sobre os diversos estilos de código que encontramos durante nossa longa jornada (isso deveria ter uma música dos anos 60 como trilha sonora...), ele me apareceu no dia seguinte com essa pérola que vos mostro, entitulada "Os códigos que eu tenho que agüentar".
Nos exemplos abaixo, programadores com diversos perfis (prático, metódico, enigmático, etc) se propõem a criar uma função que retorne o resultado de (2 + 2). Cada estilo de programador faz de uma forma diferente, como vemos abaixo:
//
// Prático
//
int soma()
{
return 2 + 2;
}
//
// Enigimatico
//
int soma()
{
int a = 1;
a = a << 1;
a = (++a)++;
return a;
}
//
// Metódico
//
int soma3()
{
int a;
int b;
int c;
a = 2;
b = 2;
c = a + b;
return c;
}
//
// Aprendeu orientação a objetos ontem
//
class cVal
{
private:
int valorInterno;
public:
int GetValue()
{
return valorInterno;
};
void SetValue(int i)
{
valorInterno = i;
};
int Soma(cVal CV)
{
return this->GetValue() + CV.GetValue();
};
};
int soma()
{
cVal a,b;
a.SetValue(2);
b.SetValue(2);
return a.Soma(b);
}
//
// Macaco velho
//
int soma()
{
return 4;
}
//
// Experiente
//
static const int Soma2_2 = 4; //2 + 2 = 4
//
// STL maníaco
//
#include <vector>
#include <functional>
#include <numeric>
template<typename T>
int supersoma(T p1, T p2)
{
typedef T _MyType;
return std::plus<_MyType>()(p1,p2);
}
template<typename T>
int supersoma2(T p1, T p2)
{
std::vector<T> v;
v.reserve(2);
v.push_back(p1);
v.push_back(p2);
return std::accumulate(v.begin(), v.end(), 0, std::plus<T>());
}
template<typename T, bool b>
int supersoma3(T p1, T p2)
{
return b ? supersoma<T>(p1,p2) : supersoma2<T>(p1,p2);
}
template<typename T, bool b>
class SuperSoma4
{
public:
int operator()(T p1, T p2)
{
return supersoma3<T,b>(p1,p2);
}
};
static const bool qual_somal = false;
int soma()
{
// Stroustrup e Alexandrescu sejam louvados
return SuperSoma4<int, false>()(2,2);
}
Eu dei minha contribuição, com o exemplo "STL Maníaco". Se você conhece algum perfil que eu não mostrei, sinta-se à vontade para colocar um exemplo nos comentários.
Em 11/05/2005 14:43 - Comentários (10)
Alguém viu as especificações do XBOX360?
É de babar, e de pensar quando eu vou ter um micro com esse poder no meu desktop (ou quantas semanas o pessoal do Linux vai demorar para portar e hackear). Olhem só alguns detalhes da máquina:
|
Xbox 360 System Performance Specifications | |
| Custom IBM PowerPC-based CPU |
|
| Memory |
|
Algo me diz que todos os projetos de computação distribuída (inclusive o meu se eu tiver tempo) serão portados para o XBOX360, já que os videogames são mais baratos do que os computadores, e nesse caso específico mais poderoso que um PC comum. Isso também prova que os computadores poderiam ser mais baratos, já que um computador com essas especifícações custa muito mais que um videogame (eu duvido que esse XBOX vá custar mais do que US$ 399,99).
Além disso, teremos um videogame multicore e com suporte a 6 threads simultâneas, o que fará que os desenvolvedores de jogos comecem a explorar o uso de múltiplas threads, o que não é feito hoje. Assim, como os jogos para XBOX são feitos em DirectX (C++ e COM) e "quase compatíveis" com um PC, os jogos feitos para aproveitar o poder do XBOX também aproveitarão o poder dos PCs com múltiplos processadores e com multicores/hyperthreading, o que acaba por melhorar a qualidade dos jogos para PC também. Atualmente ter dois processadores não melhora o desempenho da maioria dos jogos, já que eles são single threaded.
Para mais detalhes, veja a especificação completa liberada pela Microsoft. O último videogame que eu tive foi um SuperNES, a muuuuito tempo atrás. Acho que esse eu vou ser obrigado a comprar...
Em 13/05/2005 08:08 - Comentários (8)
Problemas no carro? Instale o último Service Pack
Nos Estados Unidos, a nova moda são os carros híbridos gasolina-eletricidade. Além de não ser necessário ligá-los na tomada (as baterias são carregadas com a energia cinética dos freios e pelo próprio motor a gasolina), eles economizam bastante gasolina e são potentes, já que o motor elétrico é ligado para "dar uma força" quando o carro exige mais potência.
Mas esse mês os proprietários do modelo Toyota Prius tiveram um estranho problema: o motor era desligado quando o carro estava em alta velocidade. Em condições normais de uso, os motores são ligados e desligados dependendo da situação: em baixas velocidades, só o motor elétrico é usado, e quando o carro está parado o motor a gasolina chega a ser desligado. Quando a velocidade aumenta, o motor a gasolina assume a responsabilidade. E tudo isso é controlado por um software, que a Toyota também licenciou para as outras montadoras (li isso na Wired do mês passado). O problema do desligamento do motor em alta velocidade é devido a um bug nesse software, o que fez a fabricante convocar os seus donos para atualizarem o software, em uma das autorizadas. Ou seja: levar o carro à uma oficina para o mecânico instalar um patch, um service pack.
Não bastasse os carros mais modernos estarem usando um computador de bordo (sujeitos a vírus), temos mais essa. E aquela piada de programador que fala que para o carro funcionar é só desligar e dar partida novamente está virando realidade...
Em 16/05/2005 23:27 - Comentários (1)
Não sou o único na contra mão do MsMarketing
Pérola que eu li em um newsgroup um dia desses: "Não sei como, nos dias de hoje, ainda existem pessoas que escrevem uma nova aplicação Windows usando Win32 ou MFC ao invés de usar Windows Forms". Como eu sei que existe uma imensa massa de programadores que definitivamente não sabem o que falam, eu resolvi não discutir. Já ouvi tantas pessoas que acreditam que qualquer coisa pode ser feita em .NET, que hoje em dia eu prefiro não discutir e continuar com o meu Visual C++.
O primeiro problema disso é a definição de conceito e o entendimento da arquitetura das coisas. Falar que não usar Windows Forms não faz sentido é completamente sem sentido, já que o Windows Forms não passa de um wrapper sobre a Win32 API. Além disso, a MFC não passa de outro wrapper para a Win32 API, só que com mais de 10 anos de mercado e MUITO mais maduro do que o Windows Forms (que ainda tem vários bugs). Eu sempre achei o Windows Forms aquém das minhas expectativas para desenvolvimento de aplicativos Win32, mas acredito que a escolha da ferramenta sempre deve ser feita com calma e pesando todos os fatores, como experiência, tempo para desenvolvimento e alcance do aplicativo. É inviável fazer um aplicativo para download em .NET, já que só a runtime dá uns 25 MBs. (Não me venha com esse papo de que isso está melhorando, que mais pessoas tem o Framework instalado, etc. A grande maioria da base instalada não tem Framework e nem sabe o que é isso).
Semana passada encontrei mais algumas pessoas que compartilham da minha opinião. A primeira é a equipe que desenvolveu o newsreader Sauce. Ele foi totalmente desenvolvido em .NET, como muitos dos leitores RSS que existem hoje. Depois de não conseguir fazer o aplicativo ficar mais rápido e consumir menos memória, eles decidiram abandonar o .NET e refazer em "old unmanaged code". A nova versão ainda está em beta, mas é bem mais rápida do que a versão .NET e consome metade da memória. Fiz algumas medições entre a versão .NET e nativa (feita em C++ Builder, Delphi ou Kylix), e como dados concretos valem mais do que c palavras, vamos a eles:
| Tempo de inicialização | |
| .NET | Nativo |
| 36 | 6 |
| 25 | 2 |
| 12 | 1 |
| 16 | 5 |
| .NET | Nativo |
| 45.492 KB | 24.144 KB |
O argumento que todos os .NETers sacam assim que são "atacados" é que a aplicação usada não foi bem escrita, que não segue os best practices de alocação de memória, não usa corretamente IDisposable, bla, bla, bla. Se é tão difícil assim fazer uma aplicação com boa performance e consumo de memória razoável em .NET, é melhor continuar usando C++. Pelo menos em C++ a regra de alocação/desalocação de memória é clara, e não depende de saber quem precisa ou não de Dispose(). Além disso, tem o argumento barato de que as máquinas vão ficar mais rápidas, que a memória vai ficar barata, que o Bush vai recobrar a sanidade algum dia e que em um futuro não muito distante todos os micros terão Framework instalado. Eu desenvolvo aplicativos hoje, para clientes de hoje, que têm máquinas de hoje. Eu acho que o Windows Forms vai ficar muito melhor no futuro (Avalon), mas não posso viver lidando com coisas em fase experimental e SOs que ainda estão em alpha. Quem já tem experiência no mercado sabe que a migração para o Longhorn - ou a instalação da runtime do Avalon em todas as máquinas - deve demorar alguns anos.
Outra pessoa que compartilha da minha opinião chama-se Mark Russinovich. Para quem vive em outro mundo e não o conhece, ele além de escrever os programas do site SysInternals é o escritor do livro Windows Internals, a bíblia sagrada da arquitetura Windows. Ele escreveu um post sobre isso, e como esperado, foi impiedosamente atacado pelo cardume de Piranhas.NET. Devido ao grande número de comentários negativos, ele explicou novamente o que já tinha explicado e as Piranhas.NET não tinham lido. Compartilho da mesma opinião: .NET é bom para componentes e maravilhoso para Web (ASP.NET é muito bom). Mas Windows Forms aumenta muito o consumo de CPU e memória sem trazer grandes vantagens (traz até alguns problemas). E wrapper por wrapper eu prefiro meu WTL. :-)
Em 23/05/2005 14:31 - Comentários (27)
Tem gente que leva isso a sério demais...
Em 25/05/2005 19:38 - Comentários (4)
O outro lado da moeda
Um usuário Linux fez uma avaliação do Windows XP Home, e chegou a conclusão que ele está quase bom para o uso em desktops. Apesar de ter sido colocado na sessão de humor do site, todas as críticas e considerações que ele faz têm fundamento, e mostra que em alguns pontos o Linux com KDE ou Gnome é bem melhor do que o Windows. Eu achei interessante pelo fato da comparação estar considerando como base o Linux, e não o Windows. E o melhor de tudo: o "avaliador" soube elogiar os pontos fortes do Windows, sem simplesmente falar mal como faz a "banda podre" do Linux.
Em 28/05/2005 15:43 - Comentários (10)
Explicando a sopa de letrinhas da programação C/C++ para Windows: Win32
Outros posts dessa mesma série: ATL COM MFC
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.lib Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86 Copyright (C) Microsoft Corp 1984-1998. All rights reserved. win.cpp Microsoft (R) Incremental Linker Version 6.00.8447 Copyright (C) Microsoft Corp 1992-1998. All rights reserved. /out:win.exe user32.lib win.obj








