.NET: Como criar uma tela de login numa aplicação Windows Forms?
Hoje um colega de trabalho me questionou sobre uma dúvida básica e provavelmente muito comum entre todos os iniciantes: como criar uma tela de login numa aplicação Windows Forms e fazer com que ela seja a primeira tela a ser executada?
A solução é simples. Basta criar um formulário chamado Login, por exemplo, e dentro do método main (que fica no arquivo Program.cs) utilizar o seguinte código:

Código para abrir o formulário de login
Ele cria a tela de login, apresenta ela ao usuário e conforme o resultado continua ou não a execução da aplicação. Esta tela pode ser parecida com a da figura abaixo:

Formulário para fazer o login
Quando o usuário clicar no botão Login o código executado é o seguinte:

Pronto. Simples, fácil e rápido :).
Até +.
Utilizando XPath no Delphi
Se você ainda utiliza o bom e velho Delphi 6 deve saber o quanto é complicado encontrar e utilizar certas APIs para trabalhar com tecnologias relativamente novas.
Não que XPath ou XML sejam algo novo, mas que não é comum um desenvolvedor Delphi 4, 5 ou 6 utilizar estas tecnologias, isto é fato!
Nos últimos dias estou trabalhando em um novo projeto que armazenará todas as configurações utilizando um arquivo XML. Se fosse em .NET poderia escolher até mesmo o db4o pra isso, mas em Delphi as únicas possibilidades são o bom e velho arquivo INI ou, com a maior paciência do mundo, arquivos XML.
Como bom metido que sou, resolvi utilizar os XMLs. Já tinha uma noção básica de como utilizá-los, mas desta vez eu precisei de um recurso extra: o XPath.
Mas que diabos é esse XPath?
É uma linguagem de acesso às informações contidas em um arquivo XML. Tome como base o seguinte arquivo:

Para acessar o valor do nodo login que está dentro do bancodados, basta utilizar a seguinte expressão XPath:
/configs/bancodados/login
Entendeu? É quase igual ao acesso de um arquivo dentro de pastas e subpastas.
XPath no Delphi
A unit que dá suporte às expressões XPath no Delphi é a XMLDom. Nela você encontrará a classe IDOMNodeSelect, que provê o método selectNode.
Para ler o valor de um nodo utilizando este método use o código apresentado abaixo:

FXMLDoc é um objeto do tipo IXMLDocument que está declarado como private e foi instanciado previamente. FNodoRaiz é o nodo root do arquivo XML. No exemplo acima, este nodo é o configs.
Veja que o resultado do selectNode não possui diretamente o valor do nodo. Ao invés disso, usa-se a propriedade childNodes.item[0].nodeValue. Levei algumas horas até descobrir isso.
Para a alteração do valor de um nodo o método é semelhante ao apresentado acima. Veja:

A única diferença é que se encontrou o nodo então altera o valor ao invés de retorná-lo.
Existe um detalhe muito importante que os métodos acima não tratam. Caso um dos nodos referenciados na expressão XPath não exista, então o selectNode retornará nil. No caso do método RetornaValor isto não é um problema tão sério, pois simplesmente retornará vazio. No entanto no AlteraValor o comportamento mais óbio possível seria a auto-criação dos nodos não existentes. Para tal, você pode utilizar a rotina abaixo:

Este método cria todos os nodos não encontrados numa expressão XPath. Pode ser chamado dentro da AlteraValor da seguinte forma:

Todas estas rotinas estão disponíveis dentro de uma classe base de acesso a arquivos XML. O download dela pode ser feito aqui.
É isso ae. Até +.
Alterando o formato dos links permanentes no Wordpress sem ser esquecido pelos buscadores
Alterar o formato dos links permanentes (permalinks) implica em um grande problema: tudo o que foi indexado até hoje pelos buscadores será perdido.
Em uma das quebradas da web, encontrei um plugin para o Wordpress que resolve este problema. Ao receber uma solicitação utilizando o formato antigo, ele avisa ao solicitante que o endereço mudou e redireciona ele para o local correto.
O download dele pode ser feito aqui: Permalinks Migration Plugin.
E se a estrutura do blog mudou também?
Veja o meu blog, por exemplo. Antigamente ele era hospedado na IPHotel dentro da pasta /blog. Hoje, na DreamHost, ele está na raiz do servidor. Agora vá até o Google e procure por tudo o que ele já indexou do meu blog. Eis o resultado:

Tá vendo o /blog nas indexações? Pois é, sem uma intervenção técnica ao clicar num dos links acima você receberá um Page not found como resposta. A solução mais rápida e prática que achei para esta situação foi tratar o acesso feito à pasta blog. Em outras palavras, criei uma pasta blog, tal como existia antigamente, e adicionei um arquivo index.php com o seguinte código:
Esse código pega tudo o que vem depois do /blog e encaminha para a raiz do servidor, que é o local onde está instalado o Wordpress. Uma requisição do tipo www…/blog/index.php/algum_post, por exemplo, será enviada para http://www…/algum_post.
No meu caso tive que tratar também o index.php, pois o servidor antigo não tinha suporte ao recurso URL Rewriting, por isso os permalinks foram gerados com o nome do arquivo junto. Acredito que a maioria dos blogs não vai precisar deste tratamento, portanto o index.php pode ser removido da variável $str.
Até +.
O que é OPML?
OPML (Outline Processor Markup Language) é uma forma de compartilhar uma lista de feeds.
Entendeu? Não? Então veja outras definições um pouco mais completas:
OPML (Outline Processor Markup Language) é um arquivo padrão escrito em XML para compartilhar listas de feeds e é a melhor forma de fazer backup da sua lista caso seu agregador local (ou até mesmo seu agregador online) bata as botas de repente. Possui uma markup comum de XML só que com algumas tags e atributos padronizados. Você pode usar este arquivo de OPML tanto para fazer um backup do seus feeds quanto compartilhar suas referências na web. (Henrique, Revolução Etc)
OPML é um formato XML de listagem nativo de aplicações outliner, porém, é utilizado para listar feeds RSS que podem ser abertos e lidos por agregadores de feed. (Wikipedia)
Por que usar?
Isso vai de cada um, mas os meus motivos são os seguintes:
- Substituir a lista de sites/blogs favoritos (blogroll), afinal ela ocuparia grande parte do menu do blog;
- Ter um backup de todos os feeds que acesso;
- Facilitar o compartilhamento dos meus feeds;
- Facilitar a migração do leitor de feeds, pois a grande maioria suporta este padrão.
Como usar?
Tendo um arquivo OPML em mãos o único passo que falta é imporá-lo no leitor de feeds. Eu uso o Google Reader, que dá suporte total à importação e exportação de arquivos OPML.
Para exportar basta clicar em Manage subscriptions (logo abaixo da lista de feeds), escolher a opção Import/Export e depois Export your subscriptions as an OPML file.
O processo de importação é semelhante. Também em Manage subscriptions, Import/Export, basta escolher o arquivo OPML e clicar em Upload.
Outros leitores de feeds (Bloglines, Newsgator, etc) também suportam este formato.
Como compartilhar?
Se você faz parte da web colaborativa 2.0 certamente vai querer compartilhar seus feeds. Para isto, basta gerar o arquivo OPML e utilizar a tag link dentro do head da sua página, assim:
<link rel=”outline” type=”text/xml+opml” title=”Marcos Dell Antonio”
href=”http://www.marcosdellantonio.net/marcosdellantonio.opml” />
Claro, se quiser, também pode colocar o arquivo para download no blog, da mesma forma que eu fiz.
Dica: se você usa Wordpress, este código deverá ser colocado dentro do arquivo header.php do seu template, pois é nele que está a definição do head.
Novo visual em um novo servidor
Só o autor continua o mesmo.
Mudei a cara do bicho e a partir de agora está hospedado na DreamHost. Aproveitei o embalo e também criei uma nova página falando um pouco deste servidor.
A migração dos dados foi um pouco trabalhosa (toda culpa é minha), pois o mysql do servidor antigo (IPHotel) roda sobre Windows usando o charset latin1 (ISO-8859-1) e o da Dreamhost é UTF-8.
O cara que está escrevendo este post viu o primeiro botão pra importar um arquivo e mandou ver. Quando abriu o blog pra conferir o conteúdo importado, estava lá uma montoeira de caracteres que deveriam ter acento mas, ao invés disso, tinham vários pontos de interrogação no lugar.
Então fica aí a dica: quando for importar um arquivo qualquer na DreamHost, use o phpMyAdmin, opção Import e não esqueça de definir o charset do arquivo que você está importanto. Fazendo isso da maneira correta, ele automaticamente converterá para UTF-8 e você será feliz para sempre.
Ah, mais uma dica que anotei enquanto fazia a migração: a versão antiga do Wordpress era a 2.0. A nova, instalada através do painel da DreamHost é a 2.2. Nesta última, uma série de alterações na base de dados foi implementada. Logo, não adianta apenas copiar os dados e sair rodando, pois não vai funcionar. O que eu fiz pra deixar tudo certinho foi o seguinte:
- Exportei os dados do MySQL da IPHotel usando o MySQL Front (isso vai gerar um arquivo .sql com todos os dados da base);
- Instalei o Wordpress através do painel de controle da DreamHost;
- Importei todos os dados exportados anteriormente. Aqui vale a pena ressaltar que você deve garantir que as tabelas do mysql destino estejam vazias. Para isso, antes de cada comando insert do arquivo de importação/exportação, faça um DELETE FROM tabela ou DROP tabela. Se você utilizar o MySQL Front, pode marcar as opções de exportação da seguinte forma:

- Fui até o phpMyAdmin da DreamHost (disponível no painel de controle / Goodies / Manage MySQL) e importei o arquivo gerado através da opção Import. É neste momento que precisei definir o charset do arquivo de origem. Veja:

- Bastou clicar no botão Executar e pronto! Os dados foram copiados da base antiga para a nova;
- Depois disto, como minha versão do Wordpress era a 2.0 e a instalada é a 2.2, precisei rodar o sistema de atualização. Ele é facilmente acessado através da URL http://www.seublog.com/wp-admin/upgrade.php. A sequência de telas abaixo apareceu e após isso a atualização ficou pronta.

Início do Upgrade

Fim do Upgrade
Depois deste procedimento o blog estava pronto para ser editado e atualizado.
É isso ae. Até +.
The resource cannot be found: HTTP 404
Você já se deparou com o erro abaixo?
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
Estava lendo o tradicional blog do Benjamin Day e encontrei um post sobre a provável causa desta mensagem.
No .NET 2.0 está disponível uma nova funcionalidade para fazer com que a aplicação fique totalmente indisponível por um tempo. Isto é muito conveniente quando o site está sendo atualizado (envio de arquivos, troca de assemblies, reestruturação do banco de dados, etc).
Para que isto ocorra, basta criar um arquivo chamado App_Offline.htm dentro da pasta raiz da aplicação. Exemplo:

Todos os requests feitos ao site (independente da pasta ou arquivo da url) serão redirecionados para o App_Offline.htm. Vale a pena salientar que se você deixar este arquivo sem conteúdo algum, uma mensagem padrão será apresentada (que é a descrita logo no início do post). No entanto, você pode personalizar da forma que bem entender.
Indo um pouco mais a fundo no assunto, O ScottGu dá uma dica para que esta técnica funcione corretamente no IE 6. Nesta versão do Internet Explorer há uma feature chamada Show Friendly Http Errors (Tools -> Internet Options -> Advanced), ou no bom português: Mostrar mensagens de erro http amigáveis.
Quando esta opção estiver habilitada e o servidor retornar um status HTTP diferente do 200 e com menos de 512 bytes, o browser não irá mostrar o conteúdo do arquivo App_Offline.htm, mas sim aquela página de erro padrão:

A dica é: se você quer apresentar uma mensagem muito curta (menor que 512 bytes), utilize comentários para completar o tamanho que falta. Exemplo (do próprio blog do Scott):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head> <title>Site Under Construction</title> </head> <body> <h1>Under Construction</h1> <h2>Gone to Florida for the sun...</h2> <!-- Adding additional hidden content so that IE Friendly Errors don't prevent this message from displaying (note: it will show a "friendly" 404 error if the content isn't of a certain size). <h2>Gone to Florida for the sun...</h2> <h2>Gone to Florida for the sun...</h2> <h2>Gone to Florida for the sun...</h2> <h2>Gone to Florida for the sun...</h2> <h2>Gone to Florida for the sun...</h2> <h2>Gone to Florida for the sun...</h2> <h2>Gone to Florida for the sun...</h2> <h2>Gone to Florida for the sun...</h2> <h2>Gone to Florida for the sun...</h2> <h2>Gone to Florida for the sun...</h2> <h2>Gone to Florida for the sun...</h2> <h2>Gone to Florida for the sun...</h2> <h2>Gone to Florida for the sun...</h2> --> </body> </html>
Feio né?
Acho que vale mais a pena perder uns 15 minutos pra criar uma mensagem amigável.
Até +.
E-mail num servidor e site em outro: Google Apps + Dreamhost
Recentemente fiz um registro na Dreamhost e tive o direito de escolher um domínio grátis. Como estava querendo registrar o dellantonio.net há um certo tempo, aproveitei a oportunidade.
Porém, fiz algo que não sabia que existia nunca tinha feito antes: direcionei todos os e-mails para o Google Apps, que fica, obviamente, em um dos servidores da Google e hospedei o site na Dreamhost. Veja bem: um mesmo domínio hospedado em locais diferentes.
Para fazer isso é relativamente simples. Você deve acessar seu gerenciador de domínios e alterar os servidores Mail eXchanger (MX) e o host de arquivos em si.
O MX é responsável pelo funcionamento dos e-mails. No meu caso, todas as mensagens enviadas para o domínio dellantonio.net serão redirecionados para o Google e, consequentemente, gerenciadas pelo utópico GMail.
No que diz respeito aos arquivos (blog, etc), ficarão na Dreamhost. Desta forma, quando alguém acessar www.dellantonio.net, é para lá que o usuário será enviado.
E sobre o Google Apps?
Se você ainda não conhece, ah, não perca tempo. Basta apontar o servidor MX para lá e pronto: seus e-mails serão acessados, hospedados e gerenciados pelo GMail.
Para acessar este e outros recursos, é preciso ter uma conta no Google, fazer o login no site do Google Apps e falar um pouco da sua empresa (se não tiver uma, fale de você mesmo). O processo de aviso quando a versão beta estiver disponível é fake. O registro é feito na hora e você já pode fazer todas as configurações que precisa.
É isso aí.
T+
Delphi: como interceptar o evento OnExit de um TMaskEdit?
Com certeza o componente TMaskEdit foi modelado às pressas pela equipe responsável, pois forçar uma validação com uma mensagem fixa sempre que o usuário sai do campo é um crime. E tem mais: eu diria que a pena é de prisão perpétua, pois além disso, quando você limpa o conteúdo do campo e sai dele, a validação também é executada. Neste caso, adivinha o que acontece? Uma mensagem de erro aparece mesmo sem ter valor algum no campo.
Há quem diga que é impossível desabilitar esta validação. Realmente é, se pensarmos de forma racional. No entanto, não custa nada partir pra baixaria uma vez ou outra.
Todos os componentes trabalham com mensagens enviadas pelo Windows para ativar os eventos. Portanto, o que acontece com o TMaskEdit?
Ele recebe uma mensagem informando que o usuário saiu do campo, executa o OnExit e, neste momento, faz a validação do conteúdo.
Já que o problema descrito acima acontece mesmo quando o usuário limpa o valor do campo, a solução é interceptar o evento OnExit e só executar o código padrão caso algum valor tenha sido informado.
Como fazer? Simples. Veja:
Declare uma procedure type of object (em outra palavras, um método) e um field do tipo TWndMethod:
FOldWindowProc: TWndMethod; procedure WMWindowProc(var Msg: TMessage);
A implementação do método é a seguinte:
procedure TfrmForm.WMWindowProc(var Msg: TMessage); begin if (Msg.Msg = CM_EXIT) then begin if (maskEdit.Text <> '') then FOldWindowProc(Msg); end else FOldWindowProc(Msg); end;
No evento FormShow do formulário faça as seguintes atribuições:
FOldWindowProc := maskEdit.WindowProc; maskEdit.WindowProc := WMWindowProc;
Pronto! Agora sempre que o evento OnExit do TMaskEdit for executado ele só fará a validação se o Text for diferente de vazio.
T+
Ps1: falei especificamente do TMaskEdit, porém este conceito de captura de eventos vale para todos os componentes.
Ps2: há alguns meses eu escrevi sobre algo parecido com o componente TScrollBox. Veja aqui.
"Este sistema só pode ser acessado com Internet Explorer 6.0+"
Uma imagem vale mais do mil palavras. Eu só me pergunto: o que eu fiz de errado para merecer isto?
Até +.
C#: obtendo a diferença em dias entre duas datas
Recebi via e-mail a dúvida de um usuário que não sabia como obter a diferença entre duas datas em C#.
Eu lembro que no livro 58+ Soluções em .NET, do Fabio Camara, ele sugeria o uso do método DateDiff do VB.NET. Mas ora, será que o C# não tem algo equivalente?
Tem sim. Veja no exemplo abaixo:
static void Main(string[] args) { DateTime inicio = new DateTime(2007, 05, 01); DateTime fim = new DateTime(2007, 06, 05); TimeSpan diff; // Subtraindo normalmente diff = fim - inicio; Console.WriteLine(diff.Days); // Usando Subtract diff = fim.Subtract(inicio); Console.WriteLine(diff.Days); // Convertendo os dias em meses DateTime data = new DateTime().AddDays(diff.Days); Console.WriteLine(data.ToString("dd/MM")); Console.ReadLine(); }
É isso ae! Até +.
