Archive for September, 2007

Mais contatos

28 de September de 2007

Tem se tornado mais freqüente, pelo menos pra mim, a procura por desenvolvedores especializados em Kernel do Windows. O que é freqüente para mim? Bom, além das empresas que presto consultoria regularmante e que imagino já estarem cansados de me perguntar se conheço mais programadores de Kernel, duas empresas me pediram indicações somente neste último mês. Uma delas é a empresa que está levando um dos meus amigos, Rodrigo Strauss, para Porto Alegre. Mais difícil que encontrar vagas para este tipo de desenvolvimento, é encontrar desenvolvedores para este tipo de vaga. Normalmente quando alguém me pede uma indicação, acabo dizendo que depois de mais de dez anos de expericênia como programador, posso contar todos que conheço utilizando apenas uma das mãos.

O fato é que ambos são difíceis de encontrar, assim, estou me dispondo a encaminhar convites e oportunidades da área de Kernel Windows aos leitores deste blog que se interessarem. Os interessados devem entrar em contato por e-mail para que eu possa expandir essa nossa rede de contatos. Tentem evitar deixar endereços de e-mail na área de comentários do post, pois deste modo qualquer um (incluindo spammers) podem ver seus e-mails. Se você ainda não tem meu endereço de e-mail, basta obté-lo no meu pefil do Blogger. Mesmo quem não estiver interessado em novos desafios, pode mandar um olá. Assim vou poder saber quantos de vocês já trabalham com Kernel de Windows e tentar começar a utilizar os dedos da outra mão nessa contagem.

Uma iniciativa parecida com esta está no site da OSR Online, onde diversas empresas deixam vagas especializadas em Kernel de Windows. Quem sabe daqui a uns cem anos, quando meu blog estiver mundialmente famoso, empresas queiram publicar vagas para programadores de Kernel do Brasil aqui no DriverEntry.com.br.

Por enquanto gostaria apenas de sabem quantos são e quem são os Kernel Coders brasileiros, mas estarei aberto a sugestões. Tudo vai depender do volume e da quantidade de respostas que vou obter nessa minha tentativa.

Até mais…

Mais ieu num sei Ingrêis

27 de September de 2007

Foi através deste post que fiquei sabendo que já está disponível para navegação o beta do conteúdo do MSDN (incluindo o WDK) traduzido automáticamente para Português e outras línguas.

Para os que têm problemas em entender o texto original em Inglês, agora podem desfrutar de todo o conforto de ter os mesmos problemas em entender o texto agora em Português. Isso porque a tradução automática fica aquela beleza, mas já ajuda para quem tem pouco ou nenhum Inglês.

O resultado é exibido no já conhecido layout do MSDN, mas o texto principal virá com um split que irá separar o texto em Português do seu equivalente em Inglês. Talvez isso fique melhor quando deixar de ser beta, mas de qualquer forma, não deixa de ser uma alternativa.

Dê uma olhadinha:
Introdução do kit de drivers do Windows

Traduções automáticas podem ser bem engraçadas. Já vi traduções nojentas em manuais de produtos importados. É uma pena eu não ter encontrado aquele manual do PenDrive que comprei há pouco tempo para poder compartilhar algumas pérolas.

Device Driver Programming == Motorista de dispositivo programando

Be careful!

Try, Except, Finally e IoWriteErrorLogEntry (Parte 1)

25 de September de 2007

A maioria de vocês já deve conhecer o tratamento de exceção da linguagem C. Sabendo que a Run Time C em Kernel não oferece suporte ao tratamento de exceções do C++, o tratamento de exceções do C nos cai como uma luva. Exceções nem sempre significam que um erro crítico ocorreu, mas independente disso, tratá-las é essencial. Uma exceção não manipulada em Kernel significa tela azul. Em se tratando de uma exceção inesperada, tal como um Access Violation, conseguimos prevenir o sistema de terminar em azul utilizando manipuladores de exceção. Isso é ótimo, parabéns, mais uma vida salva, mas não podemos nos esquecer que houve uma exceção inesperada. Esse post não vai falar como utilizar manipuladores de exceção em detalhes, mas vai falar sobre como podemos reportar eventos como esses ao administrador do sistema.

Uma típica manipulação de exceção

Para os desavisados de plantão, vou apenas dar uma breve descrição sobre manipulação de exceção no fonte abaixo. Detalhes estão na referência. O fonte a seguir foi retirado de um dos exemplos disponíveis neste blog. Esta função consegue nos salvar de uma impiedosa tela azul no caso de o mané que chamar esta função passar uma string inválida como fonte desta duplicação.

/****
***     DupString
**
**      Recebe uma Unicode String e a duplica.
**      A string resultante deve ser liberada
**      utilizando a função RtlFreeUnicodeString
*/
 
NTSTATUS
DupString(IN PUNICODE_STRING   pusSource,
          OUT PUNICODE_STRING  pusTarget)
{
    NTSTATUS    nts = STATUS_SUCCESS;
 
    __try
    {
        __try
        {
            //-f--> Inicializa destino
            pusTarget->Buffer = NULL;
 
            //-f--> Aloca buffer de destino
            if (!(pusTarget->Buffer = (PWSTR)ExAllocatePool(PagedPool,
                                                            pusSource->Length)))
                ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
 
            //-f--> Copia buffer
            RtlCopyMemory(pusTarget->Buffer,
                          pusSource->Buffer,
                          pusSource->Length);
 
            //-f--> Copia tamanhos
            pusTarget->MaximumLength = pusTarget->Length = pusSource->Length;
        }
        __finally
        {
            //-f--> Se algo deu errado, desalocamos buffer de destino
            if (AbnormalTermination())
                if (pusTarget->Buffer)
                    RtlFreeUnicodeString(pusTarget);
        }
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
        nts = GetExceptionCode();
 
        DbgPrint("DupString >> An exception occourred at "__FUNCTION__
                 " with status 0x%08x.\n", nts);
 
        ASSERT(FALSE);
    }
    return nts;
}

Repare que existem dois blocos de execução. O mais externo, que vai lidar com exceções não manipuladas, e o mais interno, que vai lidar com finalizações. O manipulador do bloco de exceções vai executar o bloco __except quando alguma exceção for lançada de dentro do bloco __try. Isso nos dará a oportunidade de tentar descobrir o que ocorreu e em alguns casos até solicitar que a instrução que causou a exceção seja re-executada. O bloco de finalização __finally é executado quando a linha de execução sair do bloco principal, seja pelo simples fim do bloco, por um return, por um goto para fora do bloco, ou mesmo uma exceção que foi lançada. O bloco __finally é sempre executado. Isso nos dá a oportunidade de liberar qualquer recurso que tenha ficado pendente durante a execução do bloco. Juntando tudo, podemos imaginar a seguinte situação: Vamos supor que a função RtlCopyMemory lance uma exceção, neste caso, o bloco __except será executado, mas para que isto ocorra, o fluxo de execução vai sair do bloco mais interno também, causando assim a execução do bloco __finally.

Dentro de cada manipulador existe uma chamada de função especial. Dentro do __except temos a GetExceptionCode, que nos retorna o código da exceção que foi lançada. Esta função só pode ser chamada dentro deste contexto. Note também que dento do bloco __finally existe a chamada à função AbnormalTermination que indica que o bloco não foi executado até o seu final. Em nosso exemplo, utilizamos esta função para determinar que algo errado aconteceu e que é necessário liberar o buffer que seria retornado à função chamadora. Enfim, dê uma olhada na referência para uma completa descrição destes recursos.

O principal ponto a notar aqui, é o ASSERT ao final do bloco __except. Caso este fonte seja compilado em Checked, o ASSERT causará um prompt no depurador. Caso não haja um depurador conectado ao sistema, então uma tela azul será exibida. Isso porque esta macro lançará a exceção de break para o depurador, mas como o depurador não estará lá para manipular esta exceção, então já viu. Quando compilado em Free, a macro ASSERT é traduzida para nada, nossa função vai manipular a exceção e graciosamente retornar o código da exceção à função chamadora. Que lindo, mas quando o administrador vai ficar sabendo?

Um sinal de vida

A maneira padrão de deixar este sinal é escrevendo no registro de eventos do sistema. O que é isso? Este link pode lhe dar informações detalhadas sobre o logs de eventos do sistema. Para escrever um registro nesta lista a partir do Kernel, temos inicialmente que alocar o buffer que vai carregar toda as informações do registro utilizando a função IoAllocateErrorLogEntry.

PVOID 
  IoAllocateErrorLogEntry(
    IN PVOID  IoObject,
    IN UCHAR  EntrySize
    );

O ponteiro retornado por esta função, apesar de ser do tipo PVOID, aponta para uma estrutura do tipo IO_ERROR_LOG_PACKET, que possui tamanho variável dependendo das informações que a compõe. Essa estrutura é utilizada para empacotar todos os dados do evento que será logado.

typedef struct _IO_ERROR_LOG_PACKET
{
    UCHAR MajorFunctionCode;
    UCHAR RetryCount;
    USHORT DumpDataSize;
    USHORT NumberOfStrings;
    USHORT StringOffset;
    USHORT EventCategory;
    NTSTATUS ErrorCode;
    ULONG UniqueErrorValue;
    NTSTATUS FinalStatus;
    ULONG SequenceNumber;
    ULONG IoControlCode;
    LARGE_INTEGER DeviceOffset;
    ULONG DumpData[1];
 
} IO_ERROR_LOG_PACKET, *PIO_ERROR_LOG_PACKET;

Embora esta estrutura tenha três quilos de membros, você não vai precisar preencher a maioria deles. Feito isso, o passo seguinte é passar a estrutura para a função IoWriteErrorLogEntry e pronto. Como disse um amigo meu: “É mel na sopa”. Provavelmente ele misturou a frase “É mel na chupeta” com algo que leve sopa. Ainda não consegui descobrir o que seria. Alguma dica?

VOID 
  IoWriteErrorLogEntry(
    IN PVOID  ElEntry
    );

Vai pensando que é fácil

Então é só alocar a estrutura, inicializá-la, chamar a função de escrita e correr para o abraço? Engraçada esta pergunta. Há pouco tempo atrás estive em Porto Alegre, e lá me disseram que quando uma explicação é iniciada por “É só…”, o trabalho real é cinco vezes maior que o explicado. Vamos começar escrevendo a tão famosa frase “Hello World” para ver o tamanho da encrenca.

Muito bem… Onde é que passo a mensagem mesmo? Ah tá, isso mesmo, no arquivo de mensagens. Diferente dos arquivos de log que normalmente fazemos em aplicações, as mensagens não são passadas diretamente para a função de escrita. Ao invés disso, o membro ErrorCode da estrutura IO_ERROR_LOG_PACKET recebe o identificador da mensagem a ser exibida. Quando a função IoWriteErrorLogEntry é chamada, esta coloca o pacote em uma lista em memória. Mais tarde, este pacote é gravado no arquivo de log de eventos do sistema. O EventViewer, software utilizado para visualizar tais eventos, obtém o identificador da mensagem contido no pacote. Com esse identificador, ele localiza a string que vai estar armazenada em um módulo em separado. Este módulo pode ser o próprio driver ou uma DLL. Assim, a string é lida desse módulo e exibida ao usuário. Ufa!

Hã? Quem? Quando? Onde? Vamos nos basear no driver de exemplo mais simples que temos para adicionar estes recursos. Vamos começar compondo o módulo de mensagens escrevendo um arquivo texto de extensão .mc. Este arquivo texto vai ser compilado pelo Message Compiler. Esta compilação irá gerar o arquivo de recurso que conterá as strings junto com o arquivo de header que fará referência a alguns símbolos criados. Veja o modelo de arquivo de mensagem abaixo:

MessageIdTypedef = NTSTATUS
 
SeverityNames =
(
    Success         = 0x0:STATUS_SEVERITY_SUCCESS
    Informational   = 0x1:STATUS_SEVERITY_INFORMATIONAL
    Warning         = 0x2:STATUS_SEVERITY_WARNING
    Error           = 0x3:STATUS_SEVERITY_ERROR
)
 
FacilityNames =
(
    System          = 0x0
    DriverEntryLogs = 0x2A:DRIVERENTRY_FACILITY_CODE
)
 
LanguageNames =
(
    Portuguese  = 0x0416:msg00001
    English     = 0x0409:msg00002
)
 
MessageId = 0x0001
Facility = DriverEntryLogs
Severity = Informational
SymbolicName = EVT_HELLO_MESSAGE
 
Language = Portuguese
"Ola mundo!"
.
Language = English
"Hello world!"
.

Repare que podemos ter a mesma mensagem em várias línguas. Nossa que chique hein? Salve este arquivo com o nome de LogMsgs.mc. Pode ser o nome de sua preferência, mas lembre-se que este nome vai se repetir nos arquivos gerados. Para compilar este arquivo, basta colocá-lo na lista de fontes a serem compilados que fica no arquivo sources do seu projeto como mostra abaixo. Se você decidir que as mensagens deverão ser contidas dentro do próprio driver, então é necessário adicionar o arquivo LogMsgs.rc que vai ser gerado pelo Message Compiler.

TARGETNAME=Useless
TARGETPATH=obj
TARGETTYPE=DRIVER
 
SOURCES=LogMsgs.mc\
        Useless.c \
        LogMsgs.rc

Depois de compilado, os arquivos LogMsgs.rc e LogMsgs.h serão gerados. O arquivo de header define os códigos de erros definidos no arquivo de mensagens e deve ser incluído nos fontes que farão as chamadas para a criação do log. Observe um trecho deste arquivo que foi gerado automagicamente.

//
// MessageId: EVT_HELLO_MESSAGE
//
// MessageText:
//
//  "Ola mundo!"
//
#define EVT_HELLO_MESSAGE                ((NTSTATUS)0x402A0001L)

Finalmente já podemos escrever as linhas de código que utilizarão toda essa parafernália que criamos.

#include 
#include "LogMsgs.h"
 
/****
***     DriverEntry 
**
**      Ponto de entrada do nosso driver, tudo começa aqui,
**      depois vai enrolando, enrolando, ...
*/
 
NTSTATUS DriverEntry(IN PDRIVER_OBJECT  pDriverObject,
                     IN PUNICODE_STRING pusRegistryPath)
{
    PIO_ERROR_LOG_PACKET    pLogPacket;
 
    //-f--> Aloca a entrada para o evento
    pLogPacket = IoAllocateErrorLogEntry(pDriverObject,
                                         sizeof(IO_ERROR_LOG_PACKET));
 
    //-f--> Inicializa toda a estrutura
    RtlZeroMemory(pLogPacket, sizeof(IO_ERROR_LOG_PACKET));
 
    //-f--> Coloca a mensagem desejada
    pLogPacket->ErrorCode = EVT_HELLO_MESSAGE;
 
    //-f--> Envia a entrada para a lista de eventos
    IoWriteErrorLogEntry(pLogPacket);
 
    //-f--> Ufa, conseguimos chegar até aqui, isso merece
    //      um retorno de sucesso para o sistema.
    return STATUS_SUCCESS;
}

Tudo pronto agora?

Do ponto de vista do driver já está tudo pronto. O driver já pode ser compilado, carregado e assim criar a entrada no log carregando o número da mensagem a ser exibida pelo EventViewer. Depois de pôr o driver para rodar, vamos abrir o EventViewer e localizar a entrada gerada pelo nosso driver, e assim, ver a mensagem.


Ops! Ainda temos que informar ao EventViewer o módulo responsável por armazenar as strings. Em nosso caso, as mensagens estão no próprio driver. Para isso temos que adicionar uma chave com nome do nosso driver dentro da chave de registro do EventLog. Dentro desta chave, ainda termos que criar dois valores informando o path do módulo que conterá as mensagens e quais tipos de eventos nosso driver pode gerar. Observe com atenção o caminho do registo na figura abaixo.


Assim que entramos com os valores acima descritos no registro, é só reabrir o mesmo evento para que a mensagem seja exibida como se deve. Lembre-se que o driver não precisa enviar o evento novamente para que a mensagem seja exibida corretamente. O driver apenas manda uma entrada com o identificador da mensagem. Isso já foi feito independente do módulo de mensagem ter sido configurado. Na figura abaixo podemos observar as mensagens em português e em inglês, dependendo da língua do sistema operacional. Olha que bunitim!

Como este post está ficando maior que eu esperava (pra variar), vou dividi-lo em partes. Ainda pretendo comentar sobre como inserir parâmetros nas entradas e esclarecer a dúvida que alguns de vocês podem estar se fazendo neste instante: “Se a entrada do log fica inicialmente em uma lista ligada, e só depois de um tempo é que efetivamente vai para disco, as entradas podem ser perdidas se a máquina cair neste intervalo?”.

Será que o culpado é mesmo o mordomo? Será que a Matrix está dentro de outra Matrix? Tostines vende mais porque é fresquinho, ou é fresquinho porque vende mais? Não percam!
Até mais… 🙂

Como assim eu não gosto de tela azul?

3 de September de 2007

Não que eu morra de alegria toda vez que vejo uma. Tela azul é um sinal de que algo errado aconteceu, mas melhor você tê-la visto que um cliente seu ligar dizendo que viu uma. Por isso, precisamos fazer a maior força para que elas aconteçam. Já vi programadores fugirem da tela azul tentando se esconder atrás de um manipulador de exceções. Acho que não preciso dizer que isso é tapar o sol com a peneira. Desta forma você apenas deixa de encontrar agora os erros que você ou alguém vai encontrar daqui a algum tempo, até lá, os micros que estão utilizando seus drivers podem ter uma reinicialização repentina aqui ou alí. Mas telas azuis acontecem mesmo, é tudo uma questão de sorte, só que seus clientes podem perceber que usar os seus drivers dá o maior azar. Neste post, vou dar algumas dicas de como podemos ver mais telas azuis em nossos testes de drivers.

Uma passada de F8

Não entenda isso como “Teste você mesmo”, mas entenda por testar todos os códigos de retorno que você puder. Lembre-se que se algo der errado, não será apenas mais um MessageBox que vai aparecer, mas normalmente quando as coisas tomam esse rumo, tudo termina em azul, mais cedo ou mais tarde. Vamos torcer pelo mais cedo. Costumo dizer que todo código merece pelo menos uma passada de F8, que é a minha tecla de Step into. É, eu sei que é diferente do normal, mas quando comecei a utilizar o Visual C/C++ 1.52, o layout do teclado era esse. Mas voltando ao ponto, certa vez eu fiz uma função que deveria simplesmente ler um arquivo, e na minha passada de F8 recebi um código de retorno que não era STATUS_SUCCESS, mas passou na macro NT_SUCCESS(). A pressa me fez ignorar aquilo, afinal não era um erro, era apenas um aviso. Semanas depois, a equipe de teste me disse que por algum motivo o driver estava retornando lixo na leitura do arquivo. Um pouco de debug me voltou a mostrar aquele mesmo código de retorno. Foi só depois de olhar a sua definição no arquivo ntstatus.h que entendi tudo.

//
// MessageId: STATUS_PENDING
//
// MessageText:
//
//  The operation that was requested is pending completion.
//
#define STATUS_PENDING                   ((NTSTATUS)0x00000103L)    // winnt

Enquanto depurando, o sistema tem tempo suficiente para fazer o I/O que ficou para depois, mas quando botamos o bixo pra correr a história é outra.

Um código que passou no seu teste de F8 rodará nos mais diversos ambientes existentes e imagináveis. Logo, essa primeira fase serve apenas para retirar os erros mais grosseiros. Depois disso, é a equipe de testes que deveria surrar a vítima. Existem pessoas que realmente tem o dom de testar software. Trabalhei em uma empresa em que a pessoa que testava os produtos devia ter algum problema pessoal com o software que produzíamos (ou com nós, vai saber). Eu podia testar por dias, mas quando eu entregava o software para teste, não demorava meia hora para ele me ligar de volta dizendo aquela frase que já virou sua marca registrada: “Muito ruim!!!”. Não tinha explicação. Costumávamos dizer que o micro dele tinha sido formatado em cima de um cemitério indígena. Não é à toa que teste de desenvolvedor é tão mal visto.

Acerte no ASSERT

Imagino que a maioria de vocês já tenha ouvido falar na macro ASSERT. Esta macro tem a finalidade de assegurar que determinada condição seja verdadeira. Caso a condição seja falsa, uma tela azul nos salta aos olhos. Nossa, que macro incrível, ajudou muito mesmo. É, eu sei, não é bem assim. Na verdade este é o comportamente que teríamos se o depurador não estivesse atachado ao sistema. Então seria perfeito utilizar esta macro somente em Checked. Devo lembrá-los que Checked significa Debug e Free significa Release? Bom, já foi. Se dermos uma olhada em sua definição, veremos que o óbvio já foi pensado.

#if DBG
 
#define ASSERT( exp ) \
    ((!(exp)) ? \
        (RtlAssert( #exp, __FILE__, __LINE__, NULL ),FALSE) : \
        TRUE)
...
 
#else
 
#define ASSERT( exp )         ((void) 0)
 
...
 
#endif // DBG

Mas o que acontece se estivermos com o depurador atachado? Boa pergunta, essa é realmente uma pergunta interessante, fico feliz que você a tenha feito. Alguém já lhe disse que você leva jeito para programar? Enfim, eu alterei um dos nossos exemplos para forçar esta condição.

extern "C"
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObj,
                     IN PUNICODE_STRING pusRegistryPath)
{
    //-f--> Eu acho que tenho certeza de que esta conta está certa.
    ASSERT(1 + 1 == 3);

Caso a condição falhe e estivermos com um debugger de Kernel atachado ao sistema, este exibirá a condição que falhou na janela de saída e nos solitará que entremos com uma das quatro alternativas como mostra abaixo.


Como vocês podem ver, o ASSERT é prático, fácil e não engorda. Ele só requer um pouquinho assim de cérebro. Digo isso porque todos nós já tivemos dias difíceis, e depois das 23h nenhum programador deveria responder por qualquer código produzido. Certa vez custou-me descobrir por que o código abaixo não funcionava adequadamente. Apesar de tudo funcionar perfeitamente bem quando compilado em Checked, parecia simplesmente que uma certa função não estava sendo chamada em Free. Se derem mais uma olhada na definição desta macro, verão que a condição desaparece quando compilada em Free, e neste caso, a chamada também.

    //-f--> Não basta querer programar, tem que pensar.
    //      << Não copie isso >>
    ASSERT(DoSomeThing() == STATUS_SUCCESS);

Um sistema em Checked

Não seria bom ter um sistema operacional inteiro repleto de ASSERTs e testes para detectar o menor sinal de problemas, e ao encontrá-lo, nos presentearia com uma bela tela azul? Bem, você provavelmente já deve ter ouvido falar das versões Checked Build. Elas são exatamente isso que acabei de escrever. Um sistema operacional inteiro compilado em Checked. Isso significa que todos os ASSERTs que estão nos fontes foram incluidos nos binários finais e estão verificando o sistema para você. Pode parecer besteira ter que instalar seu driver em um desses, mas acredite, vale a pena. Já tive drivers que funcionaram muito bem durante meses, até que meu gerente sugeriu que fossem testados em versões Checked. No topo da minha arrogância, eu pensei comigo mesmo: “Até parece que vai pegar alguma coisa”. É, vivendo e aprendendo. A máquina nem iniciava com meus drivers, era uma tela azul atrás da outra. As versões de Checked Build têm verificações até de deadlock. Você seria capaz de adivinhar o que aconteceria se algum spinlock fosse mantido por mais de um determinado tempo? Aposto que sim.

Já que as versões Ckecked Build são à prova de falhas, posso usá-las como meu sistema padrão? Poder pode, mas tudo é muito mais lento, milhares de verificações estão sendo feitas todo o tempo e o código não tem qualquer otimização aplicada. Em uma instalação do zero, sem instalar qualquer software adicional, você pode encontrar ASSERTs do Internet Explorer ou de outros programas. Isso mesmo, não é só o Kernel que está em Checked, mas todo o sistema. Você teria sempre que deixar um depurador de Kernel atachado ao seu sistema, pois o menor sinal de fumaça seria motivo mais que suficiente para mais uma tela azul.

Se passou pelo Checked Build então o driver está perfeito? Sinto desapontá-lo. Lembre-se que o impacto de performance causado por tantos testes pode ocultar problemas como race conditions. O ideal é testar seus drivers em ambas as versões. Uma configuração permite que tenhamos apenas a imagem do sistema e a HAL em Checked enquanto que o restante do sistema fique em Free. Isso permitiria ter testes adicionais no Kernel enquanto o restante do sistema roda a versão mais leve. Este link explica como fazer isso.

Agora sim meu driver tá lindio?

Na verdade, isso ainda é só o mínimo que você deveria fazer. Uma outra excelente ferramenta geradora de telas azuis é o Driver Verifier. Este aplicativo trabalha em conjunto com o sistema para monitorar ações de uma lista de drivers composta por você. A partir do Windows 2000, o Driver Verifier já vem instalado. Experimente agora mesmo! Não requer prática e tão pouco habilidade. Na janela de “Run…” do Windows, digite “Verifier” e um simples Wizard será iniciado. Como pretendo terminar este post ainda nesta vida, não vou descrever passo a passo como utilizar esta ferramenta, mas existem vários links na página do produto que podem te ajudar nisso.

Vai gostar de tela azul assim no inferno!

Para se ter uma idéia de como a busca por telas azuis é importante para uma companhia de software, a Microsoft promove o IFS Plug Fest com o intuito de testar a interoperabilidade de diversos produtos que implementam File Systems ou filtros para eles. O evento é gratuito, mas cada compania deve arcar com as despesas de viagem e estadia de seus representantes. Nestes encontros, os profissionais do mundo todo reunem-se para fazer os testes entre si além de poder ter o contato e tirar possíveis dúvidas a respeito deste complexo modelo de desenvolvimento. São também promovidos seminários que discutem os problemas comuns enfrentados por esta comunidade. Ainda não estive em um desses, mas um dia quem sabe.

Calma, ainda tem mais

Além das ferramentas aqui citadas, existem outras que eu não poderia deixar de citar. Mas não vou me prolongar em explicar como cada uma delas funciona.

  • Prefast – Ferramenta que faz análize dos fontes a serem compilados pelo DDK em busca de erros comuns de programação para drivers de Kernel.
  • Static Driver Verifier – Esta ferramenta faz uma análise estática do binário já compilado. O teste é bem mais demorado, mas obtém mais resultados que os obtidos no Prefast.
  • Hardware Compatibility Test – Conjunto de softwares que aplicam o testes para a obtenção da certificação de drivers da Microsoft. Descontinuada há pouco tempo.
  • Driver Test Manager – Este é o software sucessor do HCT para testes de certificação de drivers.

Depois de tanta tela azul, só café mesmo pra ajudar.
Até mais!