Construindo o seu instalador de Device Drivers com NSIS no Windows

NSIS

A equipe de desenvolvimento terminou o projeto de um equipamento que deve se comunicar com um computador host, por exemplo, através de uma VCOM. Podemos utilizar várias formas de implementar esta VCOM e, dentre elas, podemos usar um ASIC da FTDI, Exar ou Sylabs que faça este trabalho. Para este exemplo, a forma mais fácil é utilizar o VID (Vendor ID) e PID (Product ID) default do produto. No caso do FT232RL, temos o par 0x0403 | 0x6001 para VID e PID. Se a equipe de desenvolvimento/empresa quer obter o seu próprio VID, sugiro que leia o post Getting a Vendor ID, da USB.org.

 

Neste artigo não iremos abordar o processo de obtenção de um VID para o seu produto e estaremos focando no processo de criação de um device driver a partir de um device driver padrão da FTDI, a sua posterior instalação utilizando o Driver Package Installer e a construção de um instalador utilizando o NSIS.

 

 

Criando o seu driver a partir dos drivers FTDI

 

Em um dos projetos que estou trabalhando estou utilizando uma ponte USB-USART da FTDI, como ilustrado na figura 1.

 

Comunicação Serial over USB utilizando um FT232RL
Figura 1: Comunicação Serial over USB utilizando um FT232RL

 

A primeira etapa que devemos realizar é a de obter os drivers oficiais da FTDI, através do link Virtual COM Port Drivers. Uma observação importante: esses drivers são certificados pela Microsoft e, a partir do momento que o desenvolvedor altera o VID e o PID destes drivers para atender à uma necessidade específica, os drivers não ficam mais assinados e há uma etapa intermediária de certificação dos drivers. Tal processo está fora do escopo deste artigo.

 

Após realizar o download do Driver, vamos dar uma olhada na árvore de diretórios do mesmo:

 

C:\tmp\CDM v2.12.26 WHQL Certified>tree /F
Folder PATH listing for volume OSDisk
Volume serial number is 9A45-D2FF
C:.
│- ftd2xx.h
│- ftdibus.cat
│- ftdibus.inf
│- ftdiport.cat
│- ftdiport.inf

├───amd64
│------ ftbusui.dll
│------ ftcserco.dll
│------ ftd2xx.lib
│------ ftd2xx64.dll
│------ ftdibus.sys
│------ ftlang.dll
│------ ftser2k.sys
│------ ftserui2.dll

├───i386
│------ ftbusui.dll
│------ ftcserco.dll
│------ ftd2xx.dll
│------ ftd2xx.lib
│------ ftdibus.sys
│------ ftlang.dll
│------ ftser2k.sys
│------ ftserui2.dll

├───Static
├─────amd64
│---------- ftd2xx.lib

├─────i386
└---------- ftd2xx.lib

 

Os arquivos que estão no diretório raiz do pacote são os que possuem a descrição dos dispositivos para o Windows. O arquivo de include ftd2xx.h não faz parte do driver, porém faz parte do pacote para termos acesso ao device programaticamente e, para isso, poderemos usar as bibliotecas correspondentes a cada arquitetura (x86 ou amd64).

 

Para modificar o driver e deixá-lo compatível com o seu hardware, todas as entradas relativas aos devices FTDI devem ser removidas e nos arquivos .inf devemos ter somente as informações relativas ao nosso hardware, como mostra a partícula do arquivo ftdibus.ini configurado para o nosso device, que possui VID 0404 e PID 046D

 

 

Após este processo temos o nosso driver, que já pode ser instalado em sua máquina de destino (lembrando que o suporte da FTDI não existe mais, pois, a partir deste momento, temos um driver proprietário em mãos e a responsabilidade por upgrades é de responsabilidade do fabricante.). Neste momento, a instalação pode ser realizada através do Device Manager do Windows.

 

A instalação através do Device Manager funciona muito bem, porém um usuário capaz de realizar este tipo de atividade deve ser um pouco mais especializado. Para que qualquer usuário possa instalar este device driver em sua máquina Windows vamos tentar automatizar o processo de instalação. Para isto, a Microsoft disponibiliza uma ferramenta chamada DPInst (Device Package Installer), que é configurada através de um arquivo xml. Ainda está difícil, não é? Vamos automatizar ainda mais este processo escrevendo um script de instalação utilizando a ferramenta open source NSIS.

 

 

Device Package Installer

 

DPInst é uma ferramenta criada para automatizar o processo de instalação ou atualização de drivers. Ela possui suporte para plataformas x86 e amd64 e pode ser utilizada em diversas versões de Windows.

 

O DPInst faz parte do Windows Driver Kit e pode ser obtido através do seguinte link Windows Driver Kit (WDK). No WDK encontraremos as versões para plataformas de 32 bits e 64 bits, ficando a cargo do usuário utilizar a mais apropriada à sua plataforma. O DPInst está nos diretórios abaixo:

 

A configuração do DPInst, como mencionado anteriormente, é realizada via um arquivo xml. Através deste arquivo podemos, por exemplo, indicar onde estão os arquivos .inf do driver a ser instalado, alterar modos de execução, suprimir ou não janelas de interação com o usuário, suprimir ou não a apresentação das licenças de uso do driver e etc. A seguir mostro um exemplo arquivo de configuração utilizado em um projeto que estou trabalhando: 

 

Este arquivo de configuração deve ter o nome DPInst.xml e deve estar presente no mesmo diretório do executável DPInst a ser utilizado em sua plataforma de destino. Das chaves colocadas no arquivo de configuração de exemplo, a mais importante é a subDirectory, pois esta indica o caminho onde o DPInst deve procurar os arquivos do driver. Para mais informações sobre as chaves existentes para configurar o DPInst, sugiro que verifique a documentação da Microsoft presente neste link.

 

Estando configurado o DPInst, podemos executar o instalador através de uma chamada pela linha de comando:

 

onde:

  • /lm (legacy mode): Aceita drivers não assinados e com arquivos faltantes;
  • /sw (supress windows): suprime a apresentação do Device Installation Wizard, porém o Sistema Operacional ainda pode apresentar algumas janelas de interação com o usuário.

 

Para obter mais opções, use o DPInst com o parâmetro /?, /h ou /help.

 

Após executado o DPInst, o Windows apresentará a seguinte mensagem de segurança:

 

Mensagem de segurança do Windows
Figura 2: Mensagem de segurança do Windows

 

Esta mensagem aparece pois, como dito anteriormente no texto, o driver que estamos instalando não está assinado. Para continuar o processo é só selecionar a opção para instalar o driver e continuar o processo. Em algumas aplicações isto pode ser um problema. A solução seria fazer uma interface que sempre selecionasse a opção de instalar o driver, porém não é uma solução simples. A forma mais fácil e direta é conseguir um código de autenticação da Microsoft para o seu driver. Mais informações podem ser adquiridas neste link.

 

 

Construindo o seu instalador

 

Vamos automatizar o processo de instalação um pouco mais? Para isso, utilizaremos uma ferramenta para construir instaladores para o Windows. Algumas pessoas usam o WiX,  que é uma ferramenta baseada em XML para construir Instaladores Microsoft (MSI); outras preferem o InstallShield; outras utilizam o InnoSetup, que é uma ferramenta de script com uma linguagem parecida com Pascal e é utilizada para fazer instaladores. Dentre as várias existentes, vou utilizar o NSIS (Nullsoft Scriptable Install System), que é uma ferramenta opensource, bem simples de se usar, que é configurável através de scripts em uma linguagem parecida com BASIC e altamente configurável através de plug-ins.

 

Independente da ferramenta que você for usar, o instalador fará basicamente duas tarefas: copiar o pacote do driver para o disco e executar o DPInst. Nesta seção irei mostrar um script em NSIS para realizar a instalação do nosso device driver. O primeiro passo a ser realizado é copiar e renomear a ferramenta DPInst de cada arquitetura, 32 e 64 bits, no diretório de desenvovimento do instalador.

 

Inicialmente, o primeiro problema a ser resolvido é a dependência da arquitetura. Não podemos chamar a versão 32 bits do DPInst em uma arquitetura 64 e vice versa. Para resolver este problema, utilizei o plug-in GetVersion, que através da função GetVersion::WindowsPlatformArchitecture me permite descobrir em qual arquitetura que o instalador está sendo executado. Na listagem 3 apresento o código do script que estou utilizando para construir o meu instalador. 

 

 

Neste script temos basicamente duas seções: a main, que é onde temos a descrição do instalador e a Uninstall, que é onde temos a descrição do desinstalador dos drivers. Vamos explicar os blocos principais presente no script em questão e que poderão ser utilizados na construção de qualquer instalador:

 

  1. Linhas 3-7: Assim como em C, C++, Pascal e outras linguagens, também podemos utilizar defines em scripts NSIS. Para o nosso instalador, utilizei defines para atribuir algumas características únicas do projeto, como fabricante, diretórios e etc;
  2. Linhas 10-13: Informações sobre a aplicação final. Podemos configurar ícones; configurar o nome do instalador (que aparecerá no frame da janela principal do instalador); nome do executável de destino e etc;
  3. Linhas 27-38: Descoberta da Plataforma alvo e configuração do diretório de destino do instalador. Com esta sequência de linhas conseguimos, na linha 27, coletar qual é a plataforma que o instalador está sendo executado. Esta informação fica disponível na pilha de aplicação do NSIS, por isso, para resgatá-la temos que dar um pop da pilha na variável $R0 e, a partir dela, informamos ao instalador qual é o diretório de destino, copiando o valor apropriado à variável de ambiente $INSTDIR;
  4. Linha 44: Criação do Taball de destino;
  5. Linhas 60-72: Execução do DPinst apropriado a cada plataforma. Observe que a chamada de ExecWait bloqueia o processamento até que o dpinst termine a sua tarefa. Para o nosso exemplo, temos um driver composto e, devido a isso, o instalador realizará duas chamadas a DPInst. Na primeira ele realizará a instalação correspondente ao ftdibus.inf e na segunda chamada, ao ftdiport.inf. Durante a instalação, veremos que primeiramente o device é instalado e depois disso, a VCOM correspondente é instalada;
  6. Linhas 67-78: Criação de entradas no Registro do Windows. Neste ponto criamos entradas no Registro do Windows para que a aplicação apareça na lista de programas instalados na máquina. Isso facilita o processo de desinstalação do software;
  7. Linha 81: criação do desinstalador. Neste ponto, o script cria o desinstalador. Note que o diretório de destino do desistalador deve ser o mesmo que é configurado no registro, como descrito no item anterior;
  8. Linhas 86-123. Nesta parte do script temos a seção de criação do desinstalador. Basicamente o desinstalador realiza as seguintes tarefas:
    • Executa o DPInst para desinstalar os dois devices, dependendo da plataforma em que o desinstalador está sendo executado, como feito no item 5;
    • Remove o diretório de instalação;
    • Remove as entradas do instalador no Registro.

 

Tendo explicado os componentes vamos compilar e executar o nosso script. Para compilar o script podemos fazê-lo através do Windows Explorer. Selecione o script e, com o botão direito do mouse, selecione a opção Compile NSIS, como ilustrado na figura 3.

 

Compile NSIS Script
Figura 3: Compile NSIS Script

 

No final do processo de compilação, o NSIS permite realizar o teste do instalador, como ilustrado na figura 4, abaixo.

 

Resultado da compilação do script NSIS
Figura 4: Resultado da compilação do script NSIS

 

Para executar o instalador, é só clicar em "Test Installer", e teremos o resultado mostrado na figura 5.

 

Figura 5: Teste de execução do instalador

 

Após o instalador ser executado, teremos uma nova entrada na lista de programas instalados em nossa máquina, como ilustrado na figura 6.

 

Entrada criada no Program and Features do Windows
Figura 6: Entrada criada no Program and Features do Windows

 

 

Considerações finais

 

Através deste post apresentei uma forma de se construir um instalador básico utilizando o Device Package Installer e um script de instalação NSIS. Se você faz de uma forma diferente, conte-nos sobre a sua experiência e compartilhe-a melhorar os processos e ferramentas.

NEWSLETTER

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Obrigado! Sua inscrição foi um sucesso.

Ops, algo deu errado. Por favor tente novamente.

Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.

Rafael Dias
Sou Bacharel em Física formado pelo Instituto de Física da USP, mestre em Engenharia Elétrica, com ênfase em materiais nanoestruturados pela Escola Politécnica da USP e também Técnico em Automação da Manufatura pela Escola SENAI Anchieta. Trabalho com desenvolvimento de software, firmware e me arrisco com eletrônica analógica para instrumentação e controle. Nos tempos livres gosto de dar uma espairecida e pedalar um pouco.

Deixe um comentário

avatar
 
  Notificações  
Notificar