Você está na página 1de 30

Revista The Club Megazine - 04/2002

A utilizao, reproduo, apropriao, armazenamento em banco de dados, sob qualquer forma ou meio, de textos, fotos e outras criaes intelectuais em cada publicao da revista The Club so terminantemente proibidos sem autorizao escrita dos titulares dos direitos autorais.

Copyright The Club 2002

EDITORIAL

Editorial
Ol amigos, A revista deste ms trs assuntos muito interessantes. Para quem est acompanhando as informaes sobre a plataforma .NET, Mauro SantAnna fala sobre o controle de verso na plataforma .NET. Sobre o Oracle veja algumas dicas valiosas sobre administrao. Em relao ao Palm voc ir encontrar informaes sobre o formato do arquivo PDB. Sobre Automao comercial voc ver como fazer a troca de operador em um PDV. Voc ver tambm uma matria muito interessante sobre o monitoramento de ocorrncias do Windows. Caso voc tenha algum assunto que gostaria de ver em nossa revista, envie um e-mail para info@theclub.com.br. A sua participao muito importante para ns. At o prximo ms.....
THE CLUB
Rua Acre, 950 - Avar - SP - CEP 18.700-260 Informaes: (0xx14) 3732-3689 Suporte: (0xx14) 3733-1588 Fax: (0xx14) 3732-0987

Internet
http://www.theclub.com.br Cadastro: cadastro@theclub.com.br Suporte: suporte@theclub.com.br Informaes: info@theclub.com.br

Dvidas
Correspondncia ou fax com dvidas devem ser enviados ao - THE CLUB, indicando "Suporte".

Opinio
Se voc quer dar a sua opinio sobre o clube em geral, mande a sua correspondncia para a seo "Tire sua dvida".

Reproduo
A utilizao, reproduo, apropriao, armazenamento em banco de dados, sob qualquer forma ou meio, de textos, fotos e outras criaes intelectuais em cada publicao da Revista The Club so terminantemente proibidos sem autorizao escrita dos titulares dos direitos autorais.

Copyright The Club 2002 Impresso e acabamento:


Impressos Gril - Gril Grfica e Repr. Ind. Ltda.
Tel.: (0xx14) 3762.1345 - Fax: (0xx14) 3762.1259 Rua So Paulo, 447 - Cep 18.740-000 Taquarituba - SP Tiragem: 5.000 exemplares

Celso Jefferson Paganelli Presidente - The Club

Diretor - Presidente

Celso Jefferson M. Paganelli


Diretor Tcnico

Mauro SantAnna
Colaboradores
Mrio Camilo Bohm - Claudenir C. Andrade Anderson Haertel Rodrigues - Marcio Alexandroni
Delphi marca registrada da Borland International, as demais marcas citadas so registradas pelos seus respectivos proprietrios.

Editorial ........................................................................................ 03 Controle de verso na plataforma .NET ....................................... 04 Dicas de instrues e comandos Oracle.................................... 07 Mtodos de Classe x ShowModal em Formulrios MDI ............. 09 Formato do arquivo PDB .............................................................. 11 Monitoramento de ocorrncias no Windows.............................. 16 Oque fazer para... Trocar de operador x ECF ............................... 26 Dicas & Truques .......................................................................... 28
MeGAZINE 3

COLUNA DO SANTANNA

Controle de verso na plataforma .NET


Por Mauro SantAnna (santanna@mas.com.br). Mauro um MSDN Regional Director, consultor e instrutor da MAS Informtica (www.mas.com.br), tendo ministrado treinamentos na arquitetura .NET desde outubro de 2000.

O Problema
Um dos grandes problemas existentes no Windows o controle de verses de DLL, tambm conhecido como DLL Hell. Estes so alguns de seus sintomas: As instalaes so frgeis: outros programas podem substituir uma DLL necessria e nosso programa deixa de funcionar; A instalao de nosso programa faz outros programas deixarem de funcionar; As desinstalaes por vezes deixam coisas para trs, como DLLs e entradas no Registry; impossvel ter duas verses diferentes de uma DLL carregadas ao mesmo tempo, mesmo que diferentes programas exijam diferentes verses. comum que o Windows tenha que ser reinstalado periodicamente.

sistema permite a carga simultnea das duas; uma no afeta a outra.

Assembly Shared
O esquema dos assemblies private simples e eficaz, mas por vezes precisamos ter uma DLL usada por vrios aplicativos simultaneamente. Isto possvel, mas temos que fazer o seguinte: Dar um nome forte DLL; isto inclui uma assinatura criptogrfica, um nmero de verso e uma cultura (que pode ser neutra; Instalar a DLL em um local global chamado Global Assembly Cache ou GAC. As tarefas acima so feitas da seguinte forma: Primeiro criamos uma chave criptogrfica com o comando sn k MyKeyFile.snk. O arquivo contendo a chave criada DEVE SER ARMAZENADO COM CUIDADO E NUNCA DESCARTADO. Esta chave criptogrfica pode ser usada na segurana interna de sua rede, por exemplo, exigindo que as DLLs usadas na empresa tenham esta assinatura. Alm disto, absolutamente necessria para a criao de uma verso mais nova da DLL; Colocamos uma diretiva no fonte da DLL AssemblyInfo.cs para referenciar o arquivo com a chave: [assembly: AssemblyKeyFile(MyKeyFile.snk)]; Depois de compilado, registramos o assembly com o comando gacutil /i nome.dll. A lista dos Os assemblies instalados pode ser vista com o comando c:>gacutil /l:

A Soluo
Para resolver estes problemas, a Microsoft na plataforma .NET introduziu o conceito de assemblies com strong name e o Global Assembly Cacha. A princpio, uma DLL usada por um programa deve estar necessariamente no mesmo diretrio do aplicativo ou em um subdiretrio, mas NUNCA em um diretrio arbitrrio do computador ou em algum local compartilhado como c:\windows\system32. Estas DLLs so chamadas de assemblies privados. Temos de cara uma grande vantagem: dois programas diferentes podem ter verses diferentes de uma mesma DLL: estas DLLs estaro necessariamente em diretrios distintos e o

MeGAZINE

COLUNA DO SANTANNA

Podemos tambm visualizar com uma Shell Extension no diretrio \windows\assembly\CAG:

MeGAZINE

COLUNA DO SANTANNA
Toda a informao a respeito da instalao das DLLs (nome, verso, cultura e token da chave criptogrfica) est apenas em arquivos e diretrios. Nada colocado no registry ou local similar. Experimente abrir uma console e visualizar o diretrio acima:

Veja um dos diretrios e compare com o que exibido no Windows Explorer:

Quando referenciamos uma DLL uma DLL atravs de early biding, as informaes de chave criptogrfica, verso e cultura so tambm colocadas no programa chamante, de forma a garantir que a verso correta utilizada. Um administrador pode alterar o nmero de verso que um programa aceita para rodar atravs da ferramenta de administrao do .NET, disponvel no painel de controle. Esta

ferramenta altera alguns arquivos XML de configurao como machine.config e nomedoaplicativo.exe.config.

Concluso
O .NET Framework efetivamente resolve o problema de DLL Hell que tanto contribuem para tornar os microcomputadores difceis e caros de administrar.

MeGAZINE

ORACLE

Dicas de Instrues e Comandos Oracle...


Mrio Camilo Bohm - Bohm,Interal Fone (011) 4221.6151 - mario@bohminteral.com.br

Vamos falar neste ms, de algumas dicas sobre administrao... LOG DAS CONEXES NO LISTENER Todas as conexes feitas no banco atravs do LISTENER, que o servio responsvel por escutar as solicitaes de conexo e operacionalizado por um servio do SO, so registradas no arquivo listener.log (onde listener corresponde tambm ao nome dado ao LISTENER na configurao do Net8). O arquivo listener.log localiza-se no sub-diretrio \NETWORK\ADMIN dentro do ORACLE_HOME. DIVERSOS NVEIS DE ARRAY NUMA MESMA INSTALAO J comentamos aqui que, para a maioria absoluta das instalaes de banco de dados, exceto aquelas com bases realmente muito pequenas, importante termos no servidor um storage baseado em array de discos. A Oracle no recomenda que uma instalao de banco de dados seja baseada em RAID 0 (onde se privilegia o desempenho

em detrimento da segurana), mas sim em RAID 5, que oferece um nvel maior de segurana e controle e com bom desempenho. Vamos imaginar que temos, por exemplo, um conjunto de 10 discos para estruturarmos nosso array de discos. No precisamos, mesmo que tenhamos apenas uma controladora, montar RAID 5 para todos os discos. Podemos destinar, por exemplo, 6 discos para a base de dados, numa estrutura RAID 5 e os demais 4 discos numa outra estrutura, em RAID 0, para o SO e os arquivos de swap do SO, que geralmente geram grande atividade de disco. Isso porque, embora tenhamos no RAID 0 um menor nvel de segurana, teremos um desempenho mais elevado para as tarefas operacionais e administrativas do SO, o que colaborar sensivelmente para a performance geral do storage. No caso de qualquer problema no storage no conjunto montado com RAID 0, o banco de dados estar preservado no conjunto montado com RAID 5, que no ser afetado, e poder ser facilmente recuperado numa outra instalao. Se tivermos ainda, uma controladora para cada conjunto de array, muito

MeGAZINE

ORACLE
melhor! REDO LOG FILES Os Redo Log Files so um conjunto de arquivos que tem como funo o registro de todas as transaes executadas no Banco de Dados. Este conjunto trabalha de forma circular, ou seja, quando o primeiro Log foi totalmente preenchido, o seguinte passa a ser utilizado. Aps o total preenchimento do ltimo log da sequncia, o banco volta a utilizar o primeiro, sobrepondo as informaes gravadas anteriormente. Os Redo Log Files podem ser espelhados, tendos as mesmas informaes registradas em locais distintos para maior segurana. Por este motivo so definidos grupos de Redo Log Files, tendo cada grupo um nmero varivel de membros. Os membros de cada grupo precisam ter o mesmo tamanho e devem estar em dispositivos fsicos diferentes para que a funo de espelhamento seja totalmente vlida. Portanto, a utilizao circular dos Redo Log Files referente aos grupos j que seus membros so idnticos em contedo e tamanho. Na criao do Banco de Dados so criados dois ou trs grupos de Redo Log Files (dependendo da plataforma) com um membro em cada grupo, e tamanho de 500k cada um. A verificao dos Redo Log Files existentes pode ser feita pela view V$LOG, como no exemplo abaixo: SQL> SELECT * FROM V$LOG; Uma vez definidos os Redo Log Files, seu tamanho no pode ser alterado, mas podem ser adicionados novos grupos substituindo os existentes. Esta operao solicita informar o file name para o novo Redo Log File. Para que se possa seguir o padro estabelecido no banco, pode-se verificar o diretrio de trabalho atravs da view V$LOGFILE, como no exemplo: SQL> SELECT * FROM V$LOGFILE; Para adicionar um novo Redo Log File, o usurio precisar ter o privilgio ALTER DATABASE. A sintaxe a ser utilizada a seguinte: SQL> ALTER DATABASE ADD LOGFILE GROUP N (FILENAME1,FILENAME2') SIZE n M); Onde, N - nmero do grupo a ser criado; FILENAME1 - nome do primeiro membro do novo grupo; FILENAME2 - nome do primeiro membro do novo grupo; E onde n igual ao tamanho do arquivo a ser criado, em megabytes. De acordo com este exemplo, para criar um novo grupo de Redo Log Files com dois membros e tamanho de 5MB, num diretrio D:\ORANT\REDOLOG, o comando seria: SQL > ALTER DATABASE ADD LOGFILE GROUP 4 2 (D:\ORANT\REDOLOG\LOG_UM.ORA, 3 D:\ORANT\REDOLOG\LOG_UM.ORA ) SIZE 5MB; Para remover grupos de Redo Log Files dimensionados de forma inadequada, o mesmo no pode estar como corrente no momento da eliminao. Deve ser verificado o status pela view V$LOG, e caso o Redo Log File a ser eliminado seja o corrente, deve ser forado o switch usando-se o seguinte comando: SQL> ALTER SYSTEM SWITCH LOGFILE; Verifique depois novamente o status do Redo Log File pela view V$LOG, certificando-se de que o log a ser removido no o log corrente. Para remover o log, usar o seguinte comando: SQL> ALTER DATABASE DROP LOGFILE GROUP N, Onde n o nmero do grupo a ser excludo. Estes procedimentos devem ser realizados com o banco no ar, porm com muito cuidado, pois excluir um log corrente pode causar a inutilizao do banco.

MeGAZINE

DELPHI

Mtodos de Classe x ShowModal em Formulrios MDI


por Anderson Haertel Rodrigues

Introduo:
O artigo desse ms poderia ser resumido em uma dica, mas, decidi alm de dar a dica, mostrar o que e para que serve Mtodos de Classe. Mtodos de Classe Mtodo de Classe como o prprio nome diz, este mtodo no est relacionado instncia da classe e sim a classe puramente dita. A definio do mtodo tambm diferenciada: Type ... TMyClass = Class public Class function MyFunction: Boolean; end; Class function begin end; MyFunction: Boolean;

poder ter acesso ao mesmo. A real funo dos mtodos de classe, poder chamar um mtodo na classe sem ter a necessidade de se criar o objeto classe.

Self
Quando criamos Mtodos de Classe, o identificador Self aponta para a Classe onde o mtodo foi chamado. Pode ser tambm, em uma classe derivada da classe principal.

Onde e como usar


Precisei em meu sistema, mostrar um formulrio MDI como Modal ShowModal, mas, sabido que no posso tornar formulrios MDI Modal. Est limitao, no do Delphi e sim do SO Sistema Operacional. Entre pouqussimas opes que eu possua para esta tarefa, a melhor e a mais elegante sada para o problema, seria utilizar um recurso de POO Programao Orientada a Objetos. Meu formulrio na realidade um formulrio MDIChild e necessitava em determinado momento do sistema, chamar o mesmo como sendo Modal, mas, no posso simplesmente mudar o tipo do formulrio, isto , no posso mudar a propriedade

Mtodos de Classe tem de ser definido como pblico, para voc

MeGAZINE

DELPHI
FormStyle=fsNormal em tempo de desenvolvimento, por que, desta forma, meu formulrio no seria mais Modal, e eu perco a identificao do meu sistema. Veja como eu crio meu formulrio na chamada atravs do Menu: if Form = nil Form := TForm.Create(nil); Form.Show; Ok. Funciona que uma beleza... Atento para o fato que no OnClose do Formulrio Pai existe: Action := caFree; e em cada formulrio filho no evento OnDestroy, eu indico o objeto como sendo nil: Form := nil; Lembrando, o formulrio principal da aplicao MDIForm e meu formulrio pai MDIChild. Vamos ver em ao agora como eu consegui mudar em tempo de execuo sem mexer no tipo do formulrio, para que o mesmo possa se portar como sendo Modal. Vale citar o seguinte: No existe uma tcnica para que eu d um ShowModal em formulrio MDI sem mudar o tipo dele, isto , sem eu colocar: FormStyle := fsNormal; nem to pouco eu tentar mudar no OnCreate do Formulrio o tipo dele, pois, eu no saberei se estou chamando ele do Menu e ou de um boto por exemplo,e ainda, voc ter vrios Access Violation pela frente para tratar. Vamos ao Cdigo do Mtodo de Classe: Type ... TForm = class(TFormPai) private { Private declarations } public { Public declarations } class function ShowModalForm: TModalResult; end; class function TForm.ShowModalForm: TModalResult; Neste artigo, conhecemos o conceito de mtodos de classe, deixando com o uso desses mtodos, suas classes mais organizadas e com o cdigo estruturado. Apenas feito que, voc no pode acessar diretamente variveis da classe, uma vez que os Class Methods agem em cima da classe. Sucesso a todos e at a prxima, Anderson Haertel Rodrigues - AHR. Desenvolvedor/Analista de Sistemas. Consultor especializado em desenvolvimento de Sistemas Client/Server-MultiCamadas. Oferece treinamentos para empresas em: InterBase, SQL-Server, Delphi e COM+ Recuperao de Banco de Dados InterBase. anderson.hr@bol.com.br - anderson.hr@zipmail.com.br. Florianpolis - Santa Catarina - Brasil. end; A chamada do mtodo diferente do que estamos habituados usar, pois, o mtodo est ligado a Classe e no a instancia da classe, conforme j foi dito. Digamos que voc tenha um Boto em outro formulrio para a chamada do formulrio MDIChild, basta colocar a instruo abaixo: procedure TForm1.Button1Click(Sender: TObject); begin TForm.ShowModalForm end; Ok. Conseguimos fazer o que desejamos, com o mnimo de cdigo e de uma forma elegante. begin with TForm.Create(nil) do begin FormStyle := fsNormal; Visible := False; Result := ShowModal; Close; end;

Concluso:

10

MeGAZINE

PALM

Formato do arquivo

PDB
Por: Marcio Alexandroni

Amigos do The Club, o ClubePalm (www.clubepalm.com.br) traz mais um artigo sobre a plataforma Palm, os PDAs mais utilizados no mundo todo. J publicamos aqui vrios artigos sobre informaes de como desenvolver ferramentas de auxlio aos sistemas Palm em Delphi e um dos assuntos mais procurados como o desenvolvedor pode gerar arquivos PDB para enviar ao Palm, pois muitos gostariam de desenvolver sua prpria aplicao, mas no conhecem o formato dos arquivos PDB do Palm. Muito bem, nesta edio o formato dos arquivos PDB ser desvendado! O Palm Database (PDB) o formato padro que o PalmOS utiliza para armazenamento de dados em forma de registros. Neste artigo, explicaremos o modo como so armazenados os dados dentro do PDB, as estruturas internas e os conceitos envolvidos na sua utilizao.

PQA, etc. (Veremos outros formatos em outros artigos). Outro conceito importante a destacar que o formato padro dos Bancos de Dados so detalhados aqui como se fossem uma estrutura seqencial, exatamente como so gravados os arquivos PDB no Desktop, provenientes de um HotSync. Na realidade, a forma como o PalmOS armazena os Bancos de Dados na memria pode variar em funo da quantidade de memria disponvel e verso do Sistema Operacional. Naturalmente, se voc decidir gerar um Arquivo PDB no desktop com a estrutura detalhada aqui e envi-lo ao Palm, ser perfeitamente possvel, pois durante o processo do HotSync, o PalmOS alocar os recursos necessrios para armazenar seu Banco de Dados na memria e torn-lo disponvel para suas aplicaes. Para quem vem de outras plataformas e linguagens de programao, comum tentar associar um Banco de Dados a um arquivo DBF, Paradox, etc. No possvel! O Banco de Dados do Palm no possui conceito de Campos, ndices e Chave Primria (Apesar de existir um Identificador nico do registro). O PDB uma estrutura seqencial de registros que podem ser classificados na hora da insero de um novo registro ou mesmo depois, atravs de uma funo da API do PalmOS. O desenvolvedor responsvel por determinar como os dados sero gravados nos registros, o tamanho de cada registro (porque os registros no precisam ter o mesmo tamanho). S como um exemplo, para classificar um arquivo, necessria uma funo Callback, isto , uma funo provida pelo desenvolvedor, que o PalmOS chama durante uma operao de classificao de registros. Falaremos mais sobre este assunto em outro artigo especfico sobre a Programao voltada a Banco de Dados.

Conceitos

Primeiramente, no devemos confundir os arquivos que so gravados no Desktop, de extenso PDB, com o formato de armazenamento de dados do PalmOS, o Palm Database (PDB). Os arquivos gravados no Desktop tem esta extenso para associlos ao gerenciador de HotSync do Palm, possibilitando a instalao dos Bancos de Dados no Palm e o backup deles depois de um HotSync. No PalmOS no h arquivos e extenses. Todos os dados armazenados so gravados na memria, atravs de formatos especficos para cada tipo de utilizao. At mesmo os programas (PRC, Palm Resource) so Bancos de Dados com um formato especfico. O que determina e diferencia o tipo do Banco de Dados armazenado so as informaes do Header, indicando se aquele Banco de Dados um Banco de Registros, Resource,

MeGAZINE

11

PALM
Estrutura Fsica
O formato PDB composto de blocos com tamanho varivel, exceto o Header que contm sempre 72 bytes. Cada bloco representa um conjunto de informaes dentro do Banco de Dados. Veja o desenho dos blocos abaixo: Tabela I
Header do Banco de Dados (Tamanho Fixo 72 bytes) Lista de Entradas de Registros (Tamanho varivel) AppInfo Block (Opcional, Tamanho Varivel) SortInfo Block (Opcional, Tamanho Varivel) Entradas de Registros (Tamanho Varivel)

Detalhamento dos Blocos Header


No Header, so gravadas informaes que identificam o Banco de Dados no PalmOS e esto detalhadas as localizaes dos blocos de informaes dentro do Banco de Dados. A estrutura apresentada abaixo, detalha cada parte do Header, comeando pela posio 1, como o primeiro byte do Bloco. Tabela II (Abaixo)

Posio

Tamanho

Contedo Nome genrico do Banco de Dados. Exemplo: "Banco_Generico". Os bytes que no forem usados aps o nome devem ser preenchidos com ZERO. Este nome aparece na Lista "Info", de Bancos de Dados Instalados no Palm. Flags do Banco de Dados. 16 Bits contendo detalhes sobre caractersticas do Banco de Dados no PalmOS. 0x0002 Somente para Leitura 0x0004 AppInfoBlock Modificada 0x0008 Se Setado, o HotSync far o Backup do Banco de Dados 0x0010 OK para instalar sobre uma cpia j existente no Palm 0x0020 Fora RESET do Palm aps instalar 0x0040 No permite envio do Banco via Infravermelho (Beaming) Verso do Banco de Dados, informada pelo desenvolvedor Data de Criao do Banco de Dados: Observao sobre dadas no PalmOS: O PalmOS armazena datas computadas em Segundos desde Zero Hora de 01/01/1904. No Windows, a funo time(), retorna Segundos desde Zero Hora de 01/01/1970. Assim, para converter uma data obtida da funo time() da API do Windows para uma Data do PalmOS, acrescente o valor fixo decimal 2082844800 ao valor obtido de time(). Data de Modificao do Banco de Dados. Segue a regra de datas acima. Data do ltimo Backup. Segue a regra de datas acima. Nmero de Modificaes no Banco de Dados. Posio absoluta a partir do incio do Header do Banco de Dados, identificando a localizao do AppInfo Block. Se no houver AppInfo Block no Arquivo, os quatro bytes so preenchidos com Zero. Posio absoluta a partir do incio do Header do Banco de Dados, identificando a localizao do SortInfo Block. Se no houver SortInfo Block no Arquivo, os quatro bytes so preenchidos com Zero. PDB Type. Quatro caracteres identificando o tipo do Banco de Dados. Esta informao mais o Identificador do Criador do Arquivo, a forma mais comum de abrir o Banco de Dados utilizando as funes da API do PalmOS. Creator ID. Identificador nico do criador do Banco de Dados. Se voc pretende criar uma aplicao e distribu-la para outros Palms, altamente recomendado que voc registre um ID nico na Palm, pois ele identificar cada desenvolvedor nesta plataforma. Se voc utilizar qualquer identificao, poder ocorrer conflitos em unidades que utilizem programas de outros desenvolvedores com o mesmo Creator ID. Consulte a pgina www.palmos.com/dev/tech/palmos/creatorid/ Unique ID Seed. Raramente utilizado, serve para armazenar um nmero de identificador nico para o PDB. Somente 3 bytes so utilizados, sendo que o quarto byte serve apenas para alinhamento dos bytes. Normalmente contm Zeros, pois no h documentao disponvel para sua utilizao.

1 a 32

32

33 a 34

35 a 36

37 a 40

41 a 44 45 a 48 49 a 52 53 a 56 57 a 60

4 4 4 4 4

61 a 64

65 a 68

69 a 72

12

MeGAZINE

PALM
Nota: Alguns desenvolvedores citam que o Header do Banco de Dados Palm contm 78 bytes. Isso devido a utilizao de apenas uma Record List por Banco de Dados. Na documentao oficial da Palm, encontra-se detalhada a Record List da maneira que mostramos aqui. Por questo de flexibilidade e porque pode haver mais de uma Record List em um Banco de Dados (raro, mas possvel), detalhamos o Header com 72 bytes que so realmente fixos dentro de um Banco de Dados Palm e detalhamos a estrutura da Record List separadamente. Atributos do Registro Tabela V
Bit 0,1,2,3 4 5 6 7 Significado Identificam a Categoria qual o Registro pertence (Vide AppInfo abaixo sobre Categorias) Registro marcado como Secret (Privado) Registro marcado como Busy (Ocupado pelo Sistema Operacional) Registro marcado como Dirty (Modificado recentemente) Registro marcado como Deleted (Apagado, porm no removido ainda).

Lista de Entradas de Registros (Record List)


A Record List funciona como um ndice seqencial, ou relao de todos os registros gravados no Banco de Dados. Contm entradas informando a Posio Absoluta (em bytes) dos registros a partir do Incio do Header. A primeira entrada corresponde ao primeiro registro do Banco de Dados, e assim por diante. Cada Entrada de Registro tem 8 bytes. Veja o detalhamento abaixo: Tabela III
Posio Tamanho Contedo Posio Absoluta (em bytes) a partir do incio do Header onde comea a prxima Record List (Como dissemos logo acima, raro, porm possvel). Normalmente contm Zeros. Nmero de Entradas de Registros na Record List (Conseqentemente, nmero de registros no Banco de Dados). Observao importante: se o Banco de Dados estiver vazio, as duas prximas posies (7 a 8) devem ser preenchidas com Zeros, indicando final do Banco de Dados.

Dentro do Sistema, podemos comparar os bits atravs de operaes de AND lgico e identificar os atributos do registro. Exemplo: Atributo & 0x10 = Secret Atributo & 0x20 = Busy Atributo & 0x40 = Dirty Atributo & 0x80 = Deleted Atributo & 0xf0 = Todos os atributos setados Atributo = 0 Registro Normal (Sem atributos especiais) Existem constantes que identificam estes valores dentro do PalmOS. Veremos esse assunto quando estivermos falando da API do Banco de Dados. AppInfo Block O AppInfo Block uma rea que pode ser utilizada dentro de um Banco de Dados para guardar qualquer tipo de informao que o desenvolvedor achar necessrio. Por exemplo: como dissemos anteriormente, no formato PDB no h definies de campos, tipos de dados, etc. Para suprir essa dificuldade, comum utilizar o AppInfo Block para gravar infomaes a estrutura de campos. Isso fica a critrio do desenvolvedor, no h nenhuma API do PalmOS para tal finalidade. Outra caracterstica do AppInfo Block que nele gravado o conjunto de Categorias de um Banco de Dados. Categorias (Categories no PalmOS) so classificaes que so aplicadas registros de um Banco de Dados. Cada registro pode ser associado uma Categoria e o PalmOS dispe de rotinas que permitem filtrar a busca de registros por categoria. Um exemplo tpico do uso de Categorias a aplicao Address do Palm. Nesta aplicao, possvel classificar os registros como Business, Personal, QuickList, etc. So permitidas 16 Categorias por Banco

1a4

5a6

Entradas de Registros Tabela IV


Posio Tamanho Contedo Posio Absoluta (em bytes) a partir do incio do Header onde comea o Registro no Banco de Dados. Atributos do Registro (Vide Tabela abaixo).

1a4

MeGAZINE

13

PALM
de Dados, sendo que normalmente a primeira da lista criada com o nome Unfiled, para indicar que o registro no foi classificado em nenhuma categoria (default). Estrutura da Category Data dentro do AppInfo Block Tabela VI
Posio Tamanho Contedo 16 bits indicando qual das 16 categorias foi renomeada. um controle para a aplicao de HotSync que houve mudana nas Categorias. Array de 16 strings terminadas em Zero (NULL terminated), com 16 bytes cada string, representando o nome de cada uma das 16 categorias do Banco de Dados. Se forem classificadas menos do que 16 categorias, deve-se inicializar as outras com Zero. Array de 16 bytes representando o cdigo de identificao de cada Categoria (ID). Normalmente inicializado com valores de 1 a 16. ltimo cdigo de categoria utilizado (ID). Um byte no utilizado (Somente para alinhamento de bytes dentro da estrutura).

aplicao (AppInfo/SortInfo) se houver. Como j dissemos os registros no tem formato, nem padro de gravao, tamanho, etc (so conhecidos como Raw Data). A nica consistncia que a posio absoluta (em bytes) do registro dentro do PDB seja indicada na sua entrada correspondente na Record List.

Consideraes Finais
muito importante ressaltar a maneira como os bytes so armazenados nos processadores Motorola. Para quem costuma escovar bits na plataforma Intel, sabe que os bytes so gravados em ordem inversa, por exemplo: o valor 0x0001 gravado na memria como 01 00. Esta notao chamada de Little Endian pelos desenvolvedores. J no PalmOS o byte mais significativo vem primeiro, por exemplo: o valor 0x0001 gravado como 00 01 na memria. Essa notao chamada de Big Endian. Os desenvolvedores dizem que essa notao foi tirada das histrias de Gulliver, onde as tribos rivais Big Endians e Little Endians brigavam porque divergiam da maneira que deveriam quebrar os ovos. Um lado achava que a maneira correta de quebrar um ovo era pela parte de cima, o outro pela parte de baixo (se que ovo tem parte de cima ou de baixo!?!)... Interessante como isso veio parar aqui, no? Esperamos que este artigo possa contribuir com o desenvolvedor, elucidando alguns pontos importantes dos Bancos de Dados da plataforma PalmOS. At a prxima! Marcio Alexandroni atua no desenvolvimento de sistemas utilizando tecnologias Oracle, Delphi, Linux e Palm. Comeou a trabalhar na plataforma PalmOS no incio de 1999 e hoje utiliza as ferramentas CodeWarrior, Falch.net, NSBasic e PocketStudio. O ClubePalm acaba de lanar o mdulo AVANADO do Curso de Programao para Palm baseado na ferramenta PocketStudio! Veja mais detalhes em: www.clubepalm.com.br/cursopocket2.htm

256

259

16

275

276

O PalmOS dispe de rotinas de inicializao da Category Data em sua API, porm, se o desenvolvedor estiver gerando um arquivo PDB com sua prpria ferramenta, deve estar atento para gerar a estrutura das categorias na ordem correta. Dentro do AppInfo Block, logo aps o bloco de categorias, o desenvolvedor pode colocar os dados especficos de sua aplicao.

SortInfo Block
O SortInfo Block uma rea dentro do PDB destinada a aplicaes especficas do desenvolvedor. No tem formato predefinido, nem tamanho. Sua localizao dada pela posio absoluta dentro do Banco de Dados, atravs do campo especfico no Header do PDB. A maioria das aplicaes no usa o SortInfo Block e algumas publicaes informam que verses antigas do HotSync no suportam o Backup do SortInfo Block do Bancos de Dados.

Prximas Turmas: 02, 03 e 04 / Maio -> quinta, sexta e sbado: Bsico 15, 16 e 17 / Maio -> quarta, quinta e sexta: Avanado 05, 06 e 07 / Junho -> quarta, quinta e sexta: Bsico

Entradas de Registros
Os registros que foram apontados na Record List, so colocados logo aps o ltimo bloco de dados especficos da

14

MeGAZINE

Para anunciar ligue: (0xx14) 3732-3689


Continua na prxima pgina

DELPHI

Monitoramento de ocorrncias no Windows


Ns vamos falar neste artigo sobre uma API do Windows chamada SHChangeNotify. De acordo com o documentos do Windows, esta API informa ao sistema sobre qualquer evento que possa afet-lo. Bem, isso muito bom para o Windows. H muitos eventos interessantes que o sistema fica de olho: modifio de arquivos e diretrios, insero e remoo de mdia, atualizaes de espao livre em disco, etc. Por exemplo, voc provavelmente est familiarizado em ver o Windows Explorer atualizar o cone do drive de CD quando voc insere ou remove um CD. Isso um exemplo de trabalho de notificao. Muito til voc no acha? Mas no seria muito melhor se voc pudesse ter acesso a este trabalho de notificao tambm? At agora, trabalhar neste mecanismo requeria um conhecimento mais profundo. Por alguma razo, a Microsoft decidiu no revelar os mtodos pelos quais o Windows Explorer recebe estas notificaes. Este artigo vai mostrar estas informaes, e fornecer um componente que lhe dar uma vantagem para usar esta tcnica no Delphi. pode ver todas as pastas do sistema. Voc pode tambm ver as pastas que no fazem parte do sistema de arquivos, tal como o painel de controle. Alguns meios eram necessrios para identificar excepcionalmente todos as pastas, se eram parte do sistema de arquivo ou no. A soluo da Microsoft era o PIDL, um pequeno carregador turbo. No uma string simples; particularmente, um ponteiro a uma corrente de estruturas que contm o identificador da informao para uma determinada pasta. Os ndices de um PIDL so pela maior parte escondidos; no foram destinados a exposio ou a manipulao direta. Um aspecto do PIDL que ele deve ser alocado em um modo, e liberado em outro modulo escrito por uma parte diferente. Isto pode ser problemtico a medida que diferentes ambientes de desenvolvimento usem com frequencia diferentes esquemas de alocao de memria. Por exemplo, usando a procedure FreeMem do Delphi para liberar memria originalmente alocada por alguma funo RTL malloc do compilador C terminaria muito provvelmente corrompendo a pilha. Como um resultado, a memria armazenada para conter PIDL deve ser alocada e liberada pelo alocador de tarefa. Isto assegura que a memria do PIDL seja sempre alocada e liberada usando o mesmo esquema, sem levar em considerao o ambiente de desenvolvimento utilizado para o mdulo. Esta funcionalidade foi implementada atravs de uma interface COM chamada IMalloc. Voc pode usar diretamente a interface IMalloc para isto, mas ns temos optado em usar qualquer funo cheater, a qual voc encontraria definida na unit kbsnPIDL nos exemplos incluidos com est matria.

Um breve desvio
Antes de obter estas informaes, voc precisa conhecer um pouco sobre o tipo PItemIDList. Ele um tipo definido na unit ShlObj, e consulta a construo conhecida aos programadores como um PIDL (pronunciado piddle). A natureza do PIDL um tpico amplo, mais do que o bastante para ocupar seu prprio artigo. Para as finalidades de monitoramento, entretanto, uma exposio profunda no ser necessria. Basicamente, um PIDL a verso do caminho do DOS. Se voc olhar a janela do lado esquerdo do Windows Explorer, voc

16

MeGAZINE

DELPHI
A concluso para tudo isto que cada arquivo pode ser representado tambm como um PIDL ou um caminho. Muitas funes, ento, requerem PIDL como parmetros no lugar de paths tradicionais ou retornar o PIDL dentro da funo que voc pode precisar liberar mais tarde. Para o propsito deste artigo, voc pode considerar um PIDL ser um ponteiro que aponta para os dados que deveriam no ser modificados em qualquer caminho. As funes fornecidas na unit kbsnPIDL vo converter um path do arquivo de sistema para um PIDL e vice versa. O nico aspecto pouco comum que voc nunca deveria liberar um PIDL com uma funo usual da VCL, como FreeMem; voc deve usar somente a funo FreePIDL fornecida na unit kbsnPIDL. A chave para receber as notificaes de mudana a funo SHChangeNotifyRegister. function SHChangeNotifyRegister(Window: HWND; Flags: DWORD; EventMask: ULONG; MessageID: UINT; ItemCount: DWORD; var Items: TNotifyRegister): THandle; stdcall; Isto usado para registrar uma janela com o shell, o qual ser ento notificado por todos os eventos subsequentes SHChangeNotify. Isto exportado de SHELL32.DLL. Como muitas funes no documentadas, ela no exportada pelo nome. Ento, ser necessrio link-la usando a funo ordinal. A exportao ordinal para SHChangeNotifyRegister 2. O parmetro Window especifica o controle da janela que deveria receber a notificao da mensagem. Pode ser qualquer janela que voc decidir, mas melhor criar uma janela invisvel de quem s tem responsabilidade de controlar a notificao de mensagens. O parmetro EventMask um bit-mask para todos os eventos que voc est interessado. Voc pode usar qualquer combinao de constantes SHCNE_xxx, o mesmo que ser usado para a funo SHChangeNotify, combinado com uma lgica ou operao. A figura 1 fornece a lista completa destas constantes. O parmetro Flags permite a voc especificar um comportamento opcional para as notificaes. Voc pode filtrar eventos e decidir se usa uma janela proxy sobre o NT. Veja a figura 2 uma lista destes flags. Normalmente, ambos os flags de interrupes devem ser configurados, como voc geralmente no se preocupa sobre a ltima fonte do evento. De qualquer modo, interromper eventos extremamente raro. O flag SHCNF_NO_PROXY permite voc controlar a notificao com mais eficincia no Windows NT, mas ele complica a mensagem controlando o procedimento e requer um conjunto de funes no documentadas. Ns explanaremos toda a situao no NT mais tarde. O parmetro MessageID o identificador da mensagem que ser enviado para aquela janela. recomentado que voc use um valor derivado de WM_USER para o valor de MessageID para previnir conflitos com mensagens do sistema. O parmetro ItemCount especifica o nmero de caminhos que voc deseja monitorar. Normalmente, isto ser 1, mas possvel monitorar muitos caminhos diferentes atravs do parmetro Items. O parmetro Items um ponteiro para um tipo de registro TNotifyRegister. Veja a definio de TNotifyRegister. TNotifyRegister = packed record pidlPath: PItemIDList; bWatchSubtree: BOOL; end; Se o pidlPath mostrado no cdigo acima especificar um PIDL vlido para uma pasta vlida, voc receber um evento que afeta aquela pasta. Se configurar o bWatchSubtree para True, voc receber um evento para toda a pasta especificada, por exemplo, todas as pastas e itens abaixo da pasta especificada alm da prpria pasta. Se voc configurar o pidlPath para nil, voc receber eventos para toda a pasta e itens do sistema. Se o valor do parmetro ItemCount for maior que 1, voc deve fornecer o mesmo nmero de registros TNotifyRegister para o parmetro Items na forma de vetor, um pacote de registros depois outro dentro de um grande buffer suficiente para hosped-los. Se a funo SHChangeNotifyRegister tiver sucesso, o valor de controle um retorno para o objeto de notificao modificado. Voc deveria salvar este controle para utiliz-lo mais tarde. Se a funo falhar o retorno 0 (zero). Quando voc tiver finalizado o monitoramento de eventos, voc deveria passar o controle de notificao do controle retornado por SHChangeNotifyRegister para SHChangeNotifyDeregister. O valor de exportao de SHChangeNotifyDeregister 4, e a declarao da funo a seguinte: function SHChangeNotifyDeregister (Notification: THandle): BOOL; stdcall; O parmetro Notification pega o controle da notificao de

MeGAZINE

17

DELPHI
Figura 1: Lista de constantes.
Constantes associadas com eventos simples SHCNE_ASSOCCHANGED SHCNE_ATTRIBUTES SHCNE_CREATE SHCNE_DELETE SHCNE_DRIVEADD SHCNE_DRIVEADDGUI SHCNE_DRIVEREMOVED SHCNE_EXTENDED_EVENT SHCNE_FREESPACE SHCNE_MEDIAINSERTED SHCNE_MEDIAREMOVED SHCNE_MKDIR SHCNE_NETSHARE SHCNE_NETUNSHARE SHCNE_RENAMEFOLDER SHCNE_RENAMEITEM SHCNE_RMDIR SHCNE_SERVERDISCONNECT SHCNE_UPDATEDIR SHCNE_UPDATEIMAGE SHCNE_UPDATEITEM A file-type association has changed. The attributes of an item or folder have changed. A non-folder item has been created. A non-folder item has been deleted. A drive has been added. A drive has been added via the shell. A drive has been removed. Not currently used. The amount of free space on a drive has changed. Storage media has been inserted into a drive Storage media has been removed from a drive. A folder has been created. A folder on the local computer is being shared via the network. A folder on the local computer is no longer being shared via the network. The name of a folder has changed. The name of a non-folder item has changed. A folder has been removed. The computer has disconnected from a server. The contents of an existing folder changed, but the folder wasn't renamed. An image from the system image list has changed. An existing non-folder item changed, but the item wasn't renamed.

Constants that combine multiple event types SHCNE_ALLEVENTS SHCNE_DISKEVENTS SHCNE_GLOBALEVENT Flag used with event constants SHCNE_INTERRUPT The event occurred as a result of a system interrupt.
Flag SHCNF_ACCEPT_INTERRUPTS Value $0001 $0002 $8000

Specifies a combination of all possible event identifiers. Specifies a combination of all of the disk event identifiers. Specifies a combination of all of the global event identifiers.

Figura 2: Flags SHChangeNotifyRegister

SHCNF_ACCEPT_NON_INTERRUPTS SHCNF_NO_PROXY

18

MeGAZINE

DELPHI
mudana do objeto retornado por uma chamada bem sucedida para SHChangeNotifyRegister. Como voc pode ver, se a funo for bem sucedida, o retorno ser True; mas se ela falhar o retorno ser False. convertidos automaticamente para PIDLs antes de serem emitidos em qualquer lugar. Para tipos SHCNF_PATH e SHCNF_PRINTER, isto parece bastante bvio. Para o tipo SHCNF_DWORD, um PIDL 10-byte falsificado criado, com os dois artigos DWORD imediatamente depois dos dados cb. Ignore os dados cb; no tem nenhuma utilizao nesta situao exceto como um placeholder. Este esquema codificado encapsulado para sua convenincia pelo tipo record TDWORDItemID, como mostrado abaixo: TDWORDItemID = packed record cb: Word; { Ignore } dwItem1: DWORD; dwItem2: DWORD; end; O evento SHCNE_FREESPACE controlado como um caso especial. Quando a movimentao passada dentro como um caminho ou um PIDL, ele ser convertido para um DWORD contido no esquema codificado acima, com movimentaes de A: a Z: mapeando para bits de 0 a 25. Por exemplo, o drive D: mapearia para o bit 3, assim que o valor de dwItem1 teria um valor de 8. Se houver duas movimentaes especificadas para o evento, dois bits estaro ajustados ento no DWORD. O valor do segundo DWORD neste caso parece ser sem sentido.

Pegando a mensagem
Depois do registrar o recebimento do pacote de notificao de mensagens, o pacote enviar estas mensagens de notificao para a janela que voc especificou no parmetro Window da funo SHChangeNotifyRegister. O Delphi no define uma mensagem especial para estas mensagens, portanto simplesmente use o tipo padro TMessage. Este um tipo de registro variante, mas voc deve considerar defini-lo como mostrado aqui: TMessage = record Msg: DWORD; WParam: DWORD; LParam: DWORD; Result: DWORD); end; O MSG do registro TMessage ser configurado para qualquer valor que voc especificou na propriedade MessageID que voc passou para a funo SHChangeNotifyRegister. Use este parmetro para reconhecer a notificao das mensagens, oposto a ordem de diversas mensagens que o Windows enviar para a sua janela. O LParam ser configurado para o ID do evento que ocorreu. Isto ser um dos valores SHCNE_xxx mostrado na figura 1. possvel que mltiplos eventos poderiam estar juntos, assim seria melhor test-lo para a presena de um determinado valor ID, de preferncia ento via uma igualdade de teste usando o operador =. O WParam ser um ponteiro a um registro do tipo TTwoPIDLArray. O nome WParam um estilo C que um anacronismo. agora de fato um 32-bit tipo longo, exatamente como LParam, e assim pode armazenar um ponteiro. Este registro aponta a uma ordem que contm os dois PIDLs associados com o evento, como mostrado aqui: TTwoPIDLArray = packed record PIDL1: PItemIDList; PIDL2: PItemIDList; end; Aqueles que so familiarizados com a funo SHChangeNotify podem querer saber porque voc recebe somente PIDLs das mensagens de notificao de mudana, mesmo que a funo SHChangeNotify aceite tipos de dados PChar e DWORD e tambm PIDLs. A razo que todos os tipos de dados so

Windows NT e Mapa de memria


Isto tudo parece bastante simples, ao menos pelos padres de programao Windows, mas no Windows NT h um pouco de problema. O NT mantm uma cuidadosa separao de memria usada por diferentes processos. Um processo tentando acessar diretamente a memria utilizada por um outro processo mostra uma exceo, a falha geral de proteo. Voc no pode simplesmente emitir uma mensagem a uma janela em um processo diferente, e ainda esperar o ponteiro da estrutura contido nessa mensagem para ser acessvel. Para comear em torno disto, o NT despeja realmente todos os dados relevantes em um arquivo mapeado na memria, que seja acessvel de todo o processo, emite ento um controle do mapa de memria e um processo ID como os parmetros para a mensagem. Para ficar compatvel com Windows 95, algum obviamente tem que extrair a informao desse mapa de memria no outro lado. A maneira que isto trabalha que o NT cria automaticamente uma janela escondida do proxy sempre que voc chama SHChangeNotifyRegister. a janela do proxy que recebe a mensagem de notificao que contm o mapa da memria. Seu controlador de mensagem extrai ento toda a informao, e passa sobre a mensagem correta com os dados previstos a sua janela.

MeGAZINE

19

DELPHI
Naturalmente, isto no exatamente eficiente. Especificando esse flag ao chamar SHChangeNotifyRegister, voc est dizendo ao NT para no criar a janela Proxy, assim o controle do mapa de memria comea passando diretamente a sua janela a mensagem de notificao. Ento voc extrai a informao relevante do mapa de memria. Felizmente, existem duas funes que fazem todo o trabalho para voc: SHChangeNotification_Lock e SHChangeNotification_Unlock. A exportao ordinal de SHChangeNotification_Lock 64 e a funo declarada como mostrada abaixo: function SHChangeNotification_Lock (MemoryMap: THandle; ProcessID: DWORD; var PIDLs: PTwoPIDLArray; var EventID: ULONG): THandle; stdcall; O parmetro MemoryMap um controle para um bloco de memria alocado pelo sistema NT. Este controle ser contido em WParam. O parmetro ProcessID somente sada e pega uma varivel do tipo pointer para um registro do tipo TTwoPIDLArray. Voc pode inicializar a varivel pointer como nil antes de chamar a funo. No aloque um registro atual TTwoPIDLArray. Quando a funo retornar, este ponteiro apontar para um registro TTwoPIDLArray que contm dois PIDLs para a mensagem de notificao, que so normalmente passados via WParam. No tente liberar este ponteiro diretamente. O parmetro EventID apenas de sada e pega uma varivel do tipo ULONG ou Longint se voc preferir. Voc pode inicializar esta varivel com 0 antes de chamar a funo. Quando a funo retornar, esta varivel conter o EventID para esta mensagem, para o qual normalmente passado por LParam. O valor de retorno um controle para o mapa de memria, o qual voc deveria salvar; voc vai precisar disto mais tarde. Quando voc terminar o trabalho com a informao extrada via SHChangeNotification_Lock , voc deveria destravar o mapa de memria assim o NT pode jog-lo fora. Este o propsito da funo SHChangeNotification_Lock. A exportao ordinal do valor de SHChangeNotification_Lock 645, e a declarao da funo a seguinte: function SHChangeNotification_Unlock(Lock: THandle): BOOL; stdcall; O parmetro Lock o controle que voc obteu da chamada da funo SHChangeNotification_Lock . A funo retorna True para sucesso e False para falha. importante notar que estas funes existem somente no Windows NT. Se voc tentar link-las enquanto estiver rodando no Windows 95, voc ter um link invlido. Ento, impossvel usar um mtodo externo do Delphi para ligao, a menos que voc tenha completa certeza que nunca rodar em tudo a menos o NT. Voc deveria usar uma ligao dinmica chamando a funo de GetProcAddress da API do Windows aps testar qual o sistema operacional est rodando. Veja a figura 3 um exemplo de usar isto no NT. var PIDLs: PTwoPIDLArray; EventId: DWORD; Lock: THandle; begin // Se NT, use o mapa de memria para acessar os dados PIDL if (SysUtils.Win32Platform = VER_PLATFORM_WIN32_NT) then begin Lock := SHChangeNotification_Lock(THandle( TheMessage.wParam), DWORD(TheMessage.lParam), PIDLs, EventId); if (Lock <> 0) then try ProcessEvent(EventId, PIDLs); finally SHChangeNotification_Unlock(Lock); end; end else // Se no for NT, acessa o PIDL diretamente. begin EventId := DWORD(TheMessage.lParam); PIDLs := PTwoPIDLArray(TheMessage.wParam); ProcessEvent(EventId , PIDLs); end; end; Figura 3: Exemplo de uso do SHChangeNotification_Lock.

A origem dos eventos


Portanto, agora voc sabe receber todas estas notificaes que esto flutuando ao seu redor, mas quem as est gerando realmente? De acordo com a documentao do Windows, uma aplicao deve usar esta funo (SHChangeNotify) se executar uma ao que possa afetar o shell.

20

MeGAZINE

DELPHI
Felizmente, o shell parece gerar a maioria das notificaes prprias. s vezes, pode ser diretamente responsvel para um evento, em que caso, ele fcil o bastante para que faa a chamada a SHChangeNotify. Entretanto, para as coisas que provavelmente originem em uma outra aplicao, tal como a criao de um arquivo, teria que presumidamente monitorar de algum modo o sistema para gerar o evento. O resultado que estas notificaes podem no ser confiveis e muitas vezes existe um atraso entre o evento e a notificao. Tambm pode decidir-se consolidar um nmero de eventos com um SHCNE_UPDATEDIR genrico no caso de overflow. Em resumo no dependa destas notificaes para aplicaes criticas. A ferramenta de movimentao de disco aparentemente no suporta esta informao. Se voc estiver deletando arquivos em um Recycle Bin, voc no comear um mtodo SHCNE_DELETE, como voc pde esperar. Voc comear realmente um SHCNE_RENAMEITEM. O SHCNE_DELETE vem somente aps voc esvaziar o Recycle Bin. Isto faz sentido se voc pensar sobre ele, porque voc est movendo realmente um arquivo de seu caminho antigo para Recycle Bin, mas no pde ser completamente intuitivo no incio. Alguns eventos podem disparar vrias vezes. Isto parece aplicar-se a maioria de eventos de arquivo. Por exemplo, se voc deletar um arquivo, voc comear provavelmente notificado duas vezes com mensagens idnticas. Esteja preparado para isso.

No acredite em tudo que l.


Um outro problema que a documentao do Windows no est completamente exata em suas descries dos vrios eventos. Seguindo as variaes da documentao que ns observamos depois da execuo real. O SHCNE_ATTRIBUTES necessrio acontecer quando os atributos de um item ou pasta forem modificados. . Entretanto, ns testemunhamos somente um evento SHCNE_ATTRIBUTES que ocorre quando o status da impressora mudou. Modificando os atributos de arquivo e pasta produzem um evento SHCNE_UPDATEITEM. O SHCNE_NETSHARE e SHCNE_NETUNSHARE so necessrios acontecer quando voc compartilha ou no uma pasta. De qualquer forma, no Windows NT, o evento SHCNE_NETUNSHARE nunca ocorre. Voc recebe um evento SHCNE_NETSHARE em ambas as ocasies. No Windows 95 eles aparecem para trabalhar como publicado. O SHCNE_UPDATEIMAGE reivindicado para significar que uma imagem na lista de imagens do sistema mudou. Entretanto, as imagens da lista de imagem do sistema nunca devem mudar. O que o evento significa realmente que algo que se estava usando em um ndice particular do cone na lista da imagem do sistema est usando agora algo mais. Os usos tpicos de SHCNE_UPDATEIMAGE incluem o Recycle Bin que mudam entre vazio e cheio, e o cone associado com drive de CD quando um CD inserido ou removido. Documente os cones, que mudam em conseqncia da mudana de um arquivo associado, no gera um SHCNE_UPDATEIMAGE. Eles produziro um evento SHCNE_ASSOCCHANGED. SHCNE_MEDIAINSERTED e SHCNE_MEDIAREMOVED no so gerados em resposta a introduzir ou a remover disquetes.

O caminho Delphi
Tanto para os detalhes desarrumados exigidos pela API Windows. Vamos projetar um componente que esconder todos estes detalhes daqueles programadores Delphi que tm coisas melhores a se preocupar. Primeiramente, ns definiremos a relao pblica do componente. H duas edies principais com este componente: onde prestar ateno, e o que preste ateno para que. A API fornece a potencialidade para filtrar alguns critrios: o tipo do evento, interrupo ou sem-interrupo, a pasta para prestar ateno nos eventos, e se as pastas secundrias devem tambm ser analisadas. Naturalmente, ns necessitamos tambm de algum meio para desligar isto. Identificar as pastas para prestar ateno o nico aspecto incomun de tudo isto. Como ns mencionamos previamente, nem todas as pastas podem ser identificadas por caminhos de arquivo do sistema. Usar PIDLs para identificar estas pastas pouco prtico para o editor de propriedade em tempo de projeto, entretanto, porque PIDLs so tipos de dados opacos e no podem ser manualmente editados por um programador. A soluo usar duas propriedades. Uma propriedade um tipo enumerado novo, TkbSpecialLocation, que encapsula a lista de constantes de API Windows que correspondem as vrias pastas especiais, por exemplo Painel De Controle. Estas constantes podem ser usadas com a funo SHGetSpecialFolderLocation para obter um PIDL a essa pasta. Ajustando uma propriedade a um destes valores enumerados, as posies especiais podem ser selecionadas sem requerer um programador. Um dos valores de TkbSpecialLocation kbslPath. Ajustar este valor permitir ao programador uma segunda

MeGAZINE

21

DELPHI
propriedade entre em um trajeto especfico do sistema de arquivos para monitorar. Est aqui a lista final de propriedades publicadas: property Active: Boolean property HandledEvents: TkbShellNotifyEventTypes property InterruptOptions TkbInterruptOptions property RootFolder: TkbSpecialLocation property RootPath: TFileName property WatchChildren: Boolean; Cada evento incluir o parmetro do remetente, como sempre, e um valor booleano que identifica se o evento foi gerado por um evento. Alguma reviso da documentao da API revela que ns temos cinco testes padres bsicos de parmetros dos dados: 1. Nenhum parmetro extra. 2. Um DWORD. 3. Um non-nil PIDL, o qual possa representar um path 4. Dois non-nil PIDLs, o qual possa representar um path. 5. Genrico eventos que tem dois PIDLs, tambm possa ser nil. As definies de tipos processuais que representam estas categorias de cinco eventos so mostradas em figura 4. Voc pode observar que os parmetros de PIDL esto representados como tipos ponteiro, melhor que PItemIDList. Isto porque PItemIDList definido na unidade ShlObj, que no est adicionada automaticamente s unidades do formulrio. Isto tem a qualidade irritante de causar erros do compilador quando um evento est atribudo, a menos que a unidade ShlObj esteja adicionada manualmente clusula dos usos da pea da relao do formulrio. TkbShellNotifySimpleEvent = procedure(Sender: TObject; IsInterrupt: Boolean) of object; TkbShellNotifyIndexEvent = procedure(Sender: TObject; Index: LongInt; IsInterrupt: Boolean) of object; TkbShellNotifyGeneralEvent = procedure(Sender: TObject; PIDL: Pointer; Path: TFileName; IsInterrupt: Boolean) of object; TkbShellNotifyRenameEvent = procedure(Sender: TObject; OldPIDL: Pointer; OldPath: TFileName; NewPIDL: Pointer; NewPath: TFileName; IsInterrupt: Boolean) of object; TkbShellNotifyGenericEvent = procedure(Sender: TObject; EventType: TkbShellNotifyEventType; PIDL1: Pointer; PIDL2: Pointer; IsInterrupt: Boolean) of object; Figura 4: Tipo de eventos definidos Decidir-se o que os eventos sero, era razoavelmente simples. Deve haver um componente para cada evento possvel. Alm disso, ns definiremos eventos encapsulando os trs eventos coletivos definidos por Windows API. A lista dos eventos e suas definies so encontradas em figura 5. property OnAnyEvent: TkbShellNotifyGenericEvent property OnDiskEvent: TkbShellNotifyGenericEvent property OnGlobalEvent: TkbShellNotifyGenericEvent property OnAssociationChanged: TkbShellNotifySimpleEvent property OnAttributesChanged: TkbShellNotifyGeneralEvent property OnDriveAdded: TkbShellNotifyGeneralEvent property OnDriveRemoved: TkbShellNotifyGeneralEvent property OnExtendedEvent: TkbShellNotifyGenericEvent property OnFolderCreated: TkbShellNotifyGeneralEvent property OnFolderDeleted: TkbShellNotifyGeneralEvent property OnFolderRenamed: TkbShellNotifyRenameEvent property OnFolderUpdated: TkbShellNotifyGeneralEvent property OnFreespaceChanged: TkbShellNotifyGeneralEvent property OnImageUpdated: TkbShellNotifyIndexEvent property OnItemCreated: TkbShellNotifyGeneralEvent property OnItemDeleted: TkbShellNotifyGeneralEvent property OnItemRenamed: TkbShellNotifyRenameEvent property OnItemUpdated: TkbShellNotifyGeneralEvent property OnMediaInserted: TkbShellNotifyGeneralEvent property OnMediaRemoved: TkbShellNotifyGeneralEvent property OnNetworkDriveAdded: TkbShellNotifyGeneralEvent property OnResourceShared: TkbShellNotifyGeneralEvent property OnResourceUnshared: TkbShellNotifyGeneralEvent property OnServerDisconnected: TkbShellNotifyGeneralEvent Figura 5: Eventos publicados em tempo de design acessvel ter mtodos auxiliares para ajustar a propriedade Active para on e off. Tambm, virtualmente todo o componente que controla dados do sistema necessita de alguma ordem de restaurao. Estes mtodos so mostrados aqui: procedure Activate; procedure Deactivate; procedure Reset; H, naturalmente, muitos detalhes para implementar um

22

MeGAZINE

DELPHI
componente que vo alm das funes do ncleo que o componente encapsula. Porque existem muitas outras referncias excelentes que cobrem os detalhes de executar componentes feitos sob encomenda no Delphi, este artigo no os cobrir. Ao invs disso, concentrar somente naquelas partes da execuo do componente que se relacionam diretamente ao problema especfico de notificaes. A implementao de notificaes gira em torno das chamadas a SHChangeNotifyRegister e a SHChangeNotifyDeregister. Tudo que ns fazemos neste componente ser um suporte para aquelas funes chamadas. Vamos esboar como as propriedades e os mtodos pblicos se relacionam para aquelas funes. A propriedade ligada o mais diretamente s chamadas Active. Ajustar esta propriedade para True far com que SHChangeNotifyRegister seja invocado com os parmetros governados por outras quatro propriedades publicadas. Como voc pode supor, ajustando-o para False far SHChangeNotifyDeregister terminar as notificaes. A mecanica para chamar as funes da API so delegados a dois mtodos, StartWatching e StopWatching, que ser discutido mais tarde. Por enquanto, est aqui um trecho do cdigo do mtodo privado da propriedade, SetActive, que ilustra a lgica no trabalho: // // if // No faz nada se o novo valor for igual ao valor antigo. (NewValue <> Self.FActive) then Se ns ativarmos, inicia o monitoramento if (NewValue) then Self.StartWatching; else // Se ns desativarmos, // finaliza o monitoramento Self.StopWatching; ter atualizado o membro interno dos dados do componente que corresponde a essa propriedade. Em seguida, ns consideramos como controlar as mensagens de notificao, que resultaro da chamada a SHChangeNotifyRegister. Uma janela deve estar disponvel para processar todas as informaes. Como fornecer esta janela? Ns poderamos usar o formulrio principal da aplicao, mas aquele requereria capturar a procedure da janela do formulrio. Parece mais simples gerar nossa prpria janela invisvel, cuja a nica finalidade segurar aquelas mensagens de notificao, e o excesso cujo destino ns temos o controle absoluto. O Delphi VCL fornece pensativamente um par das funes para facilitar este esquema. So AllocateHWnd e DeallocateHWnd, encontrado na unidade dos formulrios. A finalidade do AllocateHWnd gerar um controle a uma janela invisvel, usando um procedimento de manipulao da janela que voc fornece. Exatamente o que ns necessitamos! Agora no construtor do componente, ns podemos pegar e gravar o controle para uma janela que no tem nada melhor a fazer do que gerenciar a mensagem dos cones. Aqui est uma chamada a este mtodo acessvel: Self.FMessageWindow := AllocateHWnd(Self.HandleMessage); Como voc pode ver, a chamada trivial. O que importante o procedimento de controle da mensagem que ns passamos. onde so recebidas as mensagens de notificao, e onde ns temos a oportunidade para os despachar. AllocateHWnd leva um nico argumento TWndMethod, uma procedure que leva um nico argumento do tipo TMessage. A figura 6 mostra o controle de mensagem de nosso componente para lhe dar uma idia. procedure TkbShellNotify.HandleMessage( var TheMessage: TMessage); var PIDLs: PTwoPIDLArray; EventId: DWORD; Lock: THandle; begin { Controla somente a mensagem WM_SHELLNOTIFY . } if (TheMessage.Msg = WM_SHELLNOTIFY) then begin { Se for NT, use a mapeamento de memria para acessar o PIDL. } if SysUtils.Win32Platform=VER_PLATFORM_WIN32_NT then begin Lock := SHChangeNotification_Lock(THandle( TheMessage.wParam),

Outras quatro propriedades (alm do Active) podem substancialmente mudar o modelo de notificao, se forem modificadas. No h nenhuma maneira de atualiz-los quando Active est True, assim necessrio ressetar a notificao se estas propriedades estiverem alteradas quando Active for True. Esta a finalidade do mtodo de restaurao. Chame simplesmente os mtodos confidenciais StopWatching e StartWatching, se o componente estiver ativo. Isto tem efeito de parar as notificaes com SHChangeNotifyDeregister, e de chamar SHChangeNotifyRegister com os valores atuais das propriedades do componente. Os mtodos da propriedade para estas quatro propriedades chamam o mtodo de restaurao aps

MeGAZINE

23

DELPHI
DWORD(TheMessage.lParam), PIDLs, EventId); if (Lock <> 0) then try Self.ProcessEvent(EventId, PIDLs); finally SHChangeNotification_Unlock(Lock); end; end {Se no for NT, acesso o PIDL diretamente} else begin EventId := DWORD(TheMessage.lParam); PIDLs := PTwoPIDLArray(TheMessage.wParam); Self.ProcessEvent(EventID, PIDLs); end; end { if } {Chama a procedure default para qualquer outra mensagem} else TheMessage.Result := DefWindowProc(Self.FMessageWindow, TheMessage.Msg,TheMessage.wParam,TheMessage.lParam); end; Figura 6: Um exemplo do mtodo de controle da mensagem Como ns discutimos antes, ns primeiramente verificamos o identificador de mensagem para verificar se esta mensagem uma mensagem WM_SHELLNOTIFY. Ns ignoramos todos os outros, e os enviamos para o controle padro, porque nenhuma das diversas mensagens que transmitem a cada janela no sistema nos interessam. O WM_SHELLNOTIFY, se voc estiver querendo saber, uma constante que ns definimos, no fornecida pelo Windows. Ajust-lo igual ao WM_USER a coisa a mais fcil a fazer, e perfeitamente segura porque ns usamos esta janela somente para as mensagens de notificao. Uma vez que ns estamos satisfeitos isto de fato uma mensagem de notificao, ns descodificamos o LParam e os valores de WParam para determinar qual evento a mensagem nos est relacionando, e os dados associados de PIDL. Note como ns extramos os dados usando a chamada SHChangeNotification_Lock se o componente estiver rodando no NT. Voc ver tambm que o controle real detalhado da mensagem est delegada a um outro mtodo confidencial, ProcessEvent, para evitar repetir um pedao bastante significativo de cdigo. O mtodo privado ProcessEvent (veja Figura 7) onde ns dividimos os PIDLs fora do registro TTwoPIDLArray, os convertlos para caminhos de arquivo de sistema se possvel, e os despacha ao controlador de evento apropriado. A parte principal deste mtodo uma instruo case que chama o mtodo de manipulao do evento que corresponde ao tipo de evento. Estes mtodos de manipulao de evento so necessrios porque os eventos so freqentemente indeterminados, e chamando estes controladores nil diretamente de nada causariam falhas de exceo. Existe um mtodo semelhante para cada evento publicado que aceita o PIDLs e paths, executa qualquer processo adicional que pode ser exigido para extrair uma informao til, e chama o controlador de evento se ele foi nomeado. procedure TkbShellNotify.ProcessEvent(EventID: DWORD; PIDLs: PTwoPIDLArray); var EventType: TkbShellNotifyEventType; PIDL1: PItemIDList; PIDL2: PItemIDList; Path1: TFileName; Path2: TFileName; IsInterrupt: Boolean; begin PIDL1 := PIDLs.PIDL1; PIDL2 := PIDLs.PIDL2; Path1 := GetPathFromPIDL(PIDL1); Path2 := GetPathFromPIDL(PIDL2); IsInterrupt := Boolean(EventID and SHCNE_INTERRUPT); for EventType := Low(TkbShellNotifyEventType) to High(TkbShellNotifyEventType) do begin if (EventType in [kbsnAnyEvent, kbsnDiskEvent, kbsnGlobalEvent]) then Continue; if ((ShellNotifyEnumToConst(EventType) and EventID) <> 0) then begin Self.AnyEvent(EventType, PIDL1, PIDL2, IsInterrupt); if ((ShellNotifyEnumToConst(kbsnGlobalEvent) and ShellNotifyEnumToConst(EventType)) <> 0) then Self.GlobalEvent(EventType, PIDL1, PIDL2, IsInterrupt); if ((ShellNotifyEnumToConst(kbsnDiskEvent) and ShellNotifyEnumToConst(EventType)) <> 0) then Self.DiskEvent(EventType,PIDL1,PIDL2,IsInterrupt); case (EventType) of kbsnAssociationChanged: Self.AssociationChanged(IsInterrupt);

24

MeGAZINE

DELPHI
kbsnServerDisconnected: Self.ServerDisconnected(PIDL1,Path1,IsInterrupt); end; end; end; end; Figura 8: Um mtodo de evento-processo abreviado. O outro artificio o for loop que iterage atravs dos tipos de eventos possveis, comparando cada um ao parmetro EventID que usa uma comparao para ver se o evento deveria ser disparado. Isto necessrio porque o parmetro de EventID de fato um bitmap de flags, e como tal, poderia incluir mais de um flag de evento. Isto proibe uma comparao de igualdade simples que usa o operador =. 1, NotifyPathData); if (Self.Handle = 0) then Self.Deactivate; end; Figura 9: O mtodo privado StartWatching. Primeiro ns inicializamos os flags. Ns iremos sempre especificar SHCNF_NO_PROXY, porque ns estamos preparados para controlar a mensagem corretamente no NT. Ns tambm iremos configurar os flags SHCNF_ACCEPT_INTERRUPTS e SHCNF_ACCEPT_NON_INTERRUPTS, como determinado pelo valor da propriedade InterruptOption. Depois ns inicializamos o parametro EventMask para especificar os eventos que ns estamos interessados em monitorar. Isto realizado atravs da interao por todos os valores do tipo enumerado TkbShellNotifyEventType e configura o flag correspondente usando um operador lgico or cada vez que ns encontramos um valor, o qual configurado na propriedade HandledEvents. O ltimo parmetro para montar a informao de caminho da pasta. Ns simplesmente preenchemos o TNotifyRegister com os valores achados no RootPIDL e propriedades WatchChildren. Finalmente, ns podemos fazer a chamada a SHChangeNotifyRegister e salvar o controle retornado por aquela funo. O mtodo StopWatching bastante simples atravs de comparao. Ele meramente chama a funo SHChangeNotifyDeregister, dando o controle salvo da chamada a SHChangeNotifyRegister, e reajusta os dados internos que contm o valor de controle para zerar. Aqui est o mtodo inteiro: procedure TkbShellNotify.StopWatching; begin SHChangeNotifyDeregister(Self.FHandle); Self.FHandle := 0; end; O produto final um componente que faz notificaes quase triviais para acesso. V em frente. Experimente com o monitor de eventos fornecido neste artigo.

O ponto principal
Agora, com todas estas tarefas de apoio trabalhadas fora, ns podemos finalmente pegar o ponto principal do assunto - a chamada para SHChangeNotifyRegister. Esta funo encontrada em s um local ao longo do componente inteiro. Este lugar, claro que, o mtodo privado StartWatching. Veja o cdigo mostrado em Figura 9. procedure TkbShellNotify.StartWatching; var NotifyPathData: TNotifyRegister; Flags: DWORD; EventType: TkbShellNotifyEventType; EventMask: DWORD; begin Flags := SHCNF_NO_PROXY; if kbioAcceptInterrupts in Self.InterruptOptions then Flags := Flags or SHCNF_ACCEPT_INTERRUPTS; if kbioAcceptNonInterrupts in Self.InterruptOptions then Flags := Flags or SHCNF_ACCEPT_NON_INTERRUPTS; EventMask := 0; for EventType := Low(TkbShellNotifyEventType) to High(TkbShellNotifyEventType) do if (EventType in Self.HandledEvents) then EventMask := EventMask or ShellNotifyEnumToConst(EventType); NotifyPathData.pidlPath := Self.RootPIDL; NotifyPathData.bWatchSubtree := Self.WatchChildren; Self.FHandle := SHChangeNotifyRegister( Self.FMessageWindow, Flags, EventMask, WM_SHELLNOTIFY,

Consideraes finais
As notificaes lhe do a perspiccia poderosa nos funcionamentos internos do Windows. Suas aplicaes podem usar isto para reagir a todos os tipos de eventos de sistemas importantes, dando a voc aquela margem extra sobre a concorrncia. O componente TkbShellNotify lhe d esta API em um pacote conveniente e simples, fazendo estes servios quase triviais para explorar. Faa o download do cdigo referente a esta matria no endereo www.theclub.com.br/revista/ShellNotify.zip

MeGAZINE

25

DELPHI

O que fazer para.... Trocar de Operador x ECF


Por Claudenir C. Andrade Analista de Sistemas para Automao Comercial e-mail: claudenir@bematech.com.br

Um procedimento muito comum em uma rotina no dia-a-dia de um PDV a troca de operador, seja no fechamento do caixa, na troca de turno ou na entrega de determinada quantia de dinheiro para o controle hora-a-hora dos valores arrecadados pelo pdv. Para isso pode-se aproveitar muitas informaes do ECF, desonerando o software de algumas atividades e controles que j so realizados automaticamente pelo ECF. Um dos dados interessantes que deve ser impresso em um relatrio de troca de operador so: Valor de descontos realizados no turno em questo. Valor dos Acrscimos. Valor dos Cancelamentos. Valor debitado nas sangrias efetuadas no turno em questo. Valor dos suprimentos. Valor e Totalizadores parciais, ou seja, quando foi Vendido em cada alquota. O Cdigo abaixo ser muito til quando solicitado a troca de operador e a impresso em um relatrio gerencial para refletir os valores computados pelo turno ou operador em questo. procedure TForm1.TrocaOperador1Click(Sender: TObject); Var Geral:string; Descontos,Cancelamentos,Acrescimos,Sangria, Suprimento:string;

Contador:integer; begin Operador:= inputbox(Troca de Operador,Entre com o Nome do Novo Operador,); if Operador= then begin exit; end; for Contador := 1 to 2000 do Geral := Geral + ; iRet := Bematech_FI_Descontos(Geral); Geral:=Trim(Geral); Contador:=StrToInt(Pchar(Geral))div 100; Descontos :=IntToStr(Contador); iRet := Bematech_FI_Cancelamentos(Geral); Geral:=Trim(Geral); Contador:=StrToInt(Pchar(Geral))div 100; Cancelamaentos :=IntToStr(Contador); iRet := Bematech_FI_Acrescimos(Geral); Geral:=Trim(Geral); Contador:=StrToInt(Pchar(Geral))div 100; Acrescimos :=IntToStr(Contador); {* Colocamos na varivel Sangria e Suprimento os valores encontrados ao chamar a funo VerificaTotalizadoresParciais, que entre vrios totalizadores devolve o valor

26

MeGAZINE

DELPHI
contabilizado no totalizador Sangria e Suprimento. Observe que j formatamos e pegamos o valor no meio da string retornada na Geral. Nas posies 398 de 14 em 14 dgitos conseguimos os valores de Suprimento e Sangria} for Contador := 1 to 1000 do Geral := Geral + ; iRet := Bematech_FI_VerificaTotalizadoresParciais (Geral); Geral:=Trim(Geral); Contador:=StrToInt((Copy(Geral, 398, 14))) div 100; Sangria:=IntToStr(Contador); Contador:=StrToInt((Copy(Geral, 413, 14))) div 100; Suprimento:=IntToStr(Contador); iRet := Bematech_FI_RelatorioGerencial (=================================+#13+#10); iRet := Bematech_FI_RelatorioGerencial(T R O C A D E O P E R A D O R+#13+#10); iRet := Bematech_FI_RelatorioGerencial (=================================+#13+#10+#13+#10); iRet := Bematech_FI_RelatorioGerencial(Operador: +Operador+#13+#10); iRet := Bematech_FI_RelatorioGerencial(Descontos Realizados: +Descontos+#13+#10); iRet := Bematech_FI_RelatorioGerencial (Suprimentos Realizados: +Suprimento+#13+#10); iRet := Bematech_FI_RelatorioGerencial (Sangria Realizada : +Sangria+#13+#10); iRet := Bematech_FI_RelatorioGerencial(Acrescimos Realizados: +Acrescimos+#13+#10); iRet := Bematech_FI_RelatorioGerencial (Cancelamentos Realizados: +Cancelamentos+#13+#10); iRet := Bematech_FI_RelatorioGerencial (=================================+#13+#10); iRet := Bematech_FI_RelatorioGerencial (=================================+#13+#10+#13+#10); iRet := Bematech_FI_FechaRelatorioGerencial(); end;

MeGAZINE

27

DICAS & TRUQUES

Acessando PDFs via Delphi


O acesso a arquivos PDFs via Delphi possvel a partir da importao de um controle ActiveX instalado pelo prprio Acrobat Reader em sua mquina. Felizmente o Delphi possibilita fazer esta importao de forma bastante prtica, gerando um componente que poder ser utilizado facilmente aps a importao. Vamos a importao: Acesse o menu Components | Import ActiveX Control como mostra a figura 1. Selecione na lista o controle Acrobat Control for ActiveX (Version ?.?) figura 2. Agora clique no boto Install...

Figura 1

Figura 2

28

MeGAZINE

DICAS & TRUQUES


Acesse a aba Into New Package para instalar o componente em um novo pacote, como mostra a figura 3. Clique OK. Clique em Compile e aps em Install Pronto, o componente est instalado! Veja o mesmo na palheta ActiveX do Delphi se voc manteve a palheta Default no momento da importao e tem o nome de TPdf. Para utilizar o componente, insira o TPdf em seu Form e para carregar o arquivo PDF faa o seguinte: procedure TForm1.Button1Click (Sender: TObject); begin Pdf1.LoadFile(C:\Pasta\TheClub.PDF); end; Com isso o documento ser carregado no componente TPdf e o usurio ter todas a funcionalidades oferecidas pelo Acrobat Reader .

Figura 3 acima

Figura 4 abaixo

Delphi, acertar data e hora com o Servidor.


No Windows NT/2000/XP existem APIs especficas para obter a data e hora de um Servidor, porm com Windows 9x no encontramos APIs com o mesmo efeito, porm possvel implementar via um utilitrio DOS e com isso acertar a data e

hora de uma mquina com outra da rede. procedure AcertaHora(ServerName: String); begin WinExec(PChar(net time + ServerName + /set /yes), 0); end;

Delphi, capturar teclas genricamente.


Esta dica mostra como capturar todas a teclas pressionadas na aplicao e tambm combinaes de teclas, como por exemplo CTRL+F5, ALT+P. Neste exemplo utilizamos o evento OnIdle do componente TApplicationEvents... procedure TForm1.ApplicationEvents1Idle(Sender: TObject; var Done: Boolean);

begin if (GetASyncKeyState(VK_CONTROL) <> 0) and (GetASyncKeyState(VK_F5) <> 0) then ShowMessage(Tecla CTRL+F5); if (GetASyncKeyState(VK_MENU) <> 0) and (GetASyncKeyState(Ord(P)) <> 0) then ShowMessage(Tecla ALT+P); Done := True; end;

MeGAZINE

29

DICAS & TRUQUES


Delphi, clonar um registro utilizando TTable.
Neste simples exemplo mostramos como incluir um novo registro contendo as mesmas informaes do registro sobre qual o ponteiro estava posicionado. procedure CopyARecord(tbl: TTable); var I: Integer; tblTmp: TTable; begin tblTmp := TTable.Create(nil); try tblTmp.DatabaseName := tbl.DatabaseName; tblTmp.TableName := tbl.TableName; tblTmp.Open; tblTmp.GotoCurrent(tbl); tbl.Insert; try for I := 0 to tbl.FieldCount-1 do tbl.Fields[I].Assign(tblTmp.Fields[I]); except tbl.Cancel; raise; end; finally tblTmp.Free; end; end; procedure TForm1.BitBtn1Click(Sender: TObject); begin CopyARecord(Table1); end; Do While nextkey() == 0 OL_Yield() EndDo // o cdigo acima o mais indicado para melhorar o processamento. InKey() Clear ? Com este cdigo j melhora bastante, porm menos que o anterior... ? Porm permite utilizar os Inkeys(0). OL_AutoYield( .T. ) InKey( 0 ) Poder baixar a LIB bem e o exemplo de sua utilizao no endereo abaixo: www.theclub.com.br/revista/cpufree.zip

Clipper, rodando em Windows NT/2000/XP


Quando executamos uma aplicao Clipper em qualquer um destes SOs, se formos monitorar a taxa de utilizao da CPU, veremos que ela ficar em 100% freqentemente. Depois de muito pesquisar, encontramos uma LIB que realmente funciona, onde atravs dela trocaremos nossos Inkey(0) por funes da LIB, como por exemplo: Clear ? Monitore agora o processamento da CPU, estar em 100%, depois tecle algo... Inkey( 0 ) Clear ? Consulte o processamento novamente, e veja a diferena... depois tecle algo...

Clipper, retornar a data de um arquivo qualquer.


Nesta dica utilizamos a funo Directory() e aDir() para retornar informaes de um arquivo qualquer... #include Directry.ch clear ? GetFileDate(c:\clipper\ng\ng.exe) Function GetFileDate(cFileName) local aDir, dDate

aDir := Directory (cFileName) if Len (aDir) != 1 dDate := CToD() else dDate := aDir[ 1, F_DATE] endif Return (dDate) * envie suas perguntas e sugestes para * que possamos compartilhar com outros associados

30

MeGAZINE

Você também pode gostar