30 de abril de 2010

Uso de redes sociais por empresas ainda é pequeno

Recentemente foi publicado um levantamento feito em São Paulo pela Associação Comercial (ACSP) revelando que apenas 17% das empresas fazem uso de redes sociais (Orkut, Facebook, Twitter, etc.). Ao que parece, as empresas do estado ainda dão preferência a se relacionar com seu público apenas através de sites institucionais próprios. De acordo com o site da ACSP, o estudo levou em conta entrevistas em 500 empresas de vários segmentos econômicos.

Mesmo que muitas das empresas pesquisadas não se relacionem diretamente com o grande público, é estranho que não usem essas ferramentas para divulgar suas marcas, ainda mais se considerarmos uma outra pesquisa revelada mais ou menos na mesma época e que mostra que o brasileiro é quem mais gasta tempo navegando na internet. Do tempo despendido nesta atividade, em média 4.5 horas por mês são relativas à navegação em redes sociais, o que nos coloca em sexto lugar no ranking dos maiores navegadores. Veja a matéria publicada pela Info Online aqui.

Talvez a razão para a não adoção esteja no fato de que as empresas brasileiras são as que mais restringem o acesso de seus funcionários às redes sociais no ambiente do trabalho, conforme revelou pesquisa da consultoria de recursos humanos ManPower. Ou seja, se elas não permitem que seus próprios funcionários acessem redes sociais, por que é que usariam esse meio para suas divulgações ?

A chave provavelmente é o desconhecimento. Redes sociais voltadas para ambiente corporativo são um fenômeno recente, de modo que as companhias ainda não conseguem enxergar como exatamente tais ferramentas podem auxiliá-las, o que as leva a considerar apenas as ameaças potenciais. No entanto, omitir-se representa um risco para a empresa já que ela pode estar deixando de se fazer ouvir e de interagir, impedindo uma comunicação que pode se mostrar essencial para a evolução da corporação. Veja aqui matéria da ComputerWorld a respeito do bloqueio de redes sociais nas empresas.

Mesmo antes de ter conhecimento dessas pesquisas, a ABC71 percebeu que as redes sociais tem um grande potencial enquanto ferramentas de comunicação com seus Clientes e também como forma de tornar seu nome mais conhecido no mercado. Essa percepção levou a empresa a criar perfis em diversas redes sociais, além de uma completa reformulação em seu site corporativo para poder se integrar com tais redes. Abaixo eu reproduzo matéria do portal ERP News a esse respeito. O texto original pode ser acessado neste link.

A partir de hoje, o site da ABC71 – www.abc71.com.br – estará com novo layout, muito mais dinâmico e funcional para os internautas. Selene Sidney , gerente de marketing da empresa, explica que site foi transformado em um portal com novas funcionalidades e informações de gestão e TI, não só da empresa, mas do mercado, de modo geral. “Nosso objetivo é ampliar a atuação na internet usando as mais avançadas práticas, como, por exemplo, a integração com redes sociais”.

Notícias, casos de sucessos, depoimentos de clientes, artigos de especialistas, entre outros assuntos, estarão disponíveis para que o público fique ainda mais atualizado sobre a empresa e as tendências nas áreas de gestão corporativa e tecnologia. “Todas as informações do site vão ajudar os executivos das empresas a se atualizarem com as melhores práticas de TI e gestão”, completa Selene.

Para cada público haverá informações diferenciadas. Isto é, o site da ABC71 pretende atender tanto seu público interno como seu público externo. Por isso, o site possuirá uma área de downloads para parceiros; informações da ABC71 para os clientes; e, acesso a materiais exclusivos como casos de sucesso completos, vídeos de demonstração, entre muitas funcionalidades para os prospects da empresa.

“Estudos foram realizados sobre o perfil e o comportamento dos nossos prospects, sobre os interesses dos que trabalham com TI e o que os gestores das empresas querem saber. Ou seja, fizemos um levantamento sobre as necessidades de cada público. Por isso, conseguimos fazer algo tão focado para eles”, conclui Selene.

Para ver o artigo da Associação Comercial de São Paulo sobre a adoção de redes sociais pelas empresas, veja o link http://www.acsp.com.br/upload/nce/ligadonaacsp/23_noticia1.html.

26 de abril de 2010

Recuperando a lista de adaptadores de um computador em Delphi

Em maio de 2009, bem no início desse blog, postei um texto chamado Obtendo o MAC Address para gerar um Hardware Key em Delphi, onde eu recuperava o MAC Address do adaptador de rede para gerar um código único a ser usado para liberar o licenciamento de um produto qualquer. Os trechos de programa incluídos naquele post permitiam recuperar apenas o primeiro adaptador, ignorando a existência de outros.

Enviaram-me, então, uma situação (veja aqui) em que o uso de um adaptador bluetooth instalado na USB modifica a ordem com que os adaptadores são listados. A pergunta decorrente desse cenário é como garantir que a chave gerada será sempre a mesma, sem termos que ficar na dependência da ordem com que os adaptadores são listados?

No exemplo do outro post, usei a função GetAdaptersInfo da API do Windows mas não mostrei como percorrer a lista de adaptadores. Essa função popula uma estrutura do tipo IP_ADAPTER_INFO com informações relativas a um único adaptador por vez. A estrutura IP_ADAPTER_INFO é na verdade uma lista ligada, sendo que as informações para a estrutura seguinte podem ser acessadas através do campo Next. Quando esse campo está prenchido com o valor Nil, significa que não há mais adaptadores na lista:
var i : integer;
pAdapterInfo : PIP_ADAPTER_INFO;
begin
{ ... }
repeat
{ Processa informações do adaptador atualmente posicionado }
for i := 0 to MAX_ADAPTER_ADDRESS_LENGTH - 1 do
Result[i] := pAdapterInfo.Address[i];

pAdapterInfo := pAdapterInfo.Next;
until (pAdapterInfo = Nil);
{ ... }
No trecho acima eu não mostro a chamada à função GetAdaptersInfo, que inicia as informaçõe em pAdapterInfo - veja aqui uma explicação de como fazer isso.

A ideia de percorrer toda a lista de adaptadores é que agora podemos aplicar o cálculo do código de identificação do licenciamento mostrado no outro post usando cada um dos MAC Address listados até que um deles gere o código correto ou que o fim da lista seja atingido.

Uma forma de minimizar o problema seria restringir a lista de adaptadores, verificando-lhes o tipo - se é um adaptador Ethernet, SLIP, PPP, Token Ring, etc. Essa informação é colocada no campo Type_ da estrutura IP_ADAPTER_INFO; os valores possíveis para esse campo estão na documentação encontrada no MSDN.

Segue uma função completa capaz de obter os adaptadores e percorrer a lista. Adaptadores do tipo Token Ring são desconsiderados pelo programa:
procedure ListaMACaddress;
varAdapterInfo : Pointer;
pAdapterInfo : PIP_ADAPTER_INFO;
dwBufLen, dwStatus : LongWord;
begin
dwBufLen := 0;
AdapterInfo := Nil;

GetAdaptersInfo(PIP_ADAPTER_INFO (AdapterInfo), dwBufLen);
if (dwBufLen > 0) then begin
GetMem (AdapterInfo, dwBufLen);
dwStatus := GetAdaptersInfo(PIP_ADAPTER_INFO (AdapterInfo), dwBufLen);

if (dwStatus = ERROR_SUCCESS) then begin
pAdapterInfo := PIP_ADAPTER_INFO (AdapterInfo);

repeat
{ Processa informações do adaptador atualmente posicionado }
if (pAdapterInfo.Type_ <> MIB_IF_TYPE_TOKENRING) then
TrataAdaptador (pAdapterInfo);

{ Próximo adaptador da lista }
pAdapterInfo := pAdapterInfo.Next;
until (pAdapterInfo = Nil);

FreeMem (AdapterInfo);
end;
end;
end;
A função TrataAdaptador não está listada nesse trecho mas seu objetivo é representar uma operação qualquer em cima dos dados de um adaptador.

22 de abril de 2010

Criando componentes com Delphi - parte II

Para mostrar os conceitos mais básicos por trás da criação de componentes no Delphi eu vou usar um exemplo bastante simples. Esse primeiro componente servirá apenas para forçar que a altura e o comprimento de um botão sejam mantidos num valor fixo. O objetivo é que estas propriedades do botão fiquem automaticamente padronizadas, sem possibilidade de que o programador possa alterá-las quando estiver desenhando uma tela. Essa técnica permite que se estabeleçam padrões visuais a serem compartilhados por todas as telas de um programa, que manterá uma identidade visual coesa. Mudar algum dos padrões seria, então, questão de mudar internamente um único componente !

Ok ! Esse mesmo objetivo pode ser atingido clicando-se com o botão direito num componente e escolhendo-se o comando Add To Palete. Mas esse procedimento esconde alguns dos conceitos que eu gostaria de mostrar.

De início, vou criar um novo pacote para incluir o componente e assim poder distribuí-lo junto com as aplicações - ou para que outros desenvolvedores possam criar suas aplicações. A compilação de um pacote no Delphi (e C++ Builder) gera uma arquivo com extensão BPL que é na verdade uma DLL com algumas particularidades.
Pacote
Neste exemplo, a mesma biblioteca BPL será usada tanto em design time (ambiente de desenvolvimento) quanto em runtime (tem que estar presente quando for executar as aplicações).

Agora que já temos o pacote que servirá de container ao nosso componente, podemos criar-lhe o esqueleto. Na minha versão do Delphi (2005), isso pode ser feito através do menu Component, opção New VCL Component. A seguir, é apresentado um wizard onde se pode escolher a classe que servirá de base para o componente. Como já existe um componente com toda a funcionalidade do botão, vou usá-lo como base para não ter que reinventar a roda. Após informar o nome para o novo componente, é criada uma unit com o básico a respeito do componente:
TWButtonModelo = class(TButton)
private
{ Private declarations }
protected
{ Protected declarations }
public
{ Public declarations }
published
{ Published declarations }
end;

{ ... }

procedure Register;
begin
RegisterComponents('Samples', [TWButtonModelo]);
end;

A procedure Register é criada automaticamente e representa uma parte importante do processo de fazer o IDE do Delphi enxergar o componente. Quando solicitamos ao IDE que faça a instalação de um pacote BPL, ele procurará dentro da biblioteca a função Register de cada unit e as executará. Como resultado, os componentes existentes no pacote passarão a ficar disponíveis na paleta de componentes do IDE, podendo então ser usado pelo programador em qualquer form.

Veja que no esqueleto gerado para a classe do componente há uma seção chamada Published. As propriedades que forem incluídas nessa seção poderão ser modificadas pelo programador em design time já que elas aparecerão no Inspector do Delphi quando o nosso componente estiver selecionado. Do ponto de vista das restrições de acesso por outras áreas do programa, propriedades published funcionam exatamente da mesma maneira que aquelas na seção Public, isto é, são sempre visíveis para as demais units.

Pra terminar esse exemplo básico, falta apenas restringir a mudança de valores de altura e comprimento, que é o comportamento proposto. Há uma função chamada SetBounds introduzida na classe TControl que é responsável pelas alterações relativas a posicionamento e dimensões de todos os controles. Como ela é declarada como virtual, vou apenas sobrepô-la e forçar os tamanhos que eu quero:
procedure TWButtonModelo.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
begin
AWidth := 80;
AHeight := 28;
inherited SetBounds(ALeft, ATop, AWidth, AHeight);
end;
Essa função é chamada mesmo que se modifique o valor de uma única propriedade relacionada ao tamanho do componente. Isto é, se você tentar modificar a altura ou o comprimento separadamente, ainda assim a função é chamada e forçará os valores fixados dentro do componente.

14 de abril de 2010

Criando componentes com Delphi - parte I

Um componente é um pedaço de programa construído para executar uma tarefa específica. Desse modo, o mesmo pedaço pode ser adicionado a quaisquer programas que precisem executar a tarefa proposta. Além de agilizar a criação de novos programas, criar componentes os torna mais seguros já que, uma vez que o componente foi bem testado, o risco de que ele apresente alguma falha fica reduzido. Para resumir em uma expressão, componentizar significa reutilizar códigos que já foram validados - com todas os benefícios que isso implica (tempo, dinheiro, segurança, etc.).

O desenvolvimento de programas através dos ambientes Delphi e C++ Builder é fortemente calcado na criação de componentes. Embora a maioria dos componentes disponíveis sejam visuais, isto é, propiciam ao usuário do programa final algum tipo de interação visual (botões, caixas de edição, tree views, etc.), isto não é uma obrigação. Há uma categoria de componentes "não visuais" que executam suas tarefas sem serem apresentados na tela. Mas esse fato é apenas uma das faces de um componente Delphi. Como todos os componentes nesse ambiente podem ser arrastados para montar um form, é preciso ainda se preocupar em como será a interação do componente com o programador que o está utilizando, quais propriedades serão publicadas para configuração através do Object Inspector, etc.

Por isso, iniciar a criação de um componente em Delphi demanda o planejamento de suas características estruturais. Responder algumas perguntas básicas ajuda nesse planejamento:
O que meu componente deve fazer ?
Pode parecer bobagem, mas estabelecer logo de cara o comportamento esperado para o componente ajuda a evitar surpresas desagradáveis. Querer acrescentar mais tarde uma funcionalidade que não tinha sido prevista pode exigir uma revisão radical da estrutura, tanto do componente quanto de outros fontes associados a ele.
Meu componente será exibido na interface gráfica ?
Todo componente no Delphi deve ser criado como uma herança direta ou indireta da classe TComponent, que é quem fornece o comportamento para interação com o form e outros detalhes. Responder a essa pergunta ajudará a determinar qual das classes derivadas de TComponent deverá ser usada como superclasse para nosso componente. Por exemplo, todos os componentes visíveis para o usuário devem herdar de TControl (ou uma de suas muitas heranças).
O componente que vou construir é totalmente novo ou já algo parecido ?
Aqui novamente o objetivo é estabelecer a classe base mais apropriada para nosso componente. Se o que você almeja é, por exemplo, padronizar o comprimento e a altura dos botões que serão adicionados aos forms seu programa, não é preciso criar um novo botão do zero. Neste caso, é mais prático criar uma herança de TButton.
Como será a interação com o programador ?
A resposta a essa pergunta permite determinar com antecedência quais propriedades deverão ser publicadas no inspector, a planejar a forma com que o componente como um todo se comportará quando houver alterações no valor dessas propriedades - inclusive em Design - e antever se será preciso criar um editor especial para facilitar a manutenção desses valores em tempo de design.
Meu componente estará vinculado a um Banco de dados ?
Permitir que um componente interaja com banco de dados exige alguns cuidados extras. O componente poderá estar ligado a um único campo, a uma query ou a uma tabela inteira, sendo que a comunicação deve ser feita por intermédio de classes especiais. Também é preciso cuidado para não disparar alterações não previstas nos dados.
Meu componente estará vinculado a outro(s) componente(s) ?
Vincular um componente a outro não é uma situação rara - muitos componentes permitem associar um Popup Menu ou um Action (ação genérica), por exemplo. Mas isso requer atenção com as interações decorrentes de tal associação. Um problema clássico envolvendo esse cenário é como agir quando o componente associado é removido da memória (comando Free).
Introduzir eventos faz sentido no meu componente ?
Eventos servem para notificar o programador a respeito de ocorrências relevantes dentro do seu componente. Eles dão ao programador a oportunidade de tomar providências, modificando o comportamento padrão do seu componente ou usando informações fornecidas por ele para realizar alguma outra operação - como mostrar um status. Alguns exemplos de eventos: um botão foi clicado, um novo registro está posicionado no banco de dados, uma operação se encerrou, um erro ocorreu, etc.
Em suas versões mais recentes, o Delphi passou a diferenciar os pacotes de componentes que podem ser usados em tempo de Design daqueles exclusivos para uso em tempo de execução. Essa diferenciação ocorreu porque componentes complexos podem incluir editores especiais para facilitar a vida do programador que está configurando o componente em tempo de design. Esses editores deixavam o pacote maior mas eram irrelevantes para o usuário final, de forma que agora eles podem ser incluídos num pacote a parte que não precisa ser distribuído.

Portanto, ao planejar um pacote de componentes, essa organização também deve ser levada em consideração - embora ainda exista a possibilidade de se criar pacotes que funcionem tanto em Design quanto em Execução.

Em outros posts eu mostro na prática e passo a passo como criar componentes, desde simples heranças de componentes preexistentes até a criação de editores especiais para componentes complexos, passando por uso de eventos, aplicação de funções da API do Windows, vínculo com banco de dados, associações entre componentes e outros assuntos que forem surgindo.

6 de abril de 2010

Sincronizando arquivos e pastas no Windows

O computador invadiu faz tempo a nossa vida e já se foi a época em que mal tínhamos uma única máquina pra trabalhar. Agora há um computador no escritório, outro em casa, talvez um notebook pra quando viajamos e um outro pra quando vamos a algum Cliente. Dar manutenção em documentos, preparar apresentações, editar planilhas e arquivos fontes são tarefas que não raro temos que fazer em computadores diferentes, dependendo do momento e do lugar em que estamos trabalhando.

É fácil ver que essa situação leva à criação de diversas pastas com versões diferentes de documentos e outros arquivos. Como, então, proceder para termos certeza de que estamos realmente editando a última versão de um documento ou usando a compilação mais atualizada de um programa ?

Tendo esse cenário em mente, a Microsoft criou um programa simples e gratuito, chamado SyncToy cuja versão mais recente é a 2.1.

A operação do SyncToy 2.1 é bastante intuitiva; nele você cria pares de pastas que devem ser mantidas em sincronia e atribui um nome a cada par. Quaisquer pastas que seu computador enxergar poderão ser sincronizadas - pastas locais, na rede, num pen-drive, etc. Quando quiser sincronizar, selecione o nome do par e mande executar a sincronização; é claro que há também a opção de mandar sincronizar todos os pares simultaneamente.

A imagem abaixo mostra o par em que sincronizo os arquivos que compõem esse blog, de modo que posso fazer alterações tanto em casa quanto no escritório, tendo certeza de estar sempre com a última versão de cada arquivo.
SyncToy 2.1
Um dos melhores recursos da ferramenta é o que permite fazer um "preview" das operações que serão executadas. Com ele você vê com antecedência se a operação que será realizada é mesmo a que você deseja, sem risco de perder dados.

Há ainda configurações que permitem estipular quais extensões de arquivos devem ser consideradas e quais o SincToy deve ignorar (ex: não copiar imagens com extensão JPG). Também é possível selecionar quais das subpastas devem ser incluídas na sincronização, além da opção de lançar na lixeira arquivos que tenham sido removidos (ou sobrepostos), ao invés de simplesmente replicar a remoção.

Mas o que exatamente é sincronizado ? O mecanismo padrão é denominado Syncronize e, nesse modo, todas as alterações, criações e remoções de arquivos e pastas são sincronizadas, independente de qual das pastas no par sofreu as alterações. Há outros dois modos para se trabalhar: no modo Echo, apenas manutenções feitas na pasta (e subpastas) da esquerda são replicadas (vão para a pasta exibida à direita na interface), enquanto as alterações feitas na pasta da direita são ignoradas. O último modo disponível é o Contribute, que funciona basicamente como o Echo, exceto pelo fato de que as exclusões de arquivos são desconsideradas.

O SyncToy 2.1 possui versões tanto para sistemas 32 bits quanto para os de 64 bits. De acordo com o site da Microsoft, o programa é suportado pelo Windows 7, pelo Windows Vista e também pelo Windows XP.

O download pode ser feito diretamente através do site da Microsoft (neste link) mas há diversos outros sites que também o disponibilizam (Baixaki, Info, etc.).

Atenção : se você já usa uma versão anterior do SyncToy, veja no site da Microsoft como atualizar para a nova versão sem perigo de perder seus dados.

Mais Informações
Download do SyncToy 2.1

1 de abril de 2010

Obtendo informações sobre as tabelas de um banco SQL Server

Criar documentação para um sistema é sempre uma parte aborrecida e frequentemente negligenciada justamente por causa disso. No caso da ABC71, além da documentação das telas que é distribuída junto com o sistema, nós temos um documento que descreve as tabelas existentes no banco de dados. Sempre que uma tabela ou coluna nova é criada (ou modificada), nós registramos uma pequena descrição dela em uma tabela nossa, específica para esse fim.

Esse documento que descreve as tabelas é destinado a quem precise dar manutenção em dados diretamente no banco (parceiros, consultores, usuários avançados, etc.). Obviamente, ter apenas um breve descritivo de cada campo não é suficiente para esse objetivo - até porque é comum esquecer de alimentar a tal tabela.

Para gerar um documento mais completo, uso um conjunto de views do próprio SQL Server que permite obter informações sobre qualquer objeto existente no banco : tabelas e suas colunas, chaves, triggers, stored procedures, constraints, etc. Neste post, mostro como obter informações básicas, como a lista de tabelas, suas colunas e chaves.

A principal dessas views é a sys.sysobjects cujas linhas produzem um inventário dos objetos existentes no banco. As principais colunas retornadas por essa view estão descritas abaixo.
name é o nome de um objeto
id é o identificador único de cada objeto, independente do tipo desse objeto. O id é chave estrangeira em outras views, podendo ser usado para obter mais detalhes a respeito de um objeto. Por exemblo, há uma view que relaciona as colunas de uma determinada tabela e, nessa view, o id identifica qual é a tabela associada.
xtype identifica o tipo do objeto em cada linha da view. Essa coluna pode ser usada para filtrar os registros corretos quando for necessário um join para obter mais detalhes em outras views, como no caso das colunas citado acima. Os tipos possíveis podem ser encontrados neste link do MSDN.

Como exemplo, a query abaixo lista as tabelas de um banco.
select id, name from sys.sysobjects where xtype = 'U'

Efeito semelhante pode ser obtido simplesmente listando as linhas da view systables:
select * from sys.systables

As colunas de uma tabela são recuperadas acessando-se a view sys.syscolumns, cujas principais colunas eu comento abaixo.
name é o nome da coluna.
id identifica a tabela a qual essa coluna pertence. É o mesmo id encontrado em sys.sysobjetcs, podendo ser relacionado com ele para obter o nome da tabela.
Em type encontramos a identificação do tipo de dado atribuído à coluna. O nome para o tipo pode ser localizado na tabela sys.types. Para tipos núméricos, as colunas prec (precisão) e scale também deve ser levadas em consideração. No caso de tipos alfanuméricos ou binários, a coluna lenght determinará o tamanho máximo permitido.
O status informa, por exemplo, se essa coluna aceita o valor NULL. Para saber quais são os valores possíveis, veja a documentação no MSDN.
A ordem com que cada coluna foi criada dentro da tabela é estabelecida pelo campo colorder.

Se você não estiver trabalhando com tipos de dados criados pelo usuário, a query abaixo consegue listar as colunas de todas as tabelas de seu banco:
select *,
(select name from sys.types t
where c.type = t. system_type_id
and t.is_user_defined = 0) As Tipo
from sys.syscolumns c
--where c.id = 0 /* use o id de uma tabela p/ obter as colunas específicas */

Para levantar quais são as chaves criadas para uma tabela, podemos usar as informações retornadas pela view sys.sysindexes em conjunto com as linhas da view sys.sysindexkeys. Basicamente, a primeira view traz os nomes das chaves enquanto a segunda traz as colunas que constituem cada chave. Os campos mais relevantes da sys.sysindexes são os seguintes:
name é o nome atribuído à chave.
id novamente identifica uma tabela, cujo nome pode ser obtido relacionando-se esse campo com id encontrado em sys.sysobjetcs.
indid é um código único definido por tabela e que serve para identificar cada chave dessa tabela. Aparentemente, o valor 0 (zero) é sempre um valor interno do SQL; portanto, nos interessa apenas os registros cujo valor é maior que zero.
keycnt retorna a quantidade de campos que compõem a chave.
Use o status para determinar se a chave é primária, isso é, se os valores dos campos dessa chave poderão ser repetidos em outros registros ou não.

Na view sys.sysindexkeys encontramos os campos id (a tabela em sysobjects), indid (a chave em sysindexes) e colid (a coluna que compõe a chave, relacionada com a view syscolumns). O último campo é keyno, que indica a ordem em que as colunas aparecem na chave. A query abaixo usa essas informações para obter os nomes das colunas que compõem uma chave:
select I.name as Chave, IK.keyno as Ordem, c.name as Coluna
from sys.sysindexes I, sys.sysindexkeys IK, sys.syscolumns C
where I.id = IK.id
and I.id = c.id
and I.indid = IK.indid
and IK.colid = C.colid
and I.id = 2042867486 /* id da tabela */
and IK.indid = 2 /* número de uma chave da tabela */
order by IK.keyno

Note que há valores fixos para o objeto (tabela) e para a chave. Esse números devem ser substituídos por códigos válidos no seu banco de dados.