O NeoMatrix Tech está de casa nova!

Você deverá ser redirecionado em 6 segundos. Se não, visite:
http://www.leonelfraga.com/neomatrixtech
e atualize seus favoritos.

Aviso IMPORTANTÍSSIMO!

Aviso aos navegantes:

O NeoMatrix Tech mudou de casa!!!

A partir de agora, acessem pelo novo endereço:

http://www.leonelfraga.com/neomatrixtech

Ué... mas é só o domínio mudou de lugar?

R: Na verdade, não é bem assim hehe. Este domínio que você acessa agora aponta para um blog hospedado no Blogger, enquanto no novo, aponta para um blog na plataforma Wordpress, hospedagem própria, muito mais rápida e com um layout mais agradável de ler ;)

Não vou fechar este domínio igual ao que eu fiz com o NM Light (que já está 100% na nova plataforma). Talvez beeeeeeem depois eu faça isso.

Todos os posts daqui se encontram lá, e novos posts serão colocados somente no novo endereço.
A única coisa que não consegui importar foram os comentários. Mas em breve vai ter um post contando sobre a epopéia que foi migrar o NeoMatrix Tech!

Somente vou fechar a área de comentários daqui. Caso queiram comentar, favor ver o post correspondente no "Novo NeoMatrix Tech" e comentem por lá. É bem melhor! (pena que os permalinks "amigáveis para SEO" não funcionam lá, dá erro 404 e não consigo fazer a configuração funcionar. E olha que eu já vi vários artigos falando desse assunto :( ).

Quem assina o feed, já está lendo o conteúdo do novo NeoMatrix Tech!

quarta-feira, 30 de dezembro de 2009

Feliz Ano Novo!!!

É, meu amigo! O ano de 2009 está acabando, e tivemos até que muita coisa na tecnologia, né?

Novos processadores como a Família Core i7 e outros da Intel, novos netbooks, Windows novo, muito mimimi do Dr. Stallman, a Oracle comprando a Sun e tornando um mistério o futuro do MySQL, do OpenOffice.org e cia limitada, o Google entrando em novas áreas, e já querendo deslanchar o “Google Phone” para o comecinho do ano que vem…

Desejo a você, leitor, que tenha uma excelente virada de ano!

Segue uma mensagem ao mais estilo “nerd” possível:

public void FelizAnoNovo()
{
	foreach(NeoMatrixReader voce in NeoMatrixReaders)
	{
		this.SendMessage(voce,"Que você tenha um Feliz Ano Novo, com muitas realizações, grana no bolso, saúde e amor!");
	}
}

Um grande abraço!

Leia o restante deste post...

sábado, 12 de dezembro de 2009

Assinatura Digital com C# (.NET)

Em diversas aplicações que tratam informações sensíveis, tais como Nota Fiscal Eletrônica, emissão de certidões, entre outras, temos que trabalhar com assinaturas digitais.

Uma assinatura digital é uma marca que prova a autenticidade do arquivo, ou de uma transação, e a identidade do emissor do mesmo.

Para tal autenticidade não ser contestada, é feito o uso de um elemento chamado Certificado Digital, que é emitido por uma Autoridade Certificadora (como VeriSign, CertiSign, Serasa, Equifax, entre outras empresas) através de um processo burocrático.

E existem também diversos tipos de certificados digitais, tais como um arquivo que é instalado no micro e que contém a chave privada do usuário, certificados que são armazenados em cartões inteligentes, como o e-CPF, appliances que armazenam certificados, entre outros.

Um dos padrões de certificados digitais mais utilizado é o padrão X.509, cuja descrição mais detalhada você pode encontrar aqui.

Um tipo de assinatura digital é o formato PKCS, que “empacota” o arquivo em uma mensagem, que além do próprio arquivo contém as informações dos certificados utilizados para assiná-lo.

Certificados, no plural mesmo? Sim, um arquivo pode conter mais de uma assinatura digital :).

E o .NET Framework possui classes que trabalham com o formato PKCS e certificados X.509, nos namespaces System.Security.Cryptography.Pkcs e System.Security.Cryptography.X509Certificates.

O código abaixo serve para realizar a assinatura digital de um arquivo com múltiplas assinaturas, através de certificados X.509, utilizando somente classes nativas do .NET Framework:

public static byte[] SignFile(X509Certificate2Collection certs, byte[] data)
{
	try
	{
		ContentInfo content = new ContentInfo(data);
		SignedCms signedCms = new SignedCms(content, false);
		if (VerifySign(data))
		{
			signedCms.Decode(data);
		}
		foreach (X509Certificate2 cert in certs)
		{
			CmsSigner signer = new CmsSigner(cert);
			signer.IncludeOption = X509IncludeOption.WholeChain;
			signedCms.ComputeSignature(signer);
		}
		return signedCms.Encode();
	}
	catch(Exception ex)
	{
		throw new Exception("Erro ao assinar arquivo. A mensagem retornada foi: " + ex.Message);
	}
}

Acima somente coloquei o método principal, base de toda a classe de assinatura que será disponibilizada no final do post.

Ele recebe como parâmetros uma coleção de certificados digitais X.509, representados no .NET Framework pela classe X509Certificate2, e um array de byte que corresponde ao arquivo a ser assinado.

A classe ContentInfo contém a mensagem PKCS #7 (o arquivo assinado), representada no nosso programa pela variável content. Inicializamos essa variável com os dados do arquivo a ser assinado.

Mas pera ae… o arquivo ainda não é assinado! Sim, ele ainda não é assinado, e as assinaturas digitais serão gerenciadas pela variável signedCms, da classe SignedCms. É ela que faz o tratamento das assinaturas contidas na mensagem em signedCms, e a classe ContentInfo é exatamente o conteúdo da mensagem (no nosso caso, um arquivo qualquer) a ser assinada ou a ter as assinaturas verificadas.

Após carregar o arquivo nas classes de gerenciamento de assinaturas, verificamos se o mesmo já não é assinado, através do método VerifySign logo abaixo:

public static bool VerifySign(byte[] data)
{
	try
	{
		SignedCms signed = new SignedCms();
		signed.Decode(data);
	}
	catch
	{
		return false; // Arquivo não assinado
	}
	return true;
}

Ele simplesmente recebe um array de bytes com a mensagem, instancia uma classe SignedCms e chama o método Decode() com o array de bytes do parâmetro.

Esse método Decode() faz a decodificação da mensagem PKCS #7 e caso o arquivo contenha alguma assinatura digital, sua propriedade ContentInfo (sim, ela mesma, a que instanciamos no outro método) será populada com o arquivo assinado.

Caso o arquivo não possua assinaturas digitais, é disparada uma exceção e o método retornará false.

Voltando ao método SignFile, caso o arquivo possua assinaturas digitais, ele é recarregado na variável signedCms através do método Decode(), que substitui o conteúdo anterior, aquele que colocamos no construtor.

E tem diferença se o arquivo é assinado ou não?

Sim, uma diferença até que sutil: Lembra que eu falei que um arquivo pode ser assinado com múltiplos certificados?

Caso fiquemos apenas com a carga da variável contentCms pelo construtor, somente as informações do último certificado, caso ele fosse assinado, serão gravadas na assinatura. Utilizando o método Decode(), ele manterá os certificados que foram utilizados anteriormente. E se chamássemos ditetamente o método Decode() e o arquivo não contiver certificados, dará erro.

Agora é que vamos assinar efetivamente o arquivo: Dentro da iteração foreach, que varre cada certificado informado na coleção certs, do tipo X509CertificateCollection, criamos uma instância da classe CmsSigner, e informamos em seu construtor o certificado. Incluímos na assinatura toda a cadeia de certificados, conforme a propriedade IncludeOption do nosso objeto signedCms e a opção X509IncludeOption.WholeChain.

Importante: O certificado a ser carregado no objeto CmsSigner deve ter a chave privada.

Após isso, chamamos o método ComputeSignature do nosso objeto signedCms, que inclui as assinaturas digitais com o certificado carregado na variável signer (do tipo CmsSigner) no arquivo que carregamos em signedCms.

Terminada a inclusão de todas as assinaturas, por fim, chamamos o método Encode() da variável signedCms, que retornará um array de bytes com a mensagem PKCS #7 codificada (leia: o arquivo assinado digitalmente).

Mas… como carrego um certificado gravado para um objeto X509Certificate2?

Os certificados podem ser gravados em arquivos no disco (com extensão .cer, .pfx, etc) ou instalados no repositório de certificados do Windows. Para carregar um certificado do disco, vamos estudar esta sobrecarga do nosso método SignFile:

public static byte[] SignFile(string CertFile, string CertPass, byte[] data)
{
	FileStream fs = new FileStream(CertFile, FileMode.Open);
	byte[] buffer = new byte[fs.Length];
	fs.Read(buffer, 0, buffer.Length);
	X509Certificate2 cert = new X509Certificate2(buffer, CertPass);
	fs.Close();
	fs.Dispose();
	return SignFile(cert, data);
}

Essa sobrecarga recebe como parâmetros o path do arquivo de certificado e a senha utilizada para exportar a chave privada, além do arquivo a ser assinado.

Abrimos o arquivo utilizando um FileStream, e colocamos o conteúdo do stream em um array de bytes. Até aí, nada de exepcional.

Após isso, instanciamos um objeto da classe X509Certificate2, que recebe no construtor que utilizamos os dados brutos do certificado, que está no array de bytes que carregamos através do FileStream e a senha utilizada para exportar a chave privada.

Em seguida, utilizamos uma outra sobrecarga do método SignFile, que apenas coloca um certificado digital em uma coleção X509Certificate2Collection com o método Add() e por fim executa o método principal.

Para pegar os certificados instalados no Repositório de Certificados do Windows (a instalação deles foge do escopo deste post), utilize o seguinte código:

private static X509Certificate2 FindCertOnStore(int idx)
{ 
	X509Store st = new X509Store(StoreLocation.CurrentUser);
	st.Open(OpenFlags.ReadOnly);
	X509Certificate2 ret = st.Certificates[idx];
	st.Close()
	return ret;
}

O processo é bem simples: Crie uma instância da classe X509Store, que representa o repositório de certificados, e indique qual repositório quer abrir. No nosso exemplo, indicamos o repositório “Pessoal” do usuário que está logado na máquina quando a aplicação é executada, e chamamos o método Open() indicando somente leitura.

Daí, os certificados estarão na propriedade Certificates, que por sinal é do tipo X509Certificate2Collection. Você poderá pegar um certificado específico através de um índice ou utilizar a coleção como um todo.

É isso! Assinar arquivos digitalmente no .NET é mais simples do que eu pensava :) Um abraço e Feliz 2010!!!

download1[1] Baixe agora: Métodos para Assinatura Digital utilizando .NET com C# (13 KiB)

Leia o restante deste post...

sábado, 21 de novembro de 2009

Configurações Regionais: Parece algo sem importância, mas…

Um belo dia, você entrega seu programa que estava funcionando perfeitamente na sua máquina de desenvolvimento e em mais algumas selecionadas pela equipe de testes, até que esse belo dia torna-se um tanto trágico: em apenas uma máquina de seu cliente ele não funciona.

Você vai, olha, e derrepente uma mensagem de erro de instrução SQL, alegando que um formato DateTime estava sendo informado de forma incorreta.

Quando chega da reunião com o usuário, você vai correndo ver o código-fonte, e constata que todas as instruções SQL que foram montadas concatenando-se strings estão tratadas, escapando todos os caracteres “cruciais”. Enfim, tudo correto.

Mas você não reparou em uma coisinha no campo que estava com problema: ele estava sendo mostrado de forma diferente na interface de usuário!

As aplicações desktop (e Web também, por que não?) são sensíveis às configurações regionais do sistema operacional.

Que catzo são essas configurações regionais?

Basicamente, são as configurações de como datas, unidades monetárias, fuso horário, números e outras coisas são apresentadas para o usuário.

Por exemplo, o formato de data do Brasil é: dia / mês / ano, sendo que o último pode ter dois ou quatro dígitos.

Vamos ao seguinte cenário:

Um programa qualquer tem um campo que se chama Data de Cadastro, que é gerado automaticamente pela interface de usuário, alimentando um textbox e o texto desse sendo concatenado em uma instrução SQL para ser persistida na base de dados. No banco de dados em questão as datas são inseridas no formato dd/MM/aaaa (normalmente, datas e horas são inseridas no formato ANSI: aaaa-MM-dd HH:mm:ss).

Na sua máquina de desenvolvimento, datas e horas são apresentados no padrão brasileiro e tudo funciona maravilhosamente bem.

Agora, na máquina do usuário, com o sistema operacional em Inglês, as datas são apresentadas no formato estadunidense e chegando o dia 13 o sistema começa a dar pau.

Vejamos, temos um SQL parecido com este na máquina de desenvolvimento quando vamos debugar o programa:

insert into TABELA (meudatetime) values (‘22/12/2009’);

O banco de dados aceita isso numa boa, porém, quando debugamos na máquina do usuário, temos o seguinte:

insert into TABELA (meudatetime) values (‘12/22/2009’);

Como esse SQL foi gerado simplesmente concatenando strings, o banco de dados entende o 22 como mês, já que ele insere datas no nosso formato brasileiro, e nem aqui, nem na China, temos o mês 22. Resultado: PAU.

Uma das formas de se resolver isso é alterando as configurações regionais do sistema operacional. No Windows, vá até o Painel de Controle e procure pela opção Configurações Regionais e de Idioma (no Windows Seven, essa opção chama-se Região e Idioma) e altere o formato de data abreviada.

image

Isso resolve o nosso problema, mas e se o nosso software for para exportação, e todas as máquinas são configuradas para apresentar as configurações regionais do país em questão? Você vai forçar o seu usuário a alterar todas as máquinas, sendo que os outros sistemas estão funcionando perfeitamente?

A forma mais elegante de se resolver este problema é fazer a programação da forma correta, e aqui mostro algumas dicas:

1. Evitar a montagem de instruções SQL concatenando-se strings, e sim utilizando variáveis bind.

Utilizando uma instrução SQL estática e com variáveis bind, ou seja, uma query parametrizada, além de evitarmos ataques de SQL Injection forçamos o banco de dados a sempre trabalhar com o formato correto. Verifique a documentação do seu banco de dados ou da sua linguagem de programação para como utilizar queries parametrizadas / variáveis bind

2. Trabalhar sempre com os tipos de dados nas classes compatíveis com a base de dados.

Eu já vi programas onde o programador declarou TODAS as propriedades da classe como string e fazia a conversão de tipo quando o dado era recuperado do banco de dados (além de montar o SQL concatenado).

Declarando as variáveis com o seu tipo correspondente na base de dados, ou seja, se uma variável é do tipo TIMESTAMP na base, declare-a como DateTime, se for do tipo DOUBLE, declare como Double ou Decimal, e assim por diante. Deixe o tipo string apenas para char e varchar.

Fazendo isso, e utilizando queries parametrizadas, estaremos mantendo a compatibilidade de tipos, e o próprio mecanismo tratará de converter o que foi enviado para o formato correto.

3. Apresentar os dados na UI conforme as configurações regionais do usuário.

4. Se for utilizar SQL concatenado (é, não vai ter jeito…), formate as datas que são enviadas no banco de dados para o formato ANSI, utilizando funções de formatação de data.

Por exemplo, temos componentes do tipo DateTimePicker na tela, e este sempre apresenta as datas de acordo com a configuração regional do usuário. Caso você pegue ela em formato texto para enviar à base de dados, converta-a para o formato ANSI utilizando funções específicas que formatam datas, nada de ficar formatando com substrings. As funções específicas são projetadas para reconhecer dias, meses e anos exatamente de acordo com a configuração regional da máquina onde o programa é executado.

É, meu amigo! Parece que não, mas configurações regionais é um detalhe importante que devemos prestar atenção nas nossas aplicações!

Um abraço :)

Leia o restante deste post...

terça-feira, 27 de outubro de 2009

Experiência com o Windows Seven

Recentemente, no dia 24/10/2009, deixei o Bill Gates um pouco mais rico comprei o novíssimo Windows Seven, que foi lançado oficialmente em todo o mundo no dia 22/10/2009.

241020091763[1]

Sim, vocês leram certo: eu comprei o Windows Seven original, versão Ultimate. Claro que ao falar que compraria (ou até mesmo ler/ouvir que eu comprei), algumas pessoas disseram (vão dizer) “baixa da internet” e coisas do gênero. Resolvi que dessa vez, não vou apelar à pirataria, queria que o sistema operacional fosse legal (em todos os sentidos).

Após um excelente encontro com o pessoal da comunidade “Orientais Adultos +/- 25-35” do Orkut, no Mercado Municipal de São Paulo e antes de ir à uma reunião em minha igreja, dei uma passada na Santa Ifigênia para procurar um lugar onde vendia o Seven. Não achei nenhuma loja, onde eu perguntei, só tinham o Vista e o Seven iria chegar em alguns dias. Incrivelmente, a versão “piratex” é a que se mais achava. Todas as barracas tinha.

Um fato curioso, é que em uma das lojas o capivara vendedor disse que arrumaria sob encomenda, sob a bagatela de R$ 900,00 e queria que desse um sinal. Me desculpe pelo baixo calão a seguir, mas quase que mandei o cara se foder.

Disse para ele:

- Isso está superfaturado! O preço OFICIAL, da Microsoft, é de R$ 669,00 em qualquer lugar!

Ele vem me argumentar que o dono da loja adquiriu 18 licenças, e mais algumas para uns notebooks à uns R$ 700,00, coisa e tal. Como eu sabia muito bem do preço, deixei para lá e fui embora da loja.

Este pequeno fato mostra como é importante estar BEM informado antes de comprar algo, evitar deixar-se levar pela falácia de um vendedor, pois ele está lá para isso mesmo: vender. Além de (dever) estar mal informado, esse cara queria me enrolar

Fui até à Kalunga da Praça Ramos de Azevedo. Lá achei as versões Home Basic e Home Premium, porém, como estava procurando exatamente pela Ultimate, perguntei ao vendedor. Não tinha lá, e após uma consulta ao estoque, verificou-se que haviam duas unidades na loja próxima ao Metrô Carrão. Fui lá e agora sim, me “apossei” do novíssimo Windows Seven Ultimate.

Mas, por que a Ultimate e não a Professional ou a Home Basic / Premium?

Como eu tenho bastante programas legados, além de desenvolver utilizando Delphi 7 e afins, um recurso que utilizarei é o Modo XP (se bem que eu já uso em uma VM…), presente na versão Professional ou acima. Como a diferença de preço da Professional e da Ultimate não é grande (pela ordem de grandeza), resolvi ficar com a versão mais completa possível.

Antes de instalar no meu PC, fiz o backup básico de meus dados no outro PC. Demorou um pouco para copiar pela rede de 100 Mbps, mas foi que foi.

Após o break, vamos entrar na parte técnica da coisa, como foi a instalação, entre outras coisitas mas! Senta que lá vem história!

Primeiramente, vou listar o hardware do meu PC e dizer a você como meu disco rígido está particionado. Vamos lá:

- Placa mãe Gigabyte GA-X48-DQ6
- Processador Core 2 Duo E8400 @ 3,0 GHz (está em stock mesmo)
- 4 GB de RAM DDR 2 800 Kingston (2x 2 GB em Dual Channel)
- HD Western Digital SATA II, de 500 GB
- Placa gráfica Sapphire com chipset gráfico ATI Radeon HD 4870, com 512 MB GDDR5
- Placa de captura Pinnacle PCTV 110i
- Kit de Teclado, Mouse e Webcam Microsoft
- Monitor LCD 22’’ Samsung SyncMaster T220
- Conjunto 5.1 Logitech
- Dongle Bluetooth xing-ling genérico

Dito meu hardware básico, meu disco rígido encontrava-se particionado da segunte forma:

- 80 GB partição primária, instalado o Windows XP (vá com Deus); as outras unidades lógicas mostradas abaixo estão em uma partição extendida.
- 85,5 GB, instalado o Windows Vista (também, vá com Deus) 
- 100,0 GB, dados de usuário (Meus Documentos, pastas de desenvolvimento, downloads)
- 100,0 GB, instalação de aplicativos mais “pesados”
- 100,0 GB, arquivos de multimídia (músicas, vídeos…)

Com o disco particionado, eu poderia instalar outro sistema e não perder os dados. Mas, para prevenir, fiz backup na outra máquina.

241020091764[1] Na caixa do Windows Seven, vieram além dos manuais, dois DVD’s, um com a versão de 32 bits e outro com a 64 bits. Como tenho um processador que suporta as instruções x64 e 4 GB de RAM, a escolha mais adequada é a versão de 64 bits. Foi a que eu instalei.

Resolvi matar a partição que estava instalado o XP. Sem dó nem piedade, cliquei no Formatar quando me foi apresentado as opções de onde instalar o Windows.

Daí por diante, a instalação foi padrão: configurei o idioma, o layout do teclado, algumas outras informações e os arquivos são copiados.

241020091766[1]

Terminada a cópia, mais um boot, e foi onde configurei a data/hora, conta de usuário, inserir o serial…

Durante o boot, notei uma coisa: ele não apresentou o menu de boot com a opção de startar o Vista. Sim, esse Vista é uma versão pirata não oficial mesmo, deveria ter sido crackeada com um lance de ROM BIOS, alguma coisa assim, pois no boot aparecia algo bem rápido na tela. E outra, a ISO que baixei era bem capada, alguns recursos foram retirados e nem instalava o SP2. Bem, agora posso dizer que essa versão não está fazendo falta nenhuma.

Primeiro boot pós-instalação, o desktop me é exibido, e vou logo ver as propriedades de sistema: TODO o meu hardware básico foi reconhecido de primeira: placa mãe, placa de TV, dongle bluetooth, placa de vídeo.

Ativei o sistema, e ele logo foi fazendo um Windows Update, que atualizou mais alguns drivers e instalou o software da webcam, do teclado e do mouse Microsoft.

Baixei do site da Gigabyte o driver da placa de som, na versão Windows Seven de 64 Bits. Fiz isso para poder ter o painel de controle nativo da placa. Quando eu instalei o Windows, a placa de som foi reconhecida.

UAU!!! TODO o meu hardware reconhecido, e NÃO baixei NENHUM outro driver. Até minha placa ATI não precisou baixar driver! E o vídeo funcionou com Aero e tudo!

Os freetards se gabam pela capacidade do Linux reconhecer bem hardware. Claro que não todos os hardwares são reconhecidos pelo Linux (e pelo Windows também), necessitando de algumas gambis… Dessa vez, o Tio Bill acertou a mão hehe.

Fiz o teste do Índice de Experiência do Windows e obtive nota 5,9, que foi definida pelo meu disco rígido. Abaixo você pode ver o resultado completo.

Indice%20de%20Experiencia%20do%20Windows[1]

Agora, hora de instalar o software básico. Vou listar cada programa que instalei, já com as ressalvas:

- Firefox 3.5 –> Fiz backup da versão que eu tinha, 3.0 e restaurei o perfil no 3.5. Algumas extensões deixaram de funcionar, mas não foi por causa do Windows. Funcionou perfeitamente.

- TweetDeck –> Instalou o runtime do Adobe Air. Funcionou perfeitamente.

- Foxit Reader (leitor de PDF)

- Skype

- Windows Live Essentials: Messenger, Writer, Movie Maker e DVD Maker

- Outlook 2003

- Office 2007

- Antivírus Avira (Free Edition)

- Alcohol 120% versão 1.9.8 build 7612: Meu medo ao instalar o Alcohol é na hora de instalar o driver SCSI para a criação das unidades virtuais. Após instalar, ele necessita ser executado como administrador (botão direito, Executar como Administrador) para entrar e pede permissao para execução (olha o UAC entrando em ação!)

- Cyberlink DVD Suite (veio com o gravador de DVD)

- Nero Express 7.9.6.0 (veio com o gravador de DVD)

- Notepad++

- VMWare 6.0 (ele está hospedando VM’s de 32 bits)

- Nokia PC Suite

- Winamp

- K-Lite Mega Codec Pack

- FeedReader (que vem com uma versão do Firebird Embeded)

- PDF Creator

- Picasa 3

- NS Virtual DJ 6.0: Este necessitou ter uma chave do registro alterada. Como ele é um programa de 32 bits, o Windows Seven instalou-o em uma pasta “Arquivos de Programas (x86)”. No registro, a chave HKLM\SOFTWARE\Wow6423Node\VirtualDJ\HomeFolder estava apontando, em formato de nome do DOS, à pasta “Arquivos de Programas” (onde são instalados os programas de 64 bits). Só foi mudar essa chave e meu programa de mixagens, onde produzo os podcasts do NM Light, começou a funcionar de boa! :-D

- Visual Studio 2008 (alguns componentes são x64)

Todos os programas acima são de 32 bits, e até agora não tive nenhum problema.

Jogos: Além de alguns joguinhos antigos, como Duke Nukem, Need for Speed Underground, que rodaram bem, testei o Racedriver GRID, um jogo um pouco mais pesado, para testar a necessidade de baixar o driver da placa de vídeo do site da ATI: não precisei baixar nada, o jogo rodou de boa, em resolução 1650x1080, com 2xAA e detalhes no máximo. Não cheguei a contar a taxa de frames por segundo, mas não tive nenhum engasgo.

desktop-seven[1]

Testei também a multimídia, especialmente a integração com a placa Pinnacle PCTV 110i, que meu deu um trabalhão no Vista: O Windows Media Center funcionou perfeitamente, tanto rádio quanto TV, não presenciei aquele delay que relatei neste post. O chato é que para utilizar a entrada S-Video, ele continua insistindo em uma interface de controle remoto :-(

O Media Player Classic também funcionou de boa, e por ele, posso trocar para a entrada S-Video, ter o áudio através do Line-in da placa de som que tudo fica bem. Sim, não houve aquela tela de erro, como estava no post onde eu relatei a minha epopéia para usar a placa de captura.

Só que o WinampTV não funcionou… aí sim, acho que ele só funciona em SO’s de 32 bits.

Senti um pouco a diferença da barra de tarefas, especialmente na hora de abrir uma janela específica de um grupo e com a localização dos itens no Painel de Controle, pois estava acostumado ao jeitão clássico, mesmo no Vista.

Também demorei um pouquinho para descobrir como se acrescenta novos itens à pasta Programas do novo Menu Iniciar: Em uma pasta qualquer em “Todos os Programas”, cliquei com o botão direito e vi o seguinte caminho: “C:\ProgramData\Microsoft\Windows\Start Menu\Programs\”. Dentro dele, criei uma nova pasta, porém ao arrastar os arquivos com o botão direito para criar o atalho, o Windows mostrou uma mensagem que não pode ser criado.

Pois bem: Criei o atalho na própria pasta do programa e o movi para essa pasta nova no Menu Iniciar. Foi de boa.

E os Meus Documentos? Como meu disco estava particionado, não necessitei de restaurar o backup que tinha feito: os dados estavam todos lá. Aí só foi colocar o meu diretório de uma das partições como um local da biblioteca Documentos. Menu Iniciar, botão direito na pasta Documentos, Propriedades. Depois, clique no botão “Incluir uma Pasta” e aponte o caminho desejado. Veja a tela abaixo:

image

Fiz a mesma coisa para as bibliotecas Músicas e Imagens.

Biblioteca? Sim, agora os “antigos” Meus Documentos, Minhas Músicas e Minhas Imagens podem apontar para mais de um lugar, para o mesmo usuário, como mostrado na imagem acima.

Falhas, telas-azuis e afins? NENHUMA. Sim, o Seven está perfeito na minha máquina. Que me desculpem os freetards, mas dessa vez, o Tio Bill acertou a mão (sim, estou repetindo isso!)! A máquina está rodando muito melhor com o Seven x64. Linux? Eu uso em máquinas virtuais. Embora eu tenha adorado o Seven, não sou nenhum Wintard ou MSTard (talvez um CSharptard… quem sabe) ;-)

Leia o restante deste post...

quarta-feira, 14 de outubro de 2009

Rapidinha: Visualizando propriedades em objetos lazy em um GridView

Se você utiliza como DataSource de um gridview uma coleção do tipo List<> ao invés de um DataTable, pode ter uma hora que teremos que listar propriedades que não são de tipos primitivos (como DateTime, string, int), e sim lazy com outros objetos.

Vamos pegar como exemplo a classe TNivel do artigo anterior. Iremos construir um GridView para listar as propriedades ID, Descrição, Próximo e Anterior, utilizando como DataSource do grid uma coleção do tipo List<TNivel>.

Veja o trecho do XHTML abaixo:

<asp:GridView runat="server" id="gvNiveis">
	<Columns>
		<asp:BoundField HeaderText="Código" DataField="Id" />
		<asp:BoundField HeaderText="Descrição" DataField="Descricao" />
		<asp:BoundField HeaderText="Proximo" DataField="Proximo.Descricao" />
		<asp:BoundField HeaderText="Anterior" DataField="Proximo.Anterior" />
	</Columns>
</asp:GridView>

Compile isso, e você será brindado com uma mensagem de erro.

Como pudemos ver no artigo anterior, as propriedades Proximo e Anterior são objetos do tipo TNivel, e ao listar os campos Descricao das propriedades Proximo e Anterior em um BoundColumn ele não aceita da forma que colocamos.

Como resolvemos isso sem apelar para o evento OnRowDataBound e preencher as células manualmente?

Solução:

Crie, para cada campo, uma TemplateColumn e dentro do ItemTemplate coloque um Label. Na propriedade Text de cada Label, coloque o seguinte comando:

Text='<%# DataBinder.Eval(Container.DataItem, "Nivel.Descricao") %>'

Com a diretiva DataBinder.Eval (parecida com a #Bind, que chegamos a utilizar em artigos anteriores), podemos fazer o Bind de objetos com lazy, que tenham enfim as propriedades com tipos primitivos.

Veja como ficou nosso grid:

<asp:GridView runat="server" id="gvNiveis">
	<Columns>
		<asp:BoundField HeaderText="Código" DataField="Id" />
		<asp:BoundField HeaderText="Descrição" DataField="Descricao" />
		<asp:TemplateColumn HeaderText="Proximo">
			<ItemTemplate>
				<asp:Label runat="server" ID="lbProx" Text='<%# DataBinder.Eval(Container.DataItem, "Proximo.Descricao") %>'></asp:Label>
			</ItemTemplate>
		</asp:TemplateColumn>
		<asp:TemplateColumn HeaderText="Anterior">
			<ItemTemplate>
				<asp:Label runat="server" ID="lbAnt" Text='<%# DataBinder.Eval(Container.DataItem, "Anterior.Descricao") %>'></asp:Label>
			</ItemTemplate>
		</asp:TemplateColumn>
	</Columns>
</asp:GridView>

Enfim, é isso aí!

Um abraço :-)

Leia o restante deste post...

domingo, 4 de outubro de 2009

Momento POG: Armadilha da POO com autorrelacionamentos

Depois de um tempinho sem postagens de programação, finalmente arrumei uma coisnha para poder compartilhar contigo!

Quando você modela uma classe a partir de uma tabela, como você faz com aqueles campos de chave estrangeira, que apontam para uma outra tabela que porventura se torne uma classe também?

Se fomos seguir 100% a POO, devemos fazer um lazy com o objeto em questão, ou seja, criar uma variável privada cujo tipo corresponda a classe daquela tabela, e a sua exposição, se for o caso, em uma propriedade.

Vamos tomar a seguinte tabela como exemplo:

Tabela Niveis

É uma tabela simples, possuindo quatro campos. O detalhe é que os campos ANTES e PROXIMO relacionam-se com o campo ID da mesma tabela, ou seja, um autorrelacionamento (é, com a nova ortografia fica esquisito hehe), ou em jargão menos técnico, uma “tabela que morde o próprio rabo”. E por duas vezes.

Vamos implementar uma classe (em C#, claro, porém, de forma bem simplificada, sem tratamento de erro e tal!) para a tabela em questão:

public class TNivel
{
	#region Variáveis Privadas
	private int _Id;
	private string _Descricao;
	private TNivel _Antes;
	private TNivel _Proximo;
	#endregion
	
	#region Propriedades
	public int Id {get {return _Id;} set {_Id = value;}}
	public string Descricao {get {return _Descricao;} set {_Descricao = value;}}
	public TNivel Antes {get {return _Antes;} set {_Antes = value;}}
	public TNivel Proximo {get {return _Proximo;} set {_Proximo = value;}}
	#endregion
	
	#region Métodos
	public TNiveis(int pNivelId)
	{
		if(pNivelId != null)
		{
			DataReader dr = getReader("select * from NIVEIS where ID = " + pNivelId.ToString());
			if(dr.HasRows)
			{
				_Id = (int)dr["ID"];
				_Descricao = (string)dr["DESCRICAO"];
				_Antes = new TNivel((int)dr["ANTES"]);
				_Proximo = new TNivel((int)dr["PROXIMO"]);
			}
		}
	}
	#endregion
}

Como você pode ver, os campos PROXIMO e ANTES foram implementados como objetos do tipo TNivel, pois eles são como “ponteiros”, apontando para objetos do mesmo tipo.

O construtor desta classe recebe um ID de nível, e atribui os valores às variáveis privadas, e no caso das variáveis _Antes e _Proximo, ele cria uma nova instância da classe TNivel, passando o respectivo ponteiro em seu construtor.

Vamos inserir alguns dados na tabela?

--------------------------------------
ID   DESCRICAO     ANTES    PROXIMO
1    NIVEL 1       NULL     2
2    NIVEL 2       1        3
3    NIVEL 3       2        NULL
--------------------------------------

Montamos os dados nessa tabela de forma que representasse uma lista encadeada, sendo o primeiro nível apontando para o segundo, o segundo apontando para o primeiro e para o terceiro, e o terceiro apontando para o segundo e fechando o encadeamento.

Vamos criar uma instância do nível 1:

TNivel Nivel1 = new TNivel(1);

Quando você executou esse código, notou que o programa ficou parado?

Pois é, o programa fica travado nessa linha! P##ra, o que aconteceu aí, parece que ficou em um looping eterno e não tem nenhum laço!

Vamos fazer agora o bom e velho teste de mesa no método construtor:

  1. Nivel1: O método obtém os dados de um DataReader
  2. Nivel1: Se o DataReader contiver algum registro, continua, senão, cai fora
  3. Nivel1: A propriedade Id é alimentada
  4. Nivel1: A propriedade Descrição é alimentada
  5. Nivel1: Uma nova instância da classe TNivel é inicializada na variável _Antes, e é passado NULL como parâmetro
  6. Nivel1._Antes: O construtor é executado, obtendo os dados de um DataReader
  7. Nivel1._Antes: O Select não retornou registros, então, cai fora
  8. Uma nova instância da classe TNivel é inicializada na variável _Proximo, e é passado “2” como parâmetro.
  9. Nivel1._Proximo: O construtor é executado, obtendo os dados de um DataReader
  10. Nivel1.Proximo: O Select retornou um registro, portanto, vamos alimentar as variáveis
  11. Nivel1.Proximo: A variável Nivel1.Proximo._Id é alimentada
  12. Nivel1.Proximo: A variável Nivel1.Proximo._Descricao é alimentada
  13. Nivel1.Proximo: Uma nova instância da classe TNivel é criada na variável _Antes, e é passado “1” como parâmetro em seu construtor
  14. Nivel1.Proximo.Antes: O construtor é executado, obtendo os dados de um DataReader
  15. Nivel1.Proximo.Antes: O Select retornou um registro (os dados do Nível 1), então, continua.
  16. Nivel1.Proximo.Antes: As variáveis _Id e _Descricao são alimentadas.
  17. Nivel1.Proximo.Antes: Uma nova instância de TNivel é criada na variável _Antes, e é passado NULL como parâmetro
  18. Nivel1.Proximo.Antes.Antes: Obtém os dados de um DataReader, porém o Select não retornou nada.
  19. Nivel1.Proximo.Antes: Uma nova instância de TNivel é criada na variável _Proximo, e é passado “2” como parâmetro em seu construtor
  20. Nivel1.Proximo.Antes.Proximo: Bem, aí vc já sabe, basta retornar ao passo 9 :-)

Notaram que conforme ele carrega os objetos _Antes e _Proximo ele vai criando instâncias de TNivel “aninhadas”? Pois é, neste caso que apresentamos, um nível sempre faz referência com pelo menos um outro nível.

Ficamos em uma sinuca de bico… Manter o paradigma POO neste caso não é viável, pois o programa fica criando estas instâncias aninhadas enquanto haver memória para tal. Como saímos disso, sendo que queremos expor os níveis Próximo e Antes como um objeto TNivel?

Graças à instituição POG temos a solução para este caso!!! Vejam o código modificado de forma que as instâncias de TNivel nas propriedades Proximo e Antes sejam criadas conforme elas são acessadas:

public class TNivel
{
	#region Variáveis Privadas
	private int _Id;
	private string _Descricao;
	private int _Antes;
	private int _Proximo;
	private TNivel _oAntes;
	private TNivel _oProximo;
	#endregion
	
	#region Propriedades
	public int Id {get {return _Id;} set {_Id = value;}}
	public string Descricao {get {return _Descricao;} set {_Descricao = value;}}
	public TNivel Antes {get {return new TNivel(_Antes);} set {_oAntes = value;}}
	public TNivel Proximo {get {return new TNivel(_Proximo);} set {_oProximo = value;}}
	#endregion
	
	#region Métodos
	public TNiveis(int pNivelId)
	{
		if(pNivelId != null)
		{
			DataReader dr = getReader("select * from NIVEIS where ID = " + pNivelId.ToString());
			if(dr.HasRows)
			{
				_Id = (int)dr["ID"];
				_Descricao = (string)dr["DESCRICAO"];
				_Antes = (int)dr["ANTES"];
				_Proximo = (int)dr["PROXIMO"];
			}
		}
	}
	#endregion
}

Note que agora no construtor de TNivel armazenamos os ID dos níveis Proximo e Antes nas variáveis privadas _Antes e _Proximo, e expomos como propriedade um objeto do tipo TNivel, que em seu método get cria uma nova instância de TNivel com o ID armazenado na variável privada correspondente.

Armazenando os ID’s ao invés de criar uma nova instância diretamente, evita com que ele a aplicação crie as instâncias aninhadas do caso anterior, e somente carregue o nível através das propriedades Proximo e Antes conforme elas são chamadas pela aplicação, sempre armazenando o ID ao invés de criar uma nova instância no construtor.

Então, quando você se deparar com uma situação de autorrelacionamento e quiser manter a POO, use este procedimento, que você não terá problemas!

Um abraço!

Leia o restante deste post...

domingo, 27 de setembro de 2009

Winamp TV e Pinnacle PCTV 110i: Agora sim, em paz!

Depois da saga que foi a (tentativa de) utilização de três programas com a minha placa de captura de vídeo Pinnacle PCTV 110i, finalmente achei um programa que funcionasse de forma satisfatória com ela.

Este programa é um bem conhecido tocador de MP3 e outros formatos, sendo bem especializado para áudio (prefiro usar este a outro, incluíndo o Windows Media Player), e embora tenha funções de tocador de vídeo, esta função costuma ser deixada para outros players mais especializados no assunto, como o Media Player Classic.

Este programa é conhecido também pela sua extensibilidade, adquirida através de pequenos outros programinhas chamados plugins.

Sim, conforme vocês puderam ler pelo título, esse programa a qual me refiro é o Winamp!

Só que o Winamp sozinho nada mais é que um tocador de áudio excelente, com boas funções de gerenciamento da biblioteca de mídia, streaming e o que for. Para que o mesmo pudesse funcionar com a minha Pinnacle PCTV 110i, foi necessária a adição do plugin Winamp TV.

Plugin Winamp TV

Instalar o Winamp TV é simples, seguindo o “Windows Way of Install”, ou seja, next, next, finish. Depois disso, é necessário configurar o bicho para que o mesmo possa sintonizar os canais de TV.

Para isso, vá até o menu Options –> Preferences, vá até a guia Plugins –> Input, que o Winamp TV irá aparecer na lista à direita:

Lista de Plugins do Winamp

Dando um duplo clique nele, teremos a tela de configuração do Winamp TV, onde a parte que é mais importante neste momento, na guia Video, é o combo box Capture Device. Selecione neste combo o dispositivo correspondente à sua placa de captura de vídeo.

Configurações do Winamp TV

A segunda parte mais importante na configuração inicial é a aba Scan. Através dela, você poderá fazer o escaneamento automático dos canais de TV e rádio a serem sintonizados. Eles são gravados em pequenos arquivos localizados no diretório indicado em “Channel Filenames”.

Você também poderá adicionar manualmente os canais, clicando em “Add Manually”, onde é apresentada uma outra tela e através dela poderá selecionar a fonte de vídeo, como por exemplo, a S-Video.

Adição Manual de Canais

Feito isso, basta utilizar o Winamp para abrir os arquivos gerados, e está lá, o corpo estendido no chão: sintonia de TV e rádio utilizando o Winamp!

Tela de vídeo do Winamp TV

A dica que eu deixo aqui é: Para ter todos os canais à mão em qualquer momento, vá até a “Media Library”, crie uma playlist com um nome sugestivo, coloque os canais em fila, e através dos comandos com o botão direito do mouse sobre os itens da playlist coloque os arquivos nessa nova playlist na “Media Library”.

Plugin Winamp TV (375 KB)

Um abraço!

Leia o restante deste post...

quinta-feira, 17 de setembro de 2009

Por que Orkutização é quando algo se torna ruim?

orkut

Depois de algum tempinho matusquelando (como diz a Véia, do Energia na Véia) sobre a palavra “orkutização”, que sempre vejo em alguns posts das pessoas que acompanho no Twitter e em outros blogs, tive a idéia de fazer este post.

Se você espera por posts de programação, calma, estou “bolando” mais uma série na qual vamos construir um sisteminha, desde o início, utilizando a Classe de Conexão, um gerenciador de estabelecimentos com atividades “pouco ortodoxas”. Aguardem hehe. Como disse em outros posts, eles estão mais “excassos” pois não ando mais programando muito no serviço. Agora até estão surgindo coisas interessantes nesse aspecto (porém, em VB.NET :-( ).

E também, vou contar em um próximo post sobre como consegui fazer funcionar de forma adequada e muito aceitável a minha placa de captura Pinnacle PCTV 110i, dando final à epopéia do post anterior no qual tentei usar 3 programas, mas atenderam de forma inadequada.

Voltando às vacas frias, quando falamos em redes sociais aqui no Brasil, invariavelmente estaremos falando do Orkut, pelo menos para a grande maioria das pessoas.

Temos diversos sites de redes sociais “à lá Orkut”, como Facebook, Multiply, Ning, Via 6, entre muitos outros. E se fomos expandir o conceito de “social”, podemos colocar nesse meio os blogs, o Twitter, os fóruns “à moda antiga”, entre diversos outros meios de comunicação.

Fazendo uma analogia, os mesmos usuários que consideram o Internet Explorer a Internet em si, o Orkut é sinônimo de rede social.

Nos primeiros anos do Orkut, lá pelos tempos de 2004, era necessário um convite de outro usuário para poder participar. Eu entrei no Orkut nesta época, a convite de uma colega de faculdade, e estou com o mesmo perfil até hoje.

Isto de certa forma ajudava a selecionar os usuários que frequentavam o Orkut. Os temas postados nas mais diversas comunidades rendiam discussões com alta qualidade de argumentação dos participantes.

Claro que também tinham aqueles que fazem arruaça, trollagem, difamações e tudo o mais, mas a frequência era bem menor do que é hoje.

Quem entrava no site era para encontrar os velhos amigos e fazer novos, ou até mesmo algo a mais.

Com uma Inclusão Digital mais forte, o fim da exigência de convite para entrar no Orkut, e a grande divulgação na mídia (leia-se TV) o número de usuários (brasileiros, diga-se de passagem) aumentou drasticamente.

A grande maioria destes novos usuários é formada de adolescentes.

A qualidade das postagens nas comunidades caiu bastante, estes usuários mais novos fazem de suas páginas um verdadeiro chat, não tomam cuidado com o português, postam temas como “fico ou passo” e outras coisas do gênero, seus álbuns de fotos contém poses um tanto… deixa pra lá, sites como o Pérolas do Orkut estão aí para isso…

Isto se deve, em partes, à falta de investimentos em Educação. E não falo somente na educação escolar, e sim, na de casa mesmo.

Esta queda de qualidade afastou muitas pessoas do Orkut.

Quando os mesmos usuários que relatei acima começam a frequentar outros sites, como por exemplo o Twitter, querem que o mesmo seja como o Orkut, pelo menos da forma como eles enxergam. Tanto em funcionalidades, quanto no conteúdo postado, principalmente.

Essa falta de visão da grande massa de usuários, ou seja, achar que tudo o que for rede social é um Orkut-like, fez com que os que não sigam esse “padrão” criassem o termo “orkutização”, para denotar uma queda de qualidade em algum serviço que não era tão divulgado, sem hypes em cima dele.

É uma pena que um site tão interessante, no qual eu conheci e estou conhecendo várias pessoas muito legais, esteja, por causa de alguns usuários, sendo associado como sinônimo de degradação de outros serviços.

Para que este e diversos outros serviços não se degradem, cabe a nós fazermos a nossa parte: continuar postando bom conteúdo, discutir com civilidade, tomar cuidado com o Manoel, não alimentando os trolls, ignorando postagens sem noção… Fazendo um bom uso, ele sempre continuará legal e de muita utilidade :-)

Abraços!

Leia o restante deste post...

sábado, 29 de agosto de 2009

Pinnacle PCTV 110i x Windows Media Center x Media Player Classic x VLC Media Player

pctv110i Não há muuuuuito tempo atrás, eu assistia ao programa “O Aprendiz”, com Roberto Justus, e como todo geek, assistia no computador ao invés de descer para a sala e ver pela TV.

Para tal, possuo como hardware de sintonia de TV a placa de captura Pinnacle PCTV 110i, uma plaquinha antiga até, mas que tem me funcionado bem.

Meu computador é equipado com processador Core 2 Duo E8400 (3 GHz), 4 GB de memória principal, 500 GB de disco rígido, placa de vídeo com processador gráfico Radeon HD 4870, ou seja, este hardware não tem o porquê causar algum gargalo na captura de vídeo.

Quanto ao sistema operacional, utilizo em meu PC o Windows Vista, versão Ultimate, que por sinal, roda muitíssimo bem.

Quando instalei a Pinnacle PCTV 110i no Windows Vista, este IMEDIATAMENTE instalou os drivers adequados. Sim, o próprio Vista possui em seu banco de drivers um driver para a PCTV 110i. Eu estava pensando que seria uma epopéia para achar os drivers compatíveis com o Vista, uma vez que esta placa já esteja descontinuada.

Para não ter que instalar o software original que veio com a placa, pesadão (ele instala até o MSDE – uma espécie de SQL Server 2000 “Express”) e incompatível com o Vista, resolvi utilizar a placa com três tocadores de mídia, a saber: Windows Media Center, Media Player Classic e VLC Media Player.

Após o break, relato a você a experiência que tive em utilizar a Pinnacle PCTV 110i em cada um dos players citados.

1. Windows Media Center

O Windows Media Center é um programa que já vem incluído no Windows Vista, tem uma interface limpa e serve para visualizar diferentes tipos de mídia, tais como arquivos de vídeo, som, e claro, utilizar uma placa de captura para reproduzir e/ou gravar o que é passado através dela.

Windows Media Center x Pinnacle PCTV 110i

Para utilizar a Pinnacle PCTV 110i com o Windows Media Center, é necessário baixar um plugin chamado “Pinnacle PCTV Installer for Windows Media Center 3.0” (não achei o link para download). Instalando este plugin, o WMC poderá ser configurado para fazer a sintonia de TV e rádio através da PCTV 110i.

O assistente de configuração é simples, a placa foi configurada sem problemas para utilizar o sintonizador como fonte de áudio e vídeo.

Através da tela principal, é possível navegar pelas funções oferecidas pelo Windows Media Center, escolher a função desejada (TV, Rádio, etc), e fazer a sintonia de canais.

Interface limpa, bem acabada, fácil de operar, próprio para um Media Center. Mas, como na vida, nem tudo são flores, e tive alguns problemas ao utilizar o WMC:

- Delay entre áudio e vídeo na função de TV: Passado um certo tempo assistindo à TV, passo a notar um certo atraso entre o áudio e o vídeo. Assistir a um programa com esta situação não é nada agradável.

Reinicio o programa, e novamente, depois de um tempo tem esse maldito delay.

- Som picotado na recepção de FM: Na função de rádio, outro problema que incomoda muito. Passado um tempo, o som começa a ficar picotado.

Estes dois problemas são causados, pelo o que eu pude ler em alguns fóruns, pela função de timeshift, ou seja, aquela função que permite a “pausa de um programa ao vivo”, que fica gravando o programa no HD ao mesmo tempo que ele é reproduzido. Infelizmente, não achei maneira de desabilitar o timeshift.

- Para utilizar a entrada S-Video da placa, tenho que adquirir um hardware de controle remoto compatível: Sim, é isso mesmo o que você leu. Executando o assistente de configuração e selecionando como fonte de vídeo a entrada S-Video (através da opção de fontes de vídeo externa, set top box, satélite, etc), chega em um ponto que ele detecta o controle remoto. Como ele não consegue detectar o controle remoto da PCTV 110i, não há como concluir a configuração para assistir TV através de um decodificador de TV por assinatura, por exemplo.

Com uma experiência um tanto frustrada com o WIndows Media Center, passei a utilizar um outro programa, que é o meu padrão para assistir a vídeos.

2. Media Player Classic

Gratuito, versátil, sua interface lembra o antigo Windows Media Player 6.4, aquele que vinha com o Windows 98, porém, o leque de funcionalidades deste player contém coisas que o programa em que sua interface foi baseada nem sonhava em ter.

Media Player Classic x Pinnacle PCTV 110i

A opção para assistir pela placa de captura está na opção File / Open Device, que abre uma caixa para selecionar um dispositivo de entrada, e nos combo boxes eram apresentadas a Pinnacle PCTV 110i para origem de vídeo e áudio.

Dando OK, o player exibia o vídeo capturado pela placa, com uma configuração de entradas que utilizei em um outro programa. Beleza, parece funcionou!

E para mudar de canal e a entrada de vídeo?

Para isso, é necessário ir até o menu Play / Filters, Pinnacle PCTV 110i BDA Xbar e mudar em um combo a entrada de vídeo.

Dando Apply, cadê que ele me mudou a fonte de sinal… Que nada, ela continuou alí, gravada na configuração inicial que me foi apresentada.

Indo para outro programa, configurando a entrada, e voltando ao MPC o negócio funcionou. Agora vamos tentar mudar de canal.

Novamente, entro no menu Play, Filters, e agora seleciono a opção Pinnacle PCTV 110i BDA Analog TV Tuner e é me apresentada uma tela para a seleção de canais da placa.

Mudo de canal e dou OK. O programa me apresenta uma tela de erro e cai fora…

Erro do MPC ao mudar de canal...

Não dá para ficar exaltando a pátria a toda hora, e nessa hora deixei de ser brasileiro: desisti do Media Player Classic para utilizar a PCTV 110i e parti para outro programa.

3. VLC Media Player

Código aberto, multiplataforma (tem versões para Windows, Linux, Mac OS X, entre outros), vem com os codecs embutidos, várias opções de captura e streaming são os atrativos deste player, que em seu site contabiliza mais de 30 milhões de downloads.

VLC Media Player x Pinnacle PCTV 110i

Para poder utilizar a placa de captura, fui ao menu Mídia / Abrir Dispositivo de Captura, onde foi me apresentado uma tela para a seleção do dispositivo.

Deixei como Modo de Captura Direct Show, e selecionei a placa nos combos “Nome do Dispositivo de Vídeo” e “Nome do Dispositivo de Áudio”. Depois, cliquei em Reproduzir e o programa estava reproduzindo o que era capturado na placa.

Neste primeiro momento, sem áudio e o vídeo com cores esquisitas.

Resolvi dar uma olhadinha nas configurações avançadas, para mudar a fonte de vídeo e entrei em uma tela cheia de opções, e as que me interessaram foram as opções “Conector de Entrada de Vídeo” e “Conector de Entrada de Áudio”, além do checkbox “Propriedades do Sintonizador”.

Não mexi nas duas primeiras opções que citei, deixei o “Propriedades do Sintonizador” checado, dou OK e clico em Reproduzir. É aberta a tela de sintonia, onde podemos mudar o canal e o que será capturado: TV ou rádio FM. Coloquei FM, mudei a frequência (no mesmo lugar onde o canal de TV é trocado), dei OK e o rádio funcionou. Sem picote (somente os causados pela antena mesmo), sem delay, tudo funcionando OK.

Opções avançadas do dispositivo de captura no VLC

Resolvo seguir o mesmo caminho, e voltar para a TV. Agora o áudio funcionou. De novo, o mesmo caminho para mudar de canal. Troco de canal, dou OK, e cadê que ele mudou? Continuou no mesmo…

Vou até a tela de propriedades avançadas, e lá tem um spin button onde posso escolher o canal lá. Troquei o canal, dei OK, Reproduzir, e finalmente o canal é trocado!

Para trocar a fonte de vídeo, naquela tela de propriedades avançadas, mexo na opção “Conector de Entrada de Vídeo”, que no lugar de apresentar os nomes das entradas, é apresentado um número sequencial.

E para adivinhar quem é quem?

Tive que testar um por um, até que a imagem do decodificador de TV por assinatura ligado à entrada S-Video aparecesse no monitor. O áudio era capturado pela entrada Line In da placa de som.

Voltando ao sintonizador… novamente sem áudio, e fazendo toda aquela epopéia ele voltou a funcionar, ainda com as cores distorcidas. Para isto, ainda vou ver se é algum filtro do Direct Show que faz isso…

Aqui temos um parêntese: Este é um dos casos em que a usabilidade passa longe do Software Livre. Embora os freetards não deem tanta importância para isso, para muitos usuários a usabilidade é fundamental.

Resumo da ópera:

Windows Media Center:

Prós:

- Interface melhor acabada
- Configuração simples
- Operação simples

Contras:

- Delay entre vídeo e áudio na TV e som picotado no rádio FM, devido ao timeshift que não pode ser desabilitado
- Obrigatoriedade de um hardware de controle remoto compatível para poder utilizar a entrada S-Video

Media Player Classic:

Prós:

- Ampla variedade de formatos
- Interface minimalista, sem frescuras

Contras:

- Configuração um tanto tortuosa
- Travamentos constantes, impossibilitando mudança de canal e dispositivo de sintonia (TV ou Rádio)

VLC:

Prós:

- Código Aberto.
- Operações de mudança de canal, fonte de vídeo e modo do sintonizador funcionaram com sucesso.
- Áudio e vídeo sem delay ou picotes.

Contras:

- Configuração MUITO tortuosa
- Vídeo foi apresentado com diferença de cores, pendendo para o azul.

Enfim, essa foi a minha epopéia para utilizar a placa de captura Pinnacle PCTV 110i com o Windows Media Center, Media Player Classic e VLC. Na minha opinião, se eu conseguir ajustar o VLC para exibir as cores corretas, ele é o software que vou adotar para assistir TV no computador.

Embora muito complicado de configurar, foi o software que funcionou. Pelo menos para ouvir rádio, ele já é o meu padrão. O usuário comum certamente não o adotaria, devido às dificuldades.

Caso você tenha alguma sugestão, comente à vontade!

Um abraço!

Leia o restante deste post...

quinta-feira, 20 de agosto de 2009

Agora vai: Regulamentação da profissão de Analista de Sistemas

analise_sistemas

Depois de muita novela e muitas discussões, ontem, no dia 19/08/2009, a comissão de Constituição, Cidadania e Justiça (CCJ) do Senado aprovou o projeto de lei (PLS 607/07), que trata sobre a regulamentação da profissão de Analistas de Sistemas e Técnico de Informática.

Agora o PL segue para análise da Comissão de Assuntos Sociais (CAS) em decisão terminativa.

No projeto anteriormente aprovado pela Comissão de Ciência, Tecnologia, Inovação, Comunicação e Informática (CCT), somente profissionais com diploma superior em Análise de Sistemas, Processamento de Dados e Ciências da Computação poderão exercer a profissão de Analista de Sistemas.

Agora, se você possui diploma de nível médio, em escola oficial ou reconhecida, dos cursos (ou equivalentes) técnico em informática ou programação de computadores, poderá exercer a profissão de Técnico de Informática.

A proposta torna privativa do analista de sistemas "a responsabilidade técnica por projetos e sistemas para processamento de dados, informática e automação, assim como a emissão de laudos, relatórios ou pareceres técnicos". Ou seja, se der alguma m*, é o seu que estará na reta :P. Aliás, nós Analistas de Sistemas que somos a “ponte” entre o cliente e o programador.

Seriam criados o Conselho Federal e conselhos regionais de informática (assim como temos o CREA para os cursos de engenharia, o CRQ para químicos, entre outros) para sugar o nosso dinheiro cobrar anuidades e fiscalizar o exercício da profissão. Mas, conforme disse Marconi Perillo (PSDB-GO), o relator do PL, a criação por projeto de lei seria inconstitucional, pois isso é atribuição do Poder Executivo.

Mas será que a criação deste conselho vai resolver alguma coisa? O mercado de informática hoje é composto por pessoas das mais diversas áreas.

Quantas vezes você já não viu por aí pessoas com formação de administração, engenharia, medicina entre outras que chegam aos cargos de diretoria de grandes companhias? E inclusive passando pelo cargo de analista de sistemas.

Diploma NUNCA foi sinônimo de conhecimento. Ele significa que você cursou E concluiu um curso em uma instituição, seja ela de ensino médio ou superior. Em uma faculdade, temos noção de como são ALGUMAS coisas. Conhecimento mesmo se adquire com PRÁTICA.

Se isso for com o intuito de separar bons dos maus profissionais, essa teoria é furada. O próprio mercado faz esta separação.

É clássica a cena de empresas que contratam apenas vendo diploma, e muitas vezes um profissional sem o canudo é melhor, em muitos aspectos, do que aquele diplomado que fez seu curso em uma Uni* da vida.

Vendo por outro lado, não dá para confiar um sistema de missão crítica e alta disponibilidade e que mexem com vidas humanas (sistemas de controle de vôo, sistemas médicos, entre outros) nas mãos de qualquer um.

Mas espera ae… As empresas que desenvolvem sistemas desse porte passam por N certificações, homologações e o K7 a quatro. Ou seja, elas por si só já são BEM fiscalizadas. Um erro, e um processo pode ser fatal.

Essa história de regulamentar as profissões relacionadas à informática é longa. Não digo que sou contra a regulamentação, uma vez que já sou formado em Processamento de Dados e já posso exercer a profissão (inclusive, sou funcionário público com o cargo de Analista de Sistemas e me foi exigido o diploma na contratação) tranquilamente.

A parte que não é legal, é pagar as anuidades dos conselhos e passar por poucas-e-boas na hora que for precisar de seus serviços.

O (des)governo já nos estupra com os impostos sobre as mercadorias de informática, e agora quer aprontar mais essa? Eu hein…

Enfim, já que é para regulamentar, que façam a coisa direito e não prejudiquem os bons profissionais que por conta do destino não puderam pegar o seu diploma.

Um abraço!

[via Meio Bit e TI Inside]

Leia o restante deste post...

terça-feira, 18 de agosto de 2009

Este é o iPhone Killer

Um camarada não muito contente com as políticas da Apple em relação ao iPhone, resolveu protestar de uma forma, digamos, inusitada:

Se não fossem estas políticas e outras limitações deste aparelho, eu compraria um sim. Quem sabe em uma próxima versão e quando ficar mais barato por aqui também?

Abraços!

[via MeioBit]

Leia o restante deste post...

sábado, 8 de agosto de 2009

Qual é a sua especialidade: Programar ou analisar?

Como já mencionei em postagens anteriores, estou trabalhando como Analista de Sistemas em São Caetano do Sul, e como o próprio cargo diz, estou mais analisando sistemas do que programando.

Eu sempre gostei de programar.

Em meu serviço anterior, eu ia levantar os requisitos com o usuário (ou até mesmo com meu chefe) e eu mesmo fazia a programação.

Isso mesmo. Tão logo chegava da reunião com o cliente, se não havia nenhuma tarefa pendente, sentava no micro e já começava a programar o sistema, desde a concepção do banco de dados até os testes, passando por todas as etapas do ciclo de vida do programa.

Agora o negócio é diferente: chego da reunião com o usuário, e faço mais a parte documentamental: relatório do levantamento, casos de uso, análise funcional, parte da especificação técnica. Programar fica para os desenvolvedores.

Consegui me adaptar à rotina da análise, e claro, não deixei de programar.

E confesso que o meu perfil, mesmo como analista, é bem mais técnico do que político. Sim, quando eu faço análise, já penso logo na implementação, o sistema fica todo na minha cabeça em forma de classes, métodos, selects, e tudo o mais.

Mas, eu gosto do que eu faço, pois a função de análise é um outro desafio: você tem que “traduzir” as vontades do usuário para um formato que o programador entenda. E não é só isso, tem muito mais :-)

E você, qual é a sua função preferida? Vote na enquete abaixo:


Um abraço!

Leia o restante deste post...

sábado, 1 de agosto de 2009

Uma situação não prevista: #FAIL

É praticamente impossível prever TODAS as situações durante o desenvolvimento de um sistema, seja durante a análise, a programação, o teste e demais etapas do ciclo de vida de um programa.

fail_20at_20failing

Estava fazendo um sistema que conversa com um webservice, que eu mesmo desenvolvi, quando me deparo com um resultado um tanto indesejável.

Veja este pequeno trecho de código:

public void atualizaUltimaConsulta(int parametro)
{
	this.executaSQL("update TABELA set DATA_ULT_CONSULTA = current_date, HORA_ULT_CONSULTA = (current_time - 20) where PARAMETRO = " + parametro.ToString(), false);
}

Esta função faz parte de uma rotina de verificação de histórico: o sistema chama o webservice, executa um método que retorna um histórico de alterações e no final confirma o recebimento disparando a rotina atualizaUltimaConsulta, colocando a data e hora atuais no banco de dados, para que a seleção de novos registros de histórico a serem enviados em uma próxima requisição seja sempre os após a última consulta.

Atualizo o banco de dados com um tempo de 20 segundos antes, para que novos registros inseridos durante o processamento sejam incluídos na próxima “rodada” de verificação de histórico.

Até aí nada demais, algo (quase) perfeitamente normal.

Só que…

Era por volta da meia-noite quando fiz o teste desta rotina, e nas execuções posteriores nenhum registro era retornado, embora satisfazessem as condições para que eles sejam retornados.

Po##a, tem registro na tabela e por que nao retorna? É o c@r@lh0 de asa fumegante e voador!

Resolvi checar a tabela onde é gravada a data/hora da última consulta e eis o que eu vejo: A data ele atualizou certinho, como eu executei a rotina de confirmação de consulta depois da meia-noite, ele gravou o dia atual. Porém, no campo de hora, o maledeto me gravou 23:59, por causa da diferença de 20 segundos que retirei da hora atual, ou seja, estes registros só iriam aparecer no dia seguinte :-(

Resumindo: uma #fail de dimensionamento de tipo de dado, pois se ele fosse timestamp ao invés de campos separados isso não teria acontecido…

Mas, em produção, isso nunca aconteceu hehe.

Um abraço!

Leia o restante deste post...

sábado, 25 de julho de 2009

Um banho de água fria nos Freetards

big_linus_keynote

Há ‘extremistas’ no mundo do software livre, mas esta é uma razão principal por que eu não chamo o que faço de ’software livre’ mais. Eu não quero ser associado às pessoas para quem isso está associado a exclusão e ódio

Esta frase foi dita por Linus Torvalds quando questionado sobre o fato da Microsoft ter disponibilizado um driver para ajudar sistemas Linux virtualizados em host Windows.

Software Livre não significa ser necessáriamente de Código Aberto. São duas coisas distintas, porém os freetards mais radicais não conseguem dissociar uma coisa da outra.

Segundo os freetards, ser livre não significa liberdade de escolha. E esta opinião é endossada pelo próprio Richard Stallman (o “freetard mor”), como pode ser vista aqui.

Linus disse que acredita no desenvolvimento aberto, e isso envolve não deixar NINGUÉM, sejam desenvolvedores autônomos ou EMPRESAS, seja QUEM FOR a participar.

E óbvio que esse “seja quem for” inclui a Microsoft, que sempre é associada a movimentos “anti-linux”, entre outros.

Tá certo que o Mr. Ballmer fala muita besteira, eu detesto as propagandas “Get The Facts” da MS (aliás, não gosto de qualquer propaganda anti-concorrente de qualquer empresa), mas estamos em uma época que a interoperabilidade é um requisito fundamental.

Ah, a MS quer que instalemos o Windows ao invés do Linux nos hosts? Óbvio que sim. E para manter esse mercado disponibilizou o driver, visto que muitos usuários virtualizam Linux e a opção mais em conta para estes seria colocar o host também em Linux.

Qualquer empresa faz a mesma coisa, seja a Oracle, a SAP, a IBM entre outros: contribui onde ela mesma pode ser beneficiada. Algo puramente normal.

Os freetards veem com muito ceticismo essa contribuição da Microsoft, já falam que é cilada, somente pelo fato de ser da Microsoft!

Oras, como eu disse acima, a MS está beneficiando o Linux onde é interessante para ela, assim como TODOS fazem. Nada de mais.

Infelizmente, aqui no Brasil, os que fazem mais barulho são os que associam a expressão “Software Livre” a movimentos políticos, exclusões, apoio a pirataria de software entre outros. Quantas vezes você já ouviu falar “Linux é coisa de comunista” (não lembro se essa é mais uma das besteiras do Ballmer) e outras coisas?

Linus, como o Pai do Linux (na minha opinião o representante maior do movimento SL), não quer sua imagem associada a estes (leia-se freetards).

Está certo ele. Linus é o Cara!!!

[Via: br-Linux]

Abraços!

Leia o restante deste post...

sábado, 18 de julho de 2009

Plugin para realce de código em sites/blogs: Syntax HighLighter

Após um tempo sem postar, devido a alguns trabalhos que estou fazendo, finalmente consegui arrumar algo que é do interesse de quem escreve sobre tecnologia, especificamente programação.

Uma das coisas que deixam um site, blog, ou postagem de fórum que trate de programação mais elegante é o realce da sintaxe de códigos de programação.

Código identado, palavras-chave com cor diferente dos identificadores são itens que deixam um código de programação mais agradável para os nossos olhos.

Aqui no NeoMatrix Tech eu faço uso do plugin “Code Snippet”, do Windows Live Writer para fazer a formatação dos códigos de programação que coloco nas postagens.

Usá-lo é simples: copia-se o código que se deseja formatar para a área de transferência, chama o plugin Code Snippet do WLW, cola-se o conteúdo no editor dele, escolhe a linguagem e clica OK e seu código aparecerá formatado no post.

O senão deste plugin, além do suporte a linguagens majoritariamente da Microsoft (C#, VB, TSQL), além de (X)HTML, CSS, JavaScript) é o código HTML que ele coloca no post.

Se vocês tiverem curiosidade de ver como fica, basta ver qualquer post em que eu coloquei código de programa e dê uma olhadinha no fonte HTML dele: A área onde é gerada o snippet fica gigante!

Outro senão dele é que dependendo da largura do contêiner onde fica o snippet, o realce das linhas alternadas não fica após uma determinada largura (principalmente se faz uso do overflow em div’s).

Lendo este post no blog do Chris Benseler, vi que existe uma alternativa para fazer este realce de código, só que sem aquele HTML monstro que é gerado pelo “Code Snippet” do WLW: Trata-se da bibiliteca JavaScript Syntax HighLighter.

Com ele, basta colocar o seu código de programação em tags <pre></pre> e configurá-lo com um atributo class específico da linguagem que deseja realçar sintaxe.

Veja um exemplo:

public class TMeuArquivo : TEDIFile
{
	public override void DecodeLine(string Line)
	{
		this.Lines.Add(new TRegistroEDI());
		this.Lines[Lines.Count - 1].LinhaRegistro := Line;
		this.Lines[Lines.Count - 1].DecodificarLinha();
	}
}

Se vocês olharem o HTML desta página, verá que o código C# acima está em uma tag pre com o atributo class=”brush: c-sharp”. Esta classe CSS, chamada de “brush”, indica ao plugin qual linguagem será usada para realçar a sintaxe. Uma lista completa das linguagens está no site do desenvolvedor, assim como estão as instruções detalhadas de como utilizar.

Outra vantagem desta biblioteca são os botões que ficam do lado direito do código, que aparecem quando repousamos o mouse: Visualizar o código-fonte no visualizador de código-fonte do navegador, copiar para o clipboard (sem a formatação) e imprimir.

Isto é muito útil quando queremos copiar esse código para outro lugar, por exemplo, a IDE, para que possamos fazer um teste.

Mais uma vantagem é que ele não gera aquele HTML monstro para um simples código a ser formatado, o que representa um download menor para o usuário e um upload menor para o dono do site.

Inclusive, ele respeita as dimensões da coluna da postagem do blog, fazendo a quebra da linha e colocando marcas na nova linha que foi gerada a partir da quebra :-)

Os senões desta biblioteca são, basicamente: temos que fazer o escape de todas os sinais de maior “>” e menor “<”, pois o navegador interpreta o que estiver entre eles como HTML. Mas isso pode ser feito rapidamente com o recurso de conversão de caracteres HTML do plugin TextFX do Notepad++ (download mais do que recomendado!).

Outro senão que achei durante os meus testes é que colocando a tag pre dentro de um div com altura fixa, e overflow = auto, na home do blog o código não apareceu por completo. Mas ao entrar na página do post apareceu normalizado.

Conclusão: O “Code Snippet” do Windows Live Writer já pode ir preparando o chinelão…

Desenvolvedor: Alex Gorbatchev
Site da biblioteca: SyntaxHighlighter

[]’s a todos!

[Via: Chris B – Idéias e Pensamentos]

Leia o restante deste post...

domingo, 5 de julho de 2009

Criando Propriedades no Visual Studio 2005

Quando desenvolvemos uma classe, seja seguindo as convenções adotadas pela Classe de Conexão ou não, geralmente criamos variáveis privadas e variáveis públicas que encapsulam estas variáveis.

Imagine digitar get’s e set’s de mais de 30 campos de uma classe… Só com isso perdemos muito tempo.

Eis que procurando por um plugin para Visual Studio 2005 que me permitisse criar propriedades (com get e set) a partir de variáveis privadas obtive o seguinte resultado:

Property Manager AddIn for Visual Studio 2005 , no blog C# Shiznit.

Com este add-in instalado, basta selecionar as variáveis privadas desejadas, clicar com o botão direito do mouse, selecionar a opção “Create Property” que os get’s e set’s estarão prontinhos na área de transferência.

O Visual Studio também possui a opção “Encapsulate Field”, que faz a mesma coisa, mas somente o faz com uma variável por vez.

Vale a pena a visita e o download ;-)

Leia o restante deste post...

sábado, 27 de junho de 2009

Fazendo Arquivos EDI com C# aplicando POO Parte 4 - Final

Finalmente chegamos na parte conclusiva desta série de artigos. Iremos construir uma aplicação que irá gravar/ler um arquivo EDI. Estarei no artigo comentando o arquivo exemplo, portanto, façam o download do arquivo em anexo à este post!

Para o exemplo, na época do artigo original utilizei a IDE Sharp Develop versão 2.2, com o .NET Framework versão 2.0.

Mas antes, uma ressalva sobre o código do artigo anterior:

Caso vocês tenham notado, após o comando LoadFromFile o arquivo não é carregado, a quantidade de linhas da propriedade Count de Lines é 0. Mas por que isso?

Se olharmos na classe base, TEDIFile, o método LoadFromFile (ou LoadFromStream) faz chamada ao método virtual DecodeLine, que recebe como parâmetro uma string, que
é a linha a ser decodificada, vinda do arquivo.

Como na implementação do método não temos nenhum código, a aplicação somente irá passar por ele e não fará nenhuma ação; o método LoadFromFile simplesmente fará um looping
no arquivo texto carregado.

Como solucionar?

A classe TEDIFile apresenta comportamento genérico. Um arquivo poderá ter diferentes tipos de registro, que podem ter layouts diferentes entre si, por exemplo, um header, linhas detalhe e um registro trailler. Isto é específico de cada arquivo. Para ser mais específico, a classe deveria ser mais especializada, não é? Mas embora seja especializada, tenha o comportamento da TEDIFile.

Para tal especialização, iremos criar uma classe derivada de TEDIFile e iremos sobreescrever o método DecodeLine para adicionar os objetos à representação do nosso arquivo EDI em memória:

   1: public class TMeuArquivo : TEDIFile
   2: {
   3:     public override void DecodeLine(string Line)
   4:     {
   5:         this.Lines.Add(new TRegistroEDI());
   6:         this.Lines[Lines.Count - 1].LinhaRegistro := Line;
   7:         this.Lines[Lines.Count - 1].DecodificarLinha();
   8:     }
   9: }

Pronto, problema resolvido!

Agora, caso você tenha mais de um tipo de layout no arquivo, primeiro verifique em cada linha se há um campo para identificar o tipo de registro.

Com isso, você poderá fazer o controle através do parâmetro Line da instrução DecodeLine.

Supomos que temos três tipos de layouts (TMeuHeader,TMeuDetalhe e TMeuTrailler) e que temos um campo na posição 1 de cada linha que indica o tipo de registro, sendo H,D e T para Header, Detalhe e Trailler respectivamente. O código ficará assim:

   1: public override void DecodeLine(string Line)
   2: {
   3:     if(Lines.Substring(0,1).Equals("H"))
   4:     {
   5:         this.Lines.Add(new TMeuHeader());
   6:     }
   7:     if(Lines.Substring(0,1).Equals("D"))
   8:     {
   9:         this.Lines.Add(new TMeuDetalhe());
  10:     }
  11:     if(Lines.Substring(0,1).Equals("T"))
  12:     {
  13:         this.Lines.Add(new TMeuTrailler());
  14:     }
  15:     this.Lines[Lines.Count - 1].LinhaRegistro := Line;
  16:     this.Lines[Lines.Count - 1].DecodificarLinha();
  17: }

Como os três tipos de registros possuem comportamento semelhante, já que são herdados de TRegistroEDI e a propriedade Lines é uma coleção deste tipo de registro, a chamada ao método DecodificarLinha() é a chamada da classe correspondente.

Programa Exemplo do Artigo

Sim, notei que a explicação acima está um pouco adiantada, mas ela se fez necessária. Se não entendeu bulhufas, agora vamos à explicação do programa passo a passo!

No projeto ArquivosEDI, há um arquivo de classes chamado TArtigoEDI.cs que contém as classes especializadas. É ele que iremos explicar. No projeto também há um formulário básico, criado apenas para demonstração sem se preocupar com validações e coisas do gênero, o "framework" para criação de arquivos EDI composto pelos arquivos EDIBasicTypes.cs e EDIFile.cs.

No formulário, há um DataTable que utilizo para guardar os registros que serão necessários para guardar e receber o arquivo. O código dos botões de navegação são básicos: é incrementada uma variável de controle que indica a linha da tabela; na seleção do registro, atribuo cada campo da tabela em uma caixa de texto. O botão Inserir é análogo. O botão Novo simplesmente deixa as caixas de texto em branco.

O botão Codificar Linha pega os registros das caixas de texto e faz a formatação conforme o layout indicado no primeiro artigo e coloca o resultado na caixa de texto indicada pelo label LinhaFormatada. O botão Decodificar Linha, pega o conteúdo da caixa LinhaFormatada e joga em cada campo.

O botão Carregar Arquivo carrega o arquivo indicado na caixa de texto Nome do Arquivo e carrega o nosso DataTable; o botão Salvar Arquivo varre o DataTable e salva-o em um arquivo Texto com o nosso layout.

Observem o código:

   1: public class TRegistroArtigoEDICS : TRegistroEDI
   2: {
   3:     #region Variáveis Privadas
   4:      private string _Nome = "";
   5:      private DateTime _DataNascimento = DateTime.MinValue;
   6:      private string _TipoPessoa = "";
   7:      private long _Documento = 0;
   8:      private Double _SaldoAtual = 0;
   9:     #endregion
  10:    
  11:     #region Propriedades (Públicas)
  12:      public string Nome
  13:      {
  14:          get{return _Nome;}
  15:          set{_Nome = value;}
  16:      }
  17:      public DateTime DataNascimento
  18:      {
  19:          get{return _DataNascimento;}
  20:          set{_DataNascimento = value;}
  21:      }
  22:      public string TipoPessoa
  23:      {
  24:          get{return _TipoPessoa;}
  25:          set{_TipoPessoa = value;}
  26:      }
  27:      public long Documento
  28:      {
  29:          get{return _Documento;}
  30:          set{_Documento = value;}
  31:      }
  32:      public Double SaldoAtual
  33:      {
  34:          get{return _SaldoAtual;}
  35:          set{_SaldoAtual = value;}
  36:      }
  37:     #endregion
  38:    
  39:    
  40:     public TRegistroArtigoEDICS()
  41:     {
  42:         this._CamposEDI.Add(new TCampoRegistroEDI(TTiposDadoEDI.ediAlpha,40,0,"",null,null,1));
  43:         this._CamposEDI.Add(new TCampoRegistroEDI(TTiposDadoEDI.ediDataDDMMAAAA,8,0,DateTime.MinValue,null,null,41));
  44:         this._CamposEDI.Add(new TCampoRegistroEDI(TTiposDadoEDI.ediAlpha,1,0,"",null,null,49));
  45:         this._CamposEDI.Add(new TCampoRegistroEDI(TTiposDadoEDI.ediInteiro,20,0,0,null,null,50));
  46:         this._CamposEDI.Add(new TCampoRegistroEDI(TTiposDadoEDI.ediNumericoSemSeparador,12,2,0,null,null,70));
  47:     }
  48:    
  49:     public override void CodificarLinha()
  50:     {
  51:         this._CamposEDI[0].ValorNatural = this._Nome;
  52:         this._CamposEDI[1].ValorNatural = this._DataNascimento;
  53:         this._CamposEDI[2].ValorNatural = this._TipoPessoa;
  54:         this._CamposEDI[3].ValorNatural = this._Documento;
  55:         this._CamposEDI[4].ValorNatural = this._SaldoAtual;
  56:         base.CodificarLinha();
  57:     }
  58:    
  59:     public override void DecodificarLinha()
  60:     {
  61:         base.DecodificarLinha();
  62:         this._Nome = (string)this._CamposEDI[0].ValorNatural;
  63:         this._DataNascimento = (DateTime)this._CamposEDI[1].ValorNatural;
  64:         this._TipoPessoa = (string)this._CamposEDI[2].ValorNatural;
  65:         this._Documento = (long)this._CamposEDI[3].ValorNatural;
  66:         this._SaldoAtual = (double)this._CamposEDI[4].ValorNatural;
  67:     }
  68: }
  69:  
  70:  
  71: public class TArquivoArtigoEDI : TEDIFile
  72: {
  73:     protected override void DecodeLine(string Line)
  74:     {
  75:         base.DecodeLine(Line);
  76:         Lines.Add(new TRegistroArtigoEDICS());
  77:         Lines[Lines.Count - 1].LinhaRegistro = Line;
  78:         Lines[Lines.Count - 1].DecodificarLinha();
  79:     }
  80: }

Acima temos a definição das duas classes "principais" deste artigo.

Implementamos o nosso layout através de uma classe derivada de TRegistroEDI chamada TRegistroArtigoEDICS, onde criamos e inicializamos as variáveis privadas (e as propriedades que as expõe) correspondentes aos campos do registro. Portanto, este objeto representa cada linha do arquivo EDI.

O layout em si é definido no construtor de TRegistroArtigoEDICS, onde adicionamos em _CamposEDI os objetos do tipo TCampoRegistroEDI com a definição dos itens básicos do layout, lembra (tipo de dado, tamanho, posição inicial...)? Note que eu declarei os campos conforme eles aparecem no layout. Se quiser, pode acrescentar um comentário em cada linha de declaração de campo, para lembrar o nome dele. É importante também lembrar-se da ordem, já que iremos acessá-los através do índice (começando em zero).

Para gerar a linha formatada deste registro, sobreescrevemos o método CodificarLinha. Nele, eu atribuo cada propriedade em cada campo adicionado, campos estes que estarão dentro da coleção _CamposEDI e é acessado através do índice deste. Atribuimos a propriedade da classe na propriedade ValorNatural de cada campo. Após feita as atribuições, chamamos o método CodificarLinha() da classe pai que é o responsável pela formatação propriamente dita. O resultado formatado será acessado através da propriedade LinhaRegistro da nossa classe TRegistroArtigoEDICS.

Analogamente, temos a sobreescrita do método DecodificarLinha(): Primeiro, no nosso programa, setamos a propriedade LinhaRegistro com uma linha formatada (isto é feito na classe do arquivo, que veremos adiante), após isso, já dentro do método DecodificarLinha() é chamado o método da classe pai, que será o responsável por separar cada substring de LinhaRegistro e separar em campos com o tipo de dado definido no layout em _CamposEDI.

Feita a conversão, atribuimos nas propriedades de TRegistroArtigoEDICS os valores dos campos em _CamposEDI correspondentes, acessados através da propriedade ValorNatural do mesmo.

Como ValorNatural é do tipo object, e a conversão para outros tipos de dado não é explícita como o inverso ( = atribuir qualquer tipo de dado em uma variável object ) é necessário fazer um cast para o tipo adequado na propriedade. Um cuidado a se tomar é com valores nulos ou que não podem ser convertidos facilmente, como DateTime (já tive muuuuuito trabalho com esse tipo de dado...).

Definida a classe de cada registro, vamos definir uma classe que será responsável pelo salvamento/carregamento do arquivo texto em si. Esta classe é derivada de TEDIFile, que contém os métodos adequados) e chamaremos-a de TArquivoArtigoEDI.

De modo geral, somente o método DecodeLine precisa ser sobreescrito. Os métodos LoadFromFile, LoadFromStream e SaveToFile trabalham com a linha já codificada de cada registro.

O método DecodeLine, chamado nas funções de carga (LoadFromFile e LoadFromStream) é o responsável por adicionar efetivamente um registro vindo do arquivo texto na coleção Lines.

Neste método, adicionamos na coleção Lines um objeto do tipo do layout. No nosso exemplo, como temos somente um tipo de registro, adicionaremos um objeto do tipo TRegistroArtigoEDICS. Caso o seu arquivo tenha vários tipos de registros (e várias tipos de layout, claro) devemos fazer uma verificação que pergunta "Qual é o tipo de registro correspondente a esta linha?" ANTES de adicionar o objeto.

Como o método DecodeLine recebe a linha a ser decodificada como parâmetro, essa verificação geralmente é feita através de uma substring. Na nota no início do artigo tem um ponto explicando isso!

Feita a adição do objeto na coleção Lines, atribuimos o parâmetro Line (a linha a ser decodificada) neste objeto que acabamos de adicionar. Em seguida, chamamos o método DecodificarLinha() e a adição da linha está completa.

No nosso formulário... Agora, veja o código dos botões de salvamento e carga do arquivo do form da nossa aplicação:

   1:  
   2: void BtnGravaArqClick(object sender, EventArgs e)
   3: {
   4:     TArquivoArtigoEDI arq = new TArquivoArtigoEDI();
   5:     foreach(DataRow r in tab.Rows)
   6:     {
   7:         TRegistroArtigoEDICS reg = new TRegistroArtigoEDICS();
   8:         reg.Nome = r[0].ToString();
   9:         reg.DataNascimento = (DateTime)r[2];
  10:         reg.TipoPessoa = r[1].ToString();
  11:         reg.Documento = (long)r[3];
  12:         reg.SaldoAtual = (double)r[4];
  13:         arq.Lines.Add(reg);
  14:     }
  15:     arq.SaveToFile(@tbxArq.Text);
  16: }
  17:  
  18: void BtnCarregarArqClick(object sender, EventArgs e)
  19: {
  20:     TArquivoArtigoEDI arq = new TArquivoArtigoEDI();
  21:     tab.Rows.Clear();
  22:     arq.LoadFromFile(@tbxArq.Text);
  23:     foreach(TRegistroArtigoEDICS reg in arq.Lines)
  24:     {
  25:         DataRow linha = tab.NewRow();
  26:         linha["NOME"] = reg.Nome;
  27:         linha["TP_PESSOA"] = reg.TipoPessoa;
  28:         linha["DT_NASC"] = reg.DataNascimento;
  29:         linha["DOCTO"] = reg.Documento;
  30:         linha["SALDO"] = reg.SaldoAtual;
  31:         tab.Rows.Add(linha);
  32:     }
  33:     BtPrimeiroClick(null,null);
  34: }

No programa, guardamos em um DataTable os registros adicionados através do formulário.

Para exportar este DataTable para texto, criamos uma instância de TArquivoArtigoEDI (variável arq), varremos as linhas do DataTable. Dentro do foreach criamos uma instância de TRegistroArquivoEDICS (variável reg) que será cada linha do arquivo. Atribuimos cada coluna da linha do DataTable nas propriedades correspondentes de reg e no final adicionamos-a em arq. Terminando a iteração, chamamos o método SaveToFile() de arq para gravar o arquivo no disco.

Na importação do arquivo, o processo é o seguinte: Criamos a instância da classe do arquivo (variável arq) e limpamos o DataTable. Fazemos uma iteração percorrendo cada item da propriedade Lines da variável arq. Dentro da iteração, é criado um DataRow no esquema de tab (o nosso DataTable) e adicionamos em cada coluna desta linha as propriedades correspondentes de reg. Por fim, adicionamos o DataRow ao nosso DataTable. Concluído o processo de carga, apenas chamamos o método para ir para o primeiro registro.

Ufa! Finalmente acabou. Com isto é possível implementar rapidamente um gerador/leitor de arquivos EDI, muito utilizados no nosso dia-a-dia (vide Associação Comercial e outras entidades de proteção ao crédito, bancos, seguradoras, etc).

Exemplo de projeto com Arquivo EDI (61,8 KiB)

Um abraço a todos! :-)

Leia o restante deste post...

Sobre o NeoMatrix Tech

Meu blog para assuntos profissionais, ligado com tecnologia.
Dicas de programação (grande parte de C# e ASP.NET, mas não limitado a essa plataforma :-) ), dicas de utilitários, análises de equipamentos e serviços, resenhas sobre sites que eu visito, relacionados com tecnologia, opinião sobre mercado de trabalho, metodologias de desenvolvimento, comportamento no mundo tecnológico...

NeoMatrix Light

  © Blogger templates ProBlogger Template by Ourblogtemplates.com 2008 - Editado e configurado por Leonel F.

Voltar ao TOPO