Boletim Pascal #36
Os exemplos do código fonte desta edição estão disponíveis para download.
![]() |
![]() |
Boletim Pascal #36 - JUNHO-02-2002 ÍNDICE 1. ALGUMAS PALAVRAS DOS EDITORES 2. ASSINATURA DELPHI 3. USANDO ADO 4. USANDO ARQUIVOS DE AJUDA HTML EM SEUS PROGRAMAS 5. ASSEMBLER NATIVO EM DELPHI (I) 6. FÓRUMS 7. DELPHI NA REDE - Sites em português - Componentes, Bibliotecas e Utilidades . Shareware/Comercial . Freeware - Artigos, Dicas e Truques . Kylix - Tutoriais ________________________________________________________________________ 1. ALGUMAS PALAVRAS DOS EDITORES Editorial da Versão em Português ================================ Pessoal, Nessa edição, temos o prazer de apresentar quatro artigos especialmente interessantes. No primeiro, aprenderemos a examinar os recursos de um arquivo executável do Windows. Além dos detalhes apresentados no artigo, que é de ótimo nível, os mais interessados podem estudar o exemplo que vem com o próprio Delphi no diretório Demos/ResXplor. O segundo artigo oferece uma implementação básica de um Query Builder em Delphi usando os componentes ADO. O terceiro artigo apresenta uma solução simples e prática para migrar os arquivos de ajuda de seus projetos do antigo formato Help do Windows para o novo formato Help HTML com o mínimo de impacto para seus projetos. Finalmente o último artigo trata de forma clara e precisa a utilização do assembler no Delphi. Vários aspectos da programação assembler em Delphi são abordados como quadro da pilha, passagem de parâmetros e variáveis locais. A explicação é acompanhada de diversos exemplos esclarecedores. E a Borland, hein? O que vamos fazer com nossos aplicativos que usam o BDE? Vejam mais a respeito no editorial da edição em inglês. Espero que gostem dessa edição. Confesso que desde que começamos a versão em português, esse número é o que me deixou mais entusiasmado. Agora chega de conversa. Divirtam-se com nosso boletim! Demian Lessa demian@knowhow-online.com.br editor da versão em português __________________ Editorial da Versão em Inglês ============================= No Boletim Pascal #34 anunciamos o lançamento da versão em português do nosso boletim. Hoje, estou feliz em anunciar o lançamento da versão russa do boletim, editada por Mike Shkolnik: * Boletim Pascal - Edição Russa http://groups.yahoo.com/group/pascal-newsletter-ru/ Assinar: http://groups.yahoo.com/group/pascal-newsletter-ru/join pascal-newsletter-ru-subscribe@yahoogroups.com Gostaria de agradecer aos autores pelos artigos contribuídos nesse número e premiar S.S.B. Magesh Puvananthiran com uma licença do Greatis Print Suite, um conjunto de componentes para impressão e visualização, fornecida por Greatis Software: http://www.greatis.com/printsuite.htm No próximo número, um de nossos colaboradores será premiado com uma licença do SMImport, uma suite de componentes que permite a conversão de dados entre os formatos mais populares, fornecido por Scalabium: http://www.scalabium.com/smi/index.htm Nós também estamos promovendo uma competição para os dois primeiros artigos sobre Kylix que publicarmos. Os prêmios serão cópias do AnyShape Transpack para Kylix, por MindBlast Software: http://www.mindblastsoftware.com/ Como parte de vocês já deve saber, a Borland tomou uma importante decisão a respeito do futuro do BDE. No fundo, acho que todos nós já esperávamos por isso... O BDE com links SQL (para acesso a dados em servidores SQL) será distribuído com os produtos da Borland apenas até o final deste ano, mas será marcado como "obsoleto", implicando que nenhuma melhoria será realizada no produto. O BDE Local, versão sem os links SQL, continuará sendo distribuído com os produtos da Borland mas será marcado como "congelado", implicando que a Borland continuará distribuindo, testando e oferecendo suporte ao produto, mas nenhuma melhoria será realizada, nenhuma funcionalidade adicional ou correção de erros serão planejadas. Você pode ler mais a respeito no artigo de John Kaster no site Borland Developer Network: http://community.borland.com/article/0,1410,28688,00.html Qual o impacto dessa decisão nos seus projetos? Você continuará usando o BDE para bancos locais, planeja migrá-los para Interbase, usando IBX, ou adotará uma outra solução? E quanto à tecnologia ADO? A escolha dos links SQL continuará sendo uma escolha para novos projetos ou você pretende migrar para DataSnap Direct (também conhecido como dbExpress)? Nós realmente gostaríamos de ouvir seus comentários e planos para o futuro próximo. Ernesto De Spirito pascal-newsletter-owner@yahoogroups.com __________________ Colaboraram nesta edição: Dave Murray e José Manuel Rodríguez. Artigos por José Manuel Rodríguez, S.S.B. Magesh Puvananthiran, Dave Murray e Ernesto De Spirito. ________________________________________________________________________ JfControls Library. Multi-language. Multi-appearance. Skins. Privileges. More than 40 integrated and customizable components. Impressive GUI. Centralised resources administration. Multiple programming problems solved. For Delphi 3-6 and C++ Builder 3-5. http://www.jfactivesoft.com/ ________________________________________________________________________ 2. ASSINATURA DELPHI Por José Manuel Rodriguez (JMR) <jmr@clubdelphi.com> Introdução ========== Não muito tempo atrás, eu pude ver em um dos fóruns do Latium Software uma pergunta sobre como seria possível afirmar se um programa teria sido compilado com o Delphi. Ainda que tivesse havido um certo número de respostas recomendando o uso de aplicativos shareware e comerciais, como o famoso PE Explorer, não houve resposta direta à pergunta. O fato é que existe uma forma de fazer isso, e relativamente simples: desde o Delphi 3, qualquer arquivo: executável GUI, aplicativo de console ou DLL, incluindo controles ActiveX mas não Packages, tem uma assinatura Delphi embutida. Recursos do Windows =================== A maioria dos aplicativos Windows contêm aquilo que chamamos de recursos (resources). Recursos foram introduzidos nas primeiras fases do Windows, dada sua natureza visual gráfica: ainda que seja perfeitamente possível gerar os elementos gráficos inteiramente através de código (exatamente da forma como programas editores de recursos fazem), é uma tarefa dura e complicada. Ao invés disso, desenvolvemos os elementos da interface gráfica visualmente, com ajuda de programas especiais chamados editores de recursos (por exemplo, desenhando uma caixa de diálogo num ambiente gráfico), e então dispomos nos locais adequados os demais elementos da interface como botões, caixas de edição, etc. Quando achamos que nosso desenho da tela está aceitável, o salvamos como um recurso binário e, a partir desse instante, ele está pronto para ser incluído no nosso EXE. Neste artigo, o termo EXE refere-se a qualquer arquivo que esteja no formato PE (Portable Executable) suportado pelo Win32, como EXEs, DLLs, OCXs, etc. Sabendo que alguns desses tipos de recursos são utilizados repetidamente em quase todas as aplicações, definiu-se um conjunto padrão de recursos: Tabela de aceleradores (accelerator table) Bitmap Cursor Caixa de Diálogo Enhanced metafile Fonte Ícone Menu Entrada de tabela de mensagens (message-table entry) Entrada de tabela de literais (string-table entry) Informação de Versão Além desses recursos padrão, existe um outro tipo de recurso: recurso personalizado (custom resource) ou definido pelo usuário (user defined resource). Esses recursos são definidos conforme a necessidade do programador e são constituídos de dados binários que, por vezes, fazem sentido apenas para o programador ou aplicativo mas que, outras vezes, são dados em formatos bem conhecidos mas que não fazem parte do padrão como, por exemplo, arquivos WAV ou JPEG. Voltando ao Delphi, seria de imaginar que cada formulário que criamos no IDE do Delphi seria internamente transformado num recurso padrão do tipo Caixa de Diálogo; entretanto, a verdade é outra. Dada a forma dual de trabalho no IDE (sincronização entre formulário e código), sua forma de interação com os componentes e armazenamento de RTTI, dentre outras, os criadores do Delphi decidiram armazenar cada formulário, juntamente com todos os seus componentes, como um recurso personalizado. Mais que isso, além de incluir bitmaps, ícones, etc, e os recursos personalizados derivados dos formulários, a partir da versão 3.0, o Delphi passou a incluir dois recursos personalizados adicionais: um contendo informações a respeito dos pacotes utilizados e outro que é verdadeiramente uma assinatura do ambiente de programação utilizado. Esse último recurso, específico da Borland, é chamado DVCLAL (Delphi Visual Component Library Access License) e é incluído automaticamente pelo link-editor, sem qualquer intervenção do programador, em todos os programas desenvolvidos com o Delphi. Em minha opinião o termo é confuso já que aplicativos de console que não utilizam a VCL também possuem esse recurso no seu EXE. Recursos Dentro de um Programa ============================== Como dito anteriormente, recursos são dados binários. De fato, são precisamente esses tipos de dados binários que são considerados recursos (.RES) e que podem ser gerados diretamente por um editor de recursos; contudo, existem também recursos em formato ASCII puro (basicamente, .RC, mas também outros como .DLG, etc). Para gerar os recursos na forma .RES a partir de sua forma textual (o fonte), é preciso compilar esse fonte através do uso de um compilador de recursos (Resource Compiler) como BRCC32. O fato importante é que, uma vez inseridos num PE, um recurso não pode mais ser modificado. Isso significa que é possível abrir um PE e analisar todos os seus recursos. Se for do seu desejo, por exemplo, você pode abrir um PE com o auxílio de um editor de recursos e traduzir todos os literais para o idioma de sua preferência, sem precisar do código fonte ou sequer de uma recompilação. A API do Windows oferece uma rica classe de funções que permitem o acesso e a manipulação desses recursos com um mínimo de esforço (algumas dessas rotinas não funcionam no NT) e, como veremos, a RTL e a VCL do Delphi oferecem funções ainda mais simples de se trabalhar. No nosso caso, para determinar se um certo programa foi desenvolvido com o Delphi, precisamos verificar a existência de um recurso chamado DVCLAL no PE e, existindo, verificar que o recurso corresponde, de fato, à assinatura do Delphi. Assim sendo, podemos ficar certos de que o programa foi compilado pelo Delphi. A razão para a existência desses tipos de recurso e suas diferenças, não apenas entre as várias versões, mas até mesmo entre as distribuições Professional e C/S (ou Enterprise) de uma mesma versão não me é claro. Aparentemente, a Borland utiliza esses recursos juntamente com uma série de variáveis e rotinas definidas na unidade SysUtils não apenas para determinar se um programa foi compilado com o Delphi, mas também para evitar o uso fraudulento dos termos da licença e impossibilitar, por exemplo, a compra da versão Professional do Delphi 5 e a utilização da RTL/VCL da versão Enterprise na versão Professional para criar programas cujo desenvolvimento seria possível somente através da compra da versão Enterprise. No Delphi, existem duas variáveis do tipo array definidas em SysUtils: AL1s e AL2s. Um conjunto de procedimentos e funções também estão definidos: AL1 e AL2 (parecem ser utilizados para codificação e decodificação), GDAL e ALR (Get Delphi Access License e Access License Resource) e as funções auxiliares RCS e RPS (provavelmente Resource Client/Server e Resource Professional). Essas rotinas são chamadas de certas partes a cada vez que um módulo Delphi (DLL e pacotes incluídos) é carregado para a memória. Caso você não esteja utilizando a biblioteca correspondente a seu ambiente, que implica uma violação dos direitos de licença, o procedimento ALV (Access License Violation?) é chamado, que então impede a execução do programa. Assim, por exemplo, GDAL é chamada por DBTables.pas (que impede o uso do BDE sem a devida licensa) ou por ScktComp.pas (que impede o desenvolvimento de aplicativos TCP/IP sem a devida versão do Delphi). Ao Trabalho! ============ Primeiramente, temos que abrir o arquivo. Para fazer isso, temos que fazer uma chamada à API LoadLibraryEx. Por que utilizar essa rotina ao invés da verão mais familiar, LoadLibrary? Bem, a função LoadLibrary é utilizada basicamente para carregar uma DLL no espaço de memória do processo e, por esta razão, além de apenas carregar a DLL, a rotina tem que lidar com o mapeamento da DLL no espaço de endereçamento do processo, localizar e resolver os pontos de entrada dessas DLLs, dentre outras tarefas. Como estamos interessados apenas na abertura do PE para leitura, não há necessidade de arcar com a carga adicional imposta pela chamada a LoadLibrary e, portanto, chamar LoadLibraryEx com o parâmetro LOAD_AS_DATAFILE será essencial para evitar aquelas tarefas adicionais, tornando a tarefa mais simples e rápida: hModule := LoadLibraryEx(PChar(cModuleName), 0, LOAD_LIBRARY_AS_DATAFILE); onde hModule é uma variável do tipo THandle. Uma vez estando com o PE aberto e carregado na memória, com um handle para refernciá-lo, o próximo passo é examinar todos os recursos até encontrar os recursos personalizados. Existem identificadores definidos no Windows para todos os tipos de recursos como, por exemplo: RT_BITMAP, RT_STRING, RT_DIALOG, etc. Recursos personalizados são identificados de modo global por RT_RCDATA. Para examinar os diferentes tipos de recursos personalizados, a API do Windows oferece a função EnumResourceTypes. Essa é uma função de enumeração cujo funcionamento pode parecer um tanto estranho ao programador Delphi menos experiente com a API do Windows. O protótipo da função é: function EnumResourceTypes(hModule: HMODULE; lpEnumFunc: Pointer; lParam: Longint): BOOL; stdcall; Os parâmetros esperados são o handle que já conseguimos na chamada a LoadLibraryEx e um ponteiro para uma função de callback. O terceiro parâmetro é qualquer valor de 32 bits que podemos optar por utilizar para fins particulares (ou simplesmente igorar). A pergunta que surge é: o que significa uma função de callback? Curto e grosso, é uma função que, ao invés de ser chamada por um código nosso, é chamada pelo Windows quando apropriado. No caso de uma função de callback para uma API de enumeração, a função de enumeração irá chamar a função de callback para cada item encontrado na enumeração. Tenha cuidado pois, sendo chamada pelo SO, o Windows, e não por código nosso, a função de callback deve seguir a convenção de chamada do Windows e não a do Pascal e, por isso, você deve certificar-se que sua função de callback é declarada como stdcall. Outra questão que pode surgir é: qual o significado de fato do segundo parâmetro, lpEnumFunc? Pode ser qualquer ponteiro? Certamente que não. Deve ser um ponteiro para uma função do tipo apropriado: function EnumResTypeProc(hModule: THandle; szType: PChar; lParam: LongInt): Boolean; stdcall; Para cada tipo de recurso encontrado por EnumResourceTypes, o Windows chama EnumResTypeProc passando o handle do módulo, o tipo do recurso encontrado e o parâmetro opcional. EnumResourceTypes continuará com a enumeração enquanto existirem recursos distintos a serem enumerados e enquanto a função de callback continue retornando true; assim, quando encontrarmos o recurso do tipo RT_RCDATA, devemos retornar false para finalizar a enumeração. É importante que o segundo parâmetro mencionado anteriormente seja um ponteiro do tipo correto de função. Se olharmos EnumResourceTypes no SDK do Windows o que encontramos é: function EnumResourceTypes(hModule: HMODULE; lpEnumFunc: ENUMRESTYPEFUNC; lParam: Longint): BOOL; stdcall; sendo o tipo ENUMRESTYPEFUNC nada mais que um outro nome para o tipo TFarProc que, por sua vez, é apenas um outro nome para Pointer. Como definida, a função espera um ponteiro e, sendo assim, qualquer ponteiro passado será aceito em tempo de compilação; assim sendo, você deve ter bastante cuidado com o tipo de ponteiro passado. Sendo qualquer outro tipo de ponteiro além daquele definido, nenhum erro será reportado em tempo de compilação mas, em tempo de execução, as conseqüências serão qualquer coisa entre terríveis e desastrosas. No Object Pascal, o tipo TEnumResTypeFunc poderia ser definido como: function(hModule: THandle; szType: PChar; lParam: LongInt): Boolean; stdcall; Assim, qualquer função que definisse um parâmetro do TEnumResTypeProc e recebesse qualquer outro tipo geraria um erro em tempo de compilação, evitando erros, em tempo de execução, bem mais difíceis de depurar e de conseqüências potencialmente mais desastrosas. O problema aqui é que EnumResourceTypes é uma função da API do Windows e, sendo assim, foi escrita em C. A única forma de se passar uma função como parâmetro em C é através do uso de ponteiros para funções; esse mecanismo não permite verificação em tempo de compilação, ao contrário do Pascal que, além dos ponteiros para funções, suporta também tipos procedurais bem mais robustos. Em nossa primeira aproximação, nossa função de callback seria algo como: function EnumTypes(hModule: THandle; szType: PChar; lParam: LongInt): Bool; stdcall; begin if szType = RT_RCDATA then ... Result := False; else Result := True; end (*EnumTypes*); Como podemos ver, se o tipo de recurso encontrado não for o tipo que procuramos, RT_RCATA, retornamos True para que a enumeração continue; se for o tipo procurado, fazemos o processamento (código indicado por elipse) e retornamos False sinalizando o término da enumeração. A chamada seria: hModule := LoadLibraryEx(PChar(cModuleName), 0, LOAD_LIBRARY_AS_DATAFILE); if hModule <> 0 then EnumResourceTypes(hModule, @EnumTypes, 0) Note o uso do operador @ para passar o endereço (ponteiro para) da função de callback EnumTypes. Nesse ponto, o esqueleto do programa está praticamente concluído: abrir o arquivo e determinar se existem recursos personalizados. Se houver, devemos verificar se um desses recursos tem o nome DVCLAL. Para fazer isso, o Windows oferece uma outra função de enumeração muito parecida com aquela que acabamos de utilizar mas que, dessa feita, enumera os nomes dos recursos de um tipo específico. Eis a sintaxe dessa função: function EnumResourceNames(hModule: HMODULE; lpType: PChar; lpEnumFunc: Pointer; lParam: Longint): BOOL; stdcall; E o protótipo da função de callback: function EnumResNamesProc(hModule: THandle; szType: PChar; szName: PChar; lParam: LongInt): Bool; stdcall; O funcionamento é análogo ao já visto para os tipos de recursos. Assim, para cada tipo de recurso passado, a função de callback será chamada com cada um dos nomes de recurso daquele tipo até que todos os nomes de recurso tenham sido enumerados ou até que a função de callback retorne False. Como o funcionamento é muito parecido com aquele já visto para a outra enumeração, dispensaremos os detalhes. Assim, nosso programa principal seria algo do tipo: function EnumNames(hModule: THandle; szType: PChar; szName: PChar; lParam: LongInt): Bool; stdcall; begin if szName = 'DVCLAL' then begin Boolean(Pointer(lParam)^) := True; Result := False; exit; end (*if*); Result := True; end (*EnumNames*); function EnumTypes(hModule: THandle; szType: PChar; lParam: LongInt): Bool; stdcall; begin if szType = RT_RCDATA then Result := EnumResourceNames(hModule, szType, @EnumNames, lParam) else Result := True; end (*EnumTypes*); function IsDelphiModule(const cModuleName: String): Boolean; var hModule: THandle; begin Result := False; hModule := LoadLibraryEx(PChar(cModuleName), 0, LOAD_AS_DATAFILE); if GetLastError = 0 then EnumResourceTypes(hModule, @EnumTypes, LongInt(@Result)) else RaiseLastWin32Error; end (*IsDelphiModule*); Como pode ser visto, o programa consiste de um aninhamento de funções em dois níveis. Para cada PE testado, a primeira coisa é carregá-lo através de uma chamada a LoadLibraryEx para obter um handle. Em seguida, chamamos EnumResourceTypes com o handle que então chama nossa função de callback EnumType com o tipo de recurso encontrado. Se o tipo de recurso for RT_RCDATA, chamamos EnumResourceNames a partir da própria função de callback; se o nome do recurso RT_RCDATA passado a EnumNames for DVCLAL, presumimos que nossa busca está terminada e que o arquivo foi realmente criado pelo Delphi; assim, podemos encerrar a enumeração. Na verdade, é preciso ler os DADOS BRUTOS contidos no recurso e garantir que confere com a assinatura do Delphi e não é meramente uma coincidência. Para isso, é preciso saber como acessar um recurso e conhecer a exata estrutura e significado da assinatura Delphi. Acesso a um recurso específico não será abordado nesse artigo, mas em um artigo futuro; quanto a estrutura do DVCLAL, tenho que admitir que ainda não deduzi por completo. Aqui, empregamos um truque (eu chamaria de uma técnica inteligente, mas só porque não tenho uma avó para me elogiar). Se você lembrar bem, havia um parâmetro opcional de 32 bits; sabendo que EnumResourceTypes é chamado a partir de uma função que retorna um valor Boolean, o que devemos passar nesse parâmetro é um ponteiro para esse valor, que seria equivalente a passá-lo por referência (em C, todos os parâmetros são passados por valor de modo que, para simular a passagem por referência é preciso utilizar um ponteiro). Como esse parâmetro é "arrastado" ao longo do aninhamento de chamadas, sempre temos à disposição uma referência ao valor que será retornado pela função principal de forma que, quando um recurso do tipo RT_RCDATA com o nome DVCLAL for encontrado, podemos atribuir o valor de retorno da função principal através de sua referência. Quanto a estrutura binária do DVCLAL, há pouco o que dizer. Determinei empiricamente alguns valores para as distribuições C/S ou Enterprise de algumas versões do Delphi, mas não tive o tempo necessário para decifrar a estrutura, nem encontrei qualquer informação a respeito em lugar algum. Eis os valores que encontrei: Delphi 3.xx Client/Server DVCLAL RCDATA { 'A2 8C DF 98 7B 3C 3A 79 26 71 3F 09 0F 2A 25 17' } Delphi 4.xx, 5.xx & 6.xx Enterprise: DVCLAL RCDATA { '26 3D 4F 38 C2 82 37 B8 F3 24 42 03 17 9B 3A 83' } Um problema adicional que não mencionei é que pelo menos as últimas versões do Borland C++ Builder (versões 4.xx e 5.xx) parecem ter as mesmas assinaturas que seus análogos Delphi, dificultando assim a identificação do PE como sendo criado pelo C++ Builder ou Delphi. Talvez as informações contidas no recurso RT_RCDATA chamado Package Info ofereça informações adicionais para a resolução precisa mas até o momento da publicação deste artigo eu ainda não tinha conseguido resolver esse problema. O Que Vem Agora? ================ Nesse ponto, devemos estar familiarizados com os recursos do Windows e devemos também ter aprendido a examinar qualquer arquivo PE e determinar os recursos ali contidos. Para dizer a verdade, se precisássemos apenas testar a existência de um recurso bem conhecido e acessar seu conteúdo, poderíamos ter omitido as enumerações e atacado diretamente o problema. A API do Windows, através de FindResource e LoadResource, e a VCL, com a classe TResourceStream, facilitam esse trabalho sobremaneira. Contudo, a forma apresentada permite não apenas verificar a existência de uma assinatura Delphi no PE, mas também acessar todos os recursos de um PE. Num artigo futuro, aprenderemos a examinar todos os recursos de um PE e, se forem construídos pelo Delphi, até mesmo acessar os formulários e exibi-los, mesmo sendo recursos personalizados ou padrão. José Manuel Rodriguez (JMR) __________________ NOTA: quaisquer sugestões, correções ou críticas construtivas serão bem-vindas através do e-mail: jmr@clubdelphi.com. Todo o código aqui mencionado é original do autor e está disponível como um aplicativo demo no arquivo zip anexado a esse boletim eletrônico. ________________________________________________________________________ 3. USANDO ADO Por S.S.B. Magesh Puvananthiran <sesbaNOSPAM@hotmail.com> Esse artigo foi preparado para demonstrar como utilizar os componentes ADO disponíveis no Delphi. Escrevi um programa simples utilizando os componentes ADO para recuperar os nomes das fontes de dados (Data Source Names), nomes de tabelas, nomes de campos, nomes de procedimentos, além de uma interface para digitar uma consulta SQL, executá-la e exibir os resultados num grid. O funcionamento do programa: Quando você executa o programa, ele irá recuperar no ODBC todos os nomes das fontes de dados do sistema e exibi-las numa caixa de lista. Se você selecionar uma dessas fontes de dados, você será solicitado a digitar o nome do usuário e a senha para acessar a fonte de dados. Uma vez que tenha digitado esses valores, as tabelas e procedimentos disponíveis através da fonte de dados serão listadas. Se você clicar no nome de uma das tabelas, todos os campos da tabela serão listados. No campo texto, você pode entrar uma consulta SQL e clicar no botão Execute para rodar a consulta e exibir os resultados no grid abaixo. Você também pode salvar a consulta para um arquivo texto se clicar no botão Save. Se você clicar com o botão direito do mouse na caixa de lista dos nomes das fontes de dados, você encontrará a opção Refresh que atualizará os nomes das fontes de dados do ODBC. O código fonte completo do programa está em anexo. Essa é, na verdade, uma versão simplificada de um Query Builder, que pode ser estendido com características adicionais, e que gostaria de compartilhar com vocês. Mesmo havendo inúmeros programas desse tipo disponíveis, eu quis tentar escrever um em Delphi utilizando os componentes ADO; estarei estendendo esse programa com mais funcionalidades. Gostaria de ouvir suas idéias e sugestões para isso. Obrigado. Magesh. ________________________________________________________________________ 4. USANDO ARQUIVOS DE AJUDA HTML EM SEUS PROGRAMAS Por Dave Murray <irongut @ vodafone.net> Você tem pensado em migrar o sistema de ajuda de seus programas do formato WinHelp para o formato HTML Help? A unidade (dmHTMLHelp.pas) em anexo converte as chamadas ao sistema WinHelp para chamadas ao sistema HTML Help, permitindo que você faça a migração com o mínimo de esforço. Este artigo é baseado num artigo que escrevi para o Delphi3000.com: http://www.delphi3000.com/articles/article_2994.asp Salve essa unidade num diretório no seu Library path (Tools|Environment Options|Library|Library Path) e acrescente-a à cláusula uses de seu projeto. As chamadas ao WinHelp agora serão transformadas em chamadas ao HTML Help de forma que você pode utilizar seu novo arquivo de ajuda da mesma forma como antes. Especifique seu arquivo *.chm em Project Options|Application|Help, nas configurações de arquivo. A ajuda sensível a contexto continuará funcionando exatamente como antes. Você também pode utilizar o método TApplication.HelpCommand para enviar comandos de ajuda. Application.HelpCommand(HELP_KEY, DWORD(keyData)); NOTA: * Essa unidade associa um manipulador ao evento Application.OnHelp. NÃO associe seu próprio manipulador de evento ao Application.OnHelp. * Essa unidade ignora a propriedade HelpFile de qualquer formulário. (Delphi 4+) ________________________________________________________________________ 5. ASSEMBLER NATIVO EM DELPHI (I) Por Ernesto De Spirito <eds2004 @ latiumsoftware.com> Este artigo irá introduzir os conceitos de assembler em linha (inline assembler) no Delphi. O artigo dará uma noção básica do assunto mas não pretende oferecer, em hipótese alguma, detalhes da programação assembler que, por si só, precisariam de um livro inteiro ou mais... Por que e Quando ================ Se você der uma olhada no código fonte da RTL e da VCL, você encontrará declarações assembler inline em vários pontos. Por que a Borland optou por escrever partes do código da RTL e da VCL em assembler? A resposta é bem simples: para alcançar velocidade na execução. Nós sabemos que o compilador produz código rápido mas um compilador jamais será tão bom quanto um programador assembler profissional. Agora, se o assembler é tão bom, por que não foi utilizado em toda a RTL e VCL? A resposta é igualmente simples: porque na programação de mais alto nível, é mais fácil codificar, depurar, ler e manter o código, de modo que o sacrifício em velocidade fica compensado pelas conveniências decorrentes. Isso ajuda a explicar quando o assembler deve ser utilizado. Para ser curto, além do acesso ao sistema em baixo nível, o assembler inline deve ser utilizado quando a diferença na velocidade de execução justifica o trabalho adicional da codificação em assembler. Por exemplo, na unidade Math.pas, há muito assembler, basicamente para chamadas de sistema em baixo nível (para acesso às funções do coprocessador); em System.pas, SysUtils.pas e Classes.pas há também diversos blocos em assembler, desta vez para priorizar velocidade; no é estranho já que essas podem ser consideradas as unidades centrais da RTL e VCL. Em geral, procedimentos e funções que tendem a ser chamadas de forma repetida por um programa devem ser altamente otimizadas, mas codificação em assembler deve ser evitada tanto quanto possível. Se desejamos ganhos em velocidade, antes de optar por assembler devemos otimizar o algoritmo propriamente dito; depois, otimizamos o código Pascal. Se optarmos por assembler, o código Pascal otimizado pode servir como documentação e pode ser utilizado como "código de contigência" no caso de problemas com a manutenção do código assembler. Os Registradores da CPU ======================= Os registradores da CPU são como variáveis predefinidas residindo na CPU e, por vezes, têm tarefas especiais. Eles não têm tipo e podem ser vistos como inteiros de 32 bits com ou sem sinal ou como ponteiros, dependendo da situação. Como estão na própria CPU, é muito mais rápido acessar valores contidos nos registradores do que na memória, fazendo dos registros ideais para fazer cache de valores. Como variáveis, os registradores também possuem nomes. Os nomes daqueles que usaremos são EAX, EBX, ECX, EDX, ESI, EDI, EBP e ESP. Cada registrador tem uma particularidade que o distingue dos demais: - Para algumas instruções, a CPU foi otimizada para utilizar o registrador EAX (também conhecido como acumulador) ou ao menos os opcodes são menores. EAX é usado nas multiplicações e as divisões, intructions de string, instruções de I/O, instruções de ajuste ASCII e decimal, e em algumas instruções especiais (como CDQ, LAHF, SAHF e XLAT). - EBX é um registrador de uso geral, e é usado implicitamente por XLAT. - ECX (também conhecido como contador) tem emprego especial nas instruções LOOP, de rotação e deslocamento de bits e de manipulação de literais. - EDX é utilizado para armazenar os 32 bits mais altos do resultado de uma multiplicação ou os os 32 bits mais altos do dividendo e do resto de uma divisão. - ESI e EDI (conhecidos como índice de origem (source index) e índice de destino ("destination index") respectivamente) são como ponteiros utilizados em instruções envolvendo strings. - EBP (conhecido como ponteiro base) é normalmente usado para endereçar valores na pilha (parâmetros e variáveis locais). - ESP (conhecido como ponteiro da pilha) é utilizado para controlar a pilha. É alterado automaticamente por instruções como PUSH, POP, CALL e RET. Os registradores EBX, ESI, EDI, EBP e ESP devem ser preservados, o que significa que antes de usá-los, devemos salvar seus valores em algum lugar (normalmente na pilha ou outro registradores) e, quando terminarmos de usá-los, devemos restaurar seus valores originais (essas operações implicam no uso de instruções e perda de algum tempo) de modo que o uso desses registradores será feito somente quando justificável ou quando houver uma necessidade inevitável. Provavelmente você percebeu que os nomes dos registradores iniciam com a letra "E". O "E" representa "Extended", estendido. Nos tempos do Intel 80286, os registradores tinham 16 bits e eram chamados AX, BX, CX, etc. Esses registradores ainda existem e são exatamente os 16 bits menos significativos dos registradores EAX, EBX, ECX, etc., respectivamente. A propósito disso, os registradores AX, BX, CX e DX são divididos em dois registradores de 8 bits. AL, BL, CL e DL são os bytes menos significativos de AX, BX, CX e DX respectivamente, enquanto AH, BH, CH e DH são os bytes mais significativos de AX, BX, CX e DX respectivamente. Por exemplo, se o valor de EAX é $7AFD503C, então o valor de AX é $503C, o valor de AH é $50 e o valor de AL é $3C: 7A FD 50 3C AH AL /----/ AX /------------/ EAX Se, na situação acima, armazenarmos o valor $99 em AH, então EAX passaria a ter o valor $7AFD993C. Existe um registrador especial, o registrador de indicadores (flags), que armazena indicadores binários alterados por instruções matemáticas e lógicas ou explicitamente por código, e que são normalmente usados em instruções de desvio condicional. O indicador carry também é usado em algumas instruções de rotação e o indicador de direção é utilizado em instruções envolvendo literais. Esse registrador não é acessível por nome como os demais registradores; mas pode ser copiado e restaurado através da pilha, utilizando PUSHF e POPF respectivamente, e pode também ser copiado e restaurado parcialmente através do registrador AH, utilizando LAHF e SAHF respectivamente. Instruções Assembler ==================== Instruções assembler são dispostas em blocos asm..end blocks e têm a seguinte forma: [identificador:] [prefixo] opcode [operando1 [, operando2 [, ...]]] Onde opcode é o nome da instrução como MOV, ADD, PUSH, etc. Instruções podem ser separadas por ponto e vírgula, quebras de linhas ou comentários. A propósito, comentários são no formato do Object Pascal, isto é, o ponto e vírgula não é considerado o início de um comentário até o final da linha, como no assembler tradicional. A seguir, um exemplo de bloco asm..end com vários dos possíveis tipos de instruções e separadores de comentários: asm xchg ebx, edx; add eax, [ebx]; {ponto e vírgula separa declaração} // quebra de linha separa declaração mov ebx, p sub eax, [ebx] (*comentário separa declaração*) mov ebx, edx end; A convenção é utilizar quebras d elinhas para separação: asm xchg ebx, edx add eax, [ebx] mov ebx, p sub eax, [ebx] mov ebx, edx end; No código da VCL, você verá que os opcodes e nomes de registradores são escritos em maiúsculas e que instruções são indentadas em uma tabulação (normalmente equivalente a oito caracteres), mas utilizaremos outra convenção neste artigo. Blocos asm..end podem ocorrer em qualquer ponto do código fonte onde uma declaração Pascal ordinária puder aparecer; além disso, é possível termos rotinas 100% assembler se, ao invés de "begin", utilizarmos "asm": procedure teste; asm // declarações assembler end; Note que as duas implementações abaixo não são equivalentes: function f(parâmetros): tipo; begin asm // declarações assembler end; end; function f(parâmetros): tipo; asm // declarações assembler end; A razão disso é que o compilador realiza certas otimizações quando implementamos rotinas inteiramente em assembler, sem utilizar um bloco begin..end. As etiquetas devem ser declaradas em uma seção Label, como em qualquer código Object Pascal, a menos que foram prefixadas por "@@": function ENumeroMagico(x: integer): boolean; asm cmp eax, NumeroMagico je @@Bingo xor eax, eax ret @@Bingo: mov eax, 1 end; As etiquetas prefixadas por "@@" são locais ao bloco asm..end em que são usadas. Isto gerará um erro da compilaçao: begin .... asm .... @@destino: .... end; .... asm .... jnz @@destino // Error .... end; .... end; Para corrigi-lo, necessitamos usar uma etiqueta convencional, local ao procedimento ou à função: label destino; begin .... asm .... destino: .... end; .... asm .... jnz destino // Correto .... end; .... end; Operandos ========= Certas vezes, um ou mais operandos são implícitos. Por exemplo, a instrução CDQ (Converta Dword para Qword) parece não utilizar operando algum; entretanto, essa instrução utiliza EDX e EAX: o bit mais alto de EAX, o bit de sinal, é copiado para EDX de forma que, EDX:EAX passa a representar o inteiro em EAX convertido para Int64, onde EAX carrega os 32 bits menos significativos e EDX os 32 bits mais significativos. Para a maioria das instruções, os operandos são registradores. Por exemplo: mov eax, ecx copia o valor de ECX para EAX. Operandos podem conter valores imediatos: mov eax, 5 mov eax, 2 + 3 // expressão constante, resolvida na compilação mov al, 'A' // o código ASCII de 'A' é $41 (65) mov eax, 'ABC' // equivalente a MOV EAX, $00414243 Operandos também podem conter referências de memória: mov [ebx], eax // EBX^ := EAX; Referências de memória aparecem de várias formas: mov eax, [$000FFFC] // Endereço absoluto mov eax, [ebx] // Registrador mov eax, [ebp-12] // Registrador mais/menos deslocamento // constante mov eax, [ebp+ebx] // Registrador mais deslocamento em registro mov eax, [ebp+ebx+8] // Registrador mais deslocamento em registro // mais/menos deslocamento constante mov eax, [ebp+ebx*4] // Registrador mais deslocamento em registro // multiplicado por constante mov eax, [ebp+ebx*4+8] // Registrador mais deslocamento em registro // multiplicado por constante, mais/menos // deslocamento constante Os identificadores usuais do Pascal são traduzidos para uma das formas: mov eax, parâmetro // mov eax, [ebp + deslocamento_constante] mov eax, varlocal // mov eax, [ebp - deslocamento_constante] mov eax, varglobal // mov eax, [endereço_absoulto] call procname // chama endereço absoluto Primeiro Exemplo ================ Agora que estamos prontos para aprender alguns opcodes, vamos aos exemplos. Podemos começar com uma função simples: function f(x: integer; y: integer): integer; // f(x,y) = (-x-y+5)*7 { begin Result := (-x - y + 5) * 7; end; } asm // os parâmetros são passados em EAX (x) e EDX (y); neg eax // EAX := -EAX; // EAX = -x sub eax, edx // EAX := EAX - EDX; // EAX = -x-y add eax, 5 // EAX := EAX + 5; // EAX = -x-y+5 imul 7 // EAX := EAX * 7; // EAX = (-x-y+5)*7 end; Os três primeiros parâmetros (da esquerda para a direita) são passados em EAX, EDX e ECX. Para métodos, o primeiro parâmetro é Self (passado em EAX) e o primeiro parâmetro explicitamente declarado é, de fato, o segundo parâmetro (passado em EDX) e o segundo parâmetro explícito é de fato o terceiro parâmetro (passado em ECX). O valor de retorno deve ser armazenado em EAX para valores ordinais de 32 bits (AX e AL devem ser utilizados para retornar valores de 16 e 8 bits respectivamente). Os comentários explicam os opcodes de forma clara mas, para IMUL, temos que acrescentar duas explicações: * IMUL considera os operandos (EAX e 7 no exemplo) como inteiros com sinal (devemos utilizar MUL quando os operandos não possuírem sinal). * O resultado da multiplicação é um inteiro de 64 bits sendo que os 32 bits mais significativos do resultado são armazenados em EDX. Multiplicações são relativamente caras em termos de tempo de CPU e, por vezes, é mais fácil substitui-las por deslocamentos de bits (quando a multiplicação ou divisão operarem com potências de dois), somas e subtrações. Por exemplo: a * 7 = a * (8 - 1) = a * 8 - a = a * 2^3 - a a * 7 = a shl 3 - a Ao invés de IMUL 7, podemos fazer o seguinte: mov ecx, eax // ECX := EAX; // ECX = -x-y+5 shl eax, 3 // EAX := EAX shl 3; // EAX = (-x-y+5)*8 sub eax, ecx // EAX := EAX - ECX; // EAX = (-x-y+5)*8 - (-x-y+5) // EAX = (-x-y+5)*7 Vejamos outro exemplo: function resto(x: integer; y: integer): integer; // Retorna o resto de x dividido por y { begin Result := x mod y; end; } asm // os parâmetros são passados em EAX (x) e EDX (y); mov ecx, edx // ECX := EDX; // EDX = y cdq // EDX:EAX := Int64(EAX); // EAX = x idiv ecx // divisão inteira com sinal em 32 bits: // EAX := Int64(EDX:EAX) div integer(ECX); // EDX := Int64(EDX:EAX) mod integer(ECX); mov eax, edx // Result := EDX; // resto end; A Pilha ======= Quando um programa é carregado, ele receve uma pilha, que é uma região de memória utilizada como uma estrutura LIFO, "Last In, First Out" (último a chegar, primeiro a sair), controlada pelo registrador ESP que aponta para o topo dessa pilha. ESP inicia apontando para o final da região de modo que, cada vez que empilhamos um novo valor de 32 bits, o registrador ESP é decrementado em 4 (bytes) e o valor é armazenado no local apontado por ESP. | | +-----------+ | | +-----------+ | $01234567 | <- ESP +-----------+ | | PUSH $89ABCDEF // SUB ESP,4; MOV [ESP],$89ABCDEF | | +-----------+ | $89ABCDEF | <- ESP +-----------+ | $01234567 | +-----------+ | | De forma análoga, quando retiramos um valor de 32 bits da pilha, o valor é recuperado do local apontado por ESP e ESP é incrementado em 4 (bytes). POP EAX // MOV EAX,[ESP]; ADD ESP,4 | | +-----------+ +-----------+ | $89ABCDEF | EAX | $89ABCDEF | +-----------+ +-----------+ | $01234567 | <- ESP +-----------+ | | A pilha é utilizada para armazenar endereços de retorno de rotinas, parâmetros, variáveis locais e resultados intermediários. No exemplo a seguir, utilizamos a pilha para salvar o valor de um registrador para uso posterior: function IntDiv(x: integer; y: integer; r: pinteger = NIL): integer; // Retorna o quociente inteiro x / y e o resto em r { begin Result := x div y; if r <> NIL then r^ := x mod y; end; } asm // os parâmetros são passados em EAX (x), EDX (y) e ECX (r) push ecx // Salve ECX (r) para uso posterior mov ecx, edx // ECX := EDX; // ECX = y cdq // EDX:EAX := Int64(EAX); // EAX = x idiv ecx // divisão inteira com sinal em 32 bits: // EAX := Int64(EDX:EAX) div integer(ECX); // EDX := Int64(EDX:EAX) mod integer(ECX); pop ecx // Restaura ECX (ECX := r) cmp ecx, 0 // if ECX = NIL then jz @@end // goto @@end; mov [ecx], edx // ECX^ := EDX; // resto @@end: // identificador local (precedido por "@@") end; Note que, para cada PUSH que executamos, temos que executar um POP correspondente de modo que ESP fique inalterado (ESP é um dos registradores que temos que preservar). A instrução CMP subtrai o segundo operador do primeiro (ECX-0 nesse caso), como a instrução SUB, mas o resultado não é armazenado em lugar algum, ainda que o indicador de Zero (Zero flag) seja marcado (ligado) ou limpo (desligado) dependendo do resultado ser zero ou não, como em qualquer instrução lógica ou matemática (com a exceção de certos casos). Podemos então tirar vantagem desse fato e, ao invés de escrevermos cmp ecx, 0 podemos escrever or ecx, ecx // ECX := ECX or ECX; O resultado de ECX Or ECX é o próprio ECX; portanto, o valor armazenado em ECX é o mesmo de antes, e como dissemos anteriormente o indicador de Zero será marcado se o resultado for zero (isto é, se ECX era zero). A instrução JZ, "Jump if Zero" (Desvie se Zero), desvia (salta) para o identificador indicado como operando se o valor do indicador de Zero estiver marcado (ligado) ou continua normalmente com o fluxo de execução se o indicador de Zero estiver desmarcado (desligado). Passando Parâmetros para a Pilha -------------------------------- Voltemos para a pilha. Dissemos que os três primeiros parâmetros de uma rotina são passados em EAX, EDX e ECX; mas, o que acontece quando temos mais de três parâmetros? Parâmetros adicionais são passados na pilha, da esquerda para a direita, de forma que o último parâmetro será sempre o primeiro da pilha. Suponha que temos a seguinte função function Soma(a, b, c, d, e: integer): integer; begin Result := a + b + c + d + e; end; e queremos fazer a chamada Sum(1,2,3,4,5); Em assembler, faríamos da seguinte forma: mov eax, 1 mov edx, 2 mov ecx, 3 push 4 push 5 call Sum A instrução CALL empilha o endereço de retorno na pilha e salta para (inicia a execução) da função. A instrução RET (RETorna) gerada pelo compilador quando o final de uma função é alcançado desempilha esse endereço da pilha e salta para ele para continuar a execução a partir desse ponto. Note que quando empilhamos parâmetros na pilha mas não os desempilhamos. Isso acontece pois limpar a pilha é responsabilidade da função chamada e não da função que chama (exceto na convenção de chamada CDECL). Para limpar os parâmetros, a instrução RET é utilizada com um operando que indica o número de bytes que ESP deve ser incrementado (8 nesse caso já que ESP foi decrementado em 4 bytes para cada parâmetro empilhado). O compilador fica encarregado dessa tarefa portanto não temos com que nos preocupar; mas, se você utilizar a janela de depuração da CPU e encontrar uma instrução RET $08, agora você já sabe do que se trata. Na entrada para Soma, a pilha estaria, em teoria, da seguinte forma: | | +-----------+ | Ret_Addr | <- ESP +-----------+ | $00000005 | (parâmetro e) +-----------+ | $00000004 | (parâmetro d) +-----------+ | | Quando uma função tem parâmetros na pilha (ou variáveis locais), o compilador gera algumas instruções chamadas de "stack frame", quadro da pilha. Na entrada da função (em "asm"), EBP é empilhado de modo a ser preservado e ESP é atribuído a ele; e, antes de deixar a função, (em "end"), o valor original de EBP é desempilhado: function Soma(a, b, c, d, e: integer): integer; asm // push ebp; mov ebp, esp; .... end; // pop ebp; ret 8; Assim, quando entramos em Soma, a pilha estaria de fato da seguinte forma: | | +-----------+ | Orig. EBP | <- EBP, ESP +-----------+ | Ret_Addr | +-----------+ | $00000005 | <- EBP+8 (parâmetro e) +-----------+ | $00000004 | <- EBP+12 (parâmetro d) +-----------+ | | Em [EBP] encontramos o valor original de EBP que foi empilhado para ser preservado quando da construção do quadro de pilha; em [EBP+4] encontramos o endereço de retorno da rotina; em [EBP+8] encontramos o último parâmetro (o último parâmetro é empilhado por último e, por isso, é o primeiro da pilha). O parâmetro seguinte (da direita para a esquerda) fica em [EBP+12], e assim por diante se houvesse outros parâmetros. Agora vamos escrever a rotina Soma em assembler: function Soma(a, b, c, d, e: integer): integer; { begin Result := a + b + c + d + e; end; } asm add eax, b add eax, c add eax, d add eax, e end; Note que no bloco asm..end nós utilizamos "b", "c", "d" e "e" ao invés de "EDX", "ECX", "[EBP+12]" e "[EBP+8]" respectivamente. Nós podemos fazer assim já que o compilador fará as substituições adequadas. Variáveis Locais na Pilha ------------------------- Se nossa função assembler inline tiver variáveis locais, o compilador criará espaço para essas variáveis na pilha, movendo o ponteiro da pilha de modo que o quadro da pilha para uma função com duas variáveis locais inteiras seria: push ebp mov ebp, esp sub esp, 8 // Desloca ESP como se empilhássemos 8 bytes ... add esp, 8 // Desloca ESP como se desempilhássemos 8 bytes pop ebp Para o propósito do exemplo, aqui vai uma variação da rotina Soma acima, utilizando duas variáveis locais: function SomaL(a, b, c, d, e: integer): integer; var f, g: integer; { begin f := b + c; g := d + e; Result := a + f + g; end; } asm // push ebp; mov ebp, esp; sub esp, 8; add edx, ecx mov f, edx // b + c mov edx, d add edx, e mov g, edx // d + e add eax, f add eax, g end; // add esp, 8; pop ebp; ret 8 Nessa função, a pilha teria o seguinte aspecto: | | +-----------+ | var. g | <- EBP-8, ESP +-----------+ | var. f | <- EBP-4 +-----------+ | Orig. EBP | <- EBP +-----------+ | Ret_Addr | +-----------+ | Param e | <- EBP+8 +-----------+ | Param d | <- EBP+12 +-----------+ | | O Que Vem Agora? ================ Na continuação deste artigo, aprenderemos mais instruções e veremos como passar e retornar outros tipos de parâmetros, como trabalhar com arrays, como acessar campos de registros e objetos, como chamar métodos e mais. ________________________________________________________________________ 6. FÓRUMS Delphi (em Português) ===================== Participe da lista de discussão do Grupo Delphi-BR e faça parte da mais profissional lista Delphi do Brasil. Essa lista tem como objetivo a troca de informações entre os diversos programadores Delphi em lingua portuguesa. Aqui você encontrará grandes programadores brasileiros dando suas contribuições para a comunidade e mantendo uma via de comunicação entre todos os programadores Delphi brasileiros. http://br.groups.yahoo.com/group/delphi-br/ Se você quer juntar-se ao grupo, a melhor forma é assinar a partir da web, uma vez que pode acessar as funcionalidades especiais disponíveis no site web (um ID Yahoo! é necessário; você pode obter um gratuitamente registrando-se como um usuário Yahoo!) mas, se você não quer registrar-se ou se não possui acesso Internet completo, você também pode assinar por email: http://br.groups.yahoo.com/group/delphi-br/join delphi-br-subscribe@yahoogrupos.com.br Delphi (em Inglês) ================== Se você sabe bastante Delphi mas está longe de ser um guru, esse fórum é para você. Esse é o único fórum para programadores Delphi em nível intermediário na Web (hackers Delphi também são bem-vindos :-)). O fórum conta atualmente com mais de 700 membros e, em abril último, teve um tráfego de pouco mais de 450 mensagens: http://groups.yahoo.com/group/delphi-en Se você quer juntar-se ao grupo, a melhor forma é assinar a partir da web, uma vez que pode acessar as funcionalidades especiais disponíveis no site web (um ID Yahoo! é necessário; você pode obter um gratuitamente registrando-se como um usuário Yahoo!) mas, se você não quer registrar-se ou se não possui acesso Internet completo, você também pode assinar por email: http://groups.yahoo.com/group/delphi-en/join delphi-en-subscribe@yahoogroups.com Componentes (em Inglês) ======================= Esse é um fórum para pesquisa/recomendação de componentes de software (componetes VCL e CLX, objetos ActiveX, DLLs, SOs, etc.), assim como utilitários, tutoriais, informações, etc. O fórum é novo e tem cerca de 160 membros e tráfego muito baixo: http://groups.yahoo.com/group/components Conto com sua participação no fórum para nos ajudar a crescer. Você pode assinar pela web ou, mais facilmente, por e-mail: http://groups.yahoo.com/group/components/join components-subscribe@yahoogroups.com Desenvolvedores de Software (em Inglês) ======================================= Esse é um fórum para discussões sobre o desenvolvimento de software e para a troca de experiências de trabalho em ambientes profissionais e comerciais. Esse não é um fórum sobre programação; os assuntos abordados são mais gerais e independentes de linguagem de programação. O fórum é novo e tem cerca de 160 membros e tráfego muito baixo: http://groups.yahoo.com/group/software-developers Conto com sua participação no fórum para nos ajudar a crescer. Você pode assinar pela web ou, mais facilmente, por e-mail: http://groups.yahoo.com/group/software-developers/join software-developers-subscribe@yahoogroups.com ________________________________________________________________________ 7. DELPHI NA REDE Por Dave Murray <irongut @ vodafone.net> Sites em português ================== * Comunidade Delphi de Rio Preto Portal com componentes, novidades, artigos, links e mais. http://www.delphirp.com.br/ * Planet Delphi Site brasileiro especializado em componentes para Delphi. Download grátis. http://www.fprass.hpg.ig.com.br/ * Delphi Company Site do Fernando Gonçalves dedicado ao mundo Delphi http://www.delphicompany.hpg.ig.com.br/ * IntereSite Tudo sobre Delphi http://www.ulbrajp.com.br/~tecnobyte/ * Advanced Developers Delphi, productos, novidades, consultoria... http://www.adev.com.br * Fórum Delphi-BR http://br.groups.yahoo.com/group/delphi-br/ * Fórum Delphi !! http://www.qualyinf.com.br/forum/delphi/delphi.html Componentes, Bibliotecas e Utilitários ====================================== Shareware/Comercial ------------------- * llPDFLib v1.1 - by llionsoft, Shareware ($70, $280 with source) llPDFLib is pure Object Pascal library for creating PDF documents. Does not use any DLL and external third-party software to generate PDF files. Library consists of TPDFDocument component with properties and methods like Delphi's TPrinter but designed to generate a PDF file. http://www.llion.net/ * TPasScript v6.52 - Alexander Baranovsky, Shareware($80) (DELPHI/KYLIX) An interpreter of the Object Pascal language which supports all Object Pascal data types except interfaces. The TPasScript component allows you to embed the interpreter into your Delphi application, so you can extend and customize the application without having to recompile it. Using TPasScript you can: write and run scripts, call script-defined routines, call routines in a dll, import Delphi-defined classes, routines and variables. http://users.ints.net/virtlabor * MaxSpace - by Zecos Software, Shareware ($15) MaxSpace makes using Delphi and C++ Builder more comfortable It turns the IDE ToolBar and ObjectInspector into autohide toolbars, giving you unbelievable freedom for program editing and form designing. http://www.zecos.com/maxspc Freeware -------- * TRealSpinEdit v1.1 - Igor Popov, FREEWARE with source (DELPHI/KYLIX) Based on Visual C++ TSpinEdit, for all who need Value to be a float type. Now with negative value support. http://igp.dax.ru * FastReport CLX v2.46 - A Tzyganenko, FREEWARE w source (DELPHI/KYLIX) The first powerful cross-platform report generator for Delphi + Kylix. Create highly efficient cross-platform reports for with a minimum of coding. Development environment includes: Visual Report Designer, Visual Dialog Designer, Object Inspector, and Component Palette. http://www.fast-report.com * DBDateTimePicker - by Stefano Carfagna, FREEWARE with source Database aware DateTimePicker component for "DateTime" fields. http://www.data-ware.it * LIBXML libxml2 v2.4.21 - by Delphree, FREEWARE w source (DELPHI/KYLIX) Pascal units accessing the popular XML API from Daniel Veillard (http://www.xmlsoft.org). Usable from Kylix and Delphi and hopefully also from other Pascal compilers like FreePascal. http://sourceforge.net/projects/libxml2-pas/ * LIBXML libxslt v1.0.17 - by Delphree, FREEWARE w source (DELPHI/KYLIX) Pascal units accessing the popular XML API from Daniel Veillard (http://www.xmlsoft.org). Usable from Kylix and Delphi and hopefully also from other Pascal compilers like FreePascal. http://sourceforge.net/projects/libxml2-pas/ * Key Objects Library v1.27 - by Delphree, FREEWARE with source Based on experience aquired on eXtreme Class Library project. Main purpose is to create smaller programs using Delphi environment. http://bonanzas.rinet.ru/ * DARTH: C-to-Pascal header converter - by JEDI, FREEWARE with source Source compiles into a tool that parses C headers and generates Delphi source for Windows API calls. Artigos, Dicas e Truques ======================== * The Future of the Borland Database Engine (BDE) and SQL Links The Borland RAD Team reveals plans for future database access in Delphi and C++Builder. You need to read this if you haven't already! http://community.borland.com/article/0,1410,28688,00.html * Top Picks: Reporting Tools - by Zarko Gajic Easily create complex reports that are linked directly into your EXE. Most of the tools from this list provide all the means for you to develop reports including a report engine, designer, previewer, etc. http://delphi.about.com/library/toppicks/aatpreporting.htm * GDI Graphics in Delphi - by Alistair Keys From simple lines to direct API calls: the ultimate tutorial to GDI graphics in Delphi. Look for: drawing lines and shapes, flicker-free drawings, off-screen bitmaps, GDI drawings the API way... http://delphi.about.com/library/bluc/text/uc052102a.htm * Choosing the best Help Format for your project - by Meredith Little No developer wants to work on documentation but it is a necessary evil. This article explores the concept of developing help and describes the available help formats. http://builder.com.com/article.jhtml?id=u00220020429lit01.htm * Choose the right Tool for creating Online Help - by Meredith Little Creating online help is often seen as a burden, but many tools are available to simplify the process. Here's a look at some choices. http://builder.com.com/article.jhtml?id=u00220020430lit01.htm * Functional vs. Design in documentation - by William T. Kelly Do you need a design or functional specification? It depends on who your audience is and where you are in the product development cycle. http://builder.com.com/article.jhtml?id=u00420020503WTK01.htm * How to get the text of a StatusBar? http://www.swissdelphicenter.ch/en/showcode.php?id=935 * How to make a polygon hole on a form? http://www.swissdelphicenter.ch/en/showcode.php?id=995 * How to get the associated icon of a file shortcut? http://www.swissdelphicenter.ch/en/showcode.php?id=1108 * How to list all Subdirectories of a Directory? http://www.swissdelphicenter.ch/en/showcode.php?id=1125 * How to get the Windows Version? http://www.swissdelphicenter.ch/en/showcode.php?id=1126 * How to color text in a TRichEdit? http://www.swissdelphicenter.ch/en/showcode.php?id=1129 * How to use the IP Address Control in a Form? http://www.swissdelphicenter.ch/en/showcode.php?id=1132 * How to display the exported Dll functions? http://www.swissdelphicenter.ch/en/showcode.php?id=1133 * How to display the 'Choose Computer' dialog? http://www.swissdelphicenter.ch/en/showcode.php?id=1135 * How to use steganography? http://www.swissdelphicenter.ch/en/showcode.php?id=1139 * How to resolve environment variables? http://www.swissdelphicenter.ch/en/showcode.php?id=1140 * How to determine, if a Edit field has password characters? http://www.swissdelphicenter.ch/en/showcode.php?id=1141 * How to determine the user's logon domain? http://www.swissdelphicenter.ch/en/showcode.php?id=1142 * How to highlight HTML-Tags in TRichEdit? http://www.swissdelphicenter.ch/en/showcode.php?id=1143 * How to store more than 64 KB in a TRichEdit? http://www.swissdelphicenter.ch/en/showcode.php?id=1144 * How to select a TreeView node with the right mouse button? http://www.swissdelphicenter.ch/en/showcode.php?id=1145 * How to assign an event handler to all components? http://www.swissdelphicenter.ch/en/showcode.php?id=1148 * How to crack a URL into its component parts? http://www.swissdelphicenter.ch/en/showcode.php?id=1149 * How to delete the 'Temporary Internet Files'? http://www.swissdelphicenter.ch/en/showcode.php?id=1150 * How to get the windows file type? http://www.swissdelphicenter.ch/en/showcode.php?id=1153 * How to get the grayscale from a RGB color? http://www.swissdelphicenter.ch/en/showcode.php?id=1154 * How to convert a partition/file size to a String? http://www.swissdelphicenter.ch/en/showcode.php?id=1155 * How to detect the default smtp mailserver? http://www.swissdelphicenter.ch/en/showcode.php?id=1156 * How to implement Forward/Back/Cancel buttons in TWebbrowser? http://www.swissdelphicenter.ch/en/showcode.php?id=1158 * How to format Seconds as (hh:mm:ss)? http://www.swissdelphicenter.ch/en/showcode.php?id=1163 * Catch debug information of an application - by Tommy Andersen Ever wanted to read an application's debug information? http://www.delphi3000.com/articles/article_3216.asp * Hide application in Windows 2000 - by Eber Irigoyen Hiding your application from the taskbar and "Applications". http://www.delphi3000.com/articles/article_3220.asp * Retrieve email addresses from Outlook mails - by Alain Godinas-Andrien http://www.delphi3000.com/articles/article_3222.asp * Maping / Unmaping virtual drives - by Eber Irigoyen Two functions that let you create Virtual Drives for commonly used folders (local or network folders) so they appear on "My Computer" as a new drive for quick access. Like DOS SUBST command. http://www.delphi3000.com/articles/article_3224.asp * What Custom Compiler messages can do for you - by Yoav Abrahami Create reminders that generate compiler warnings and errors. http://www.delphi3000.com/articles/article_3228.asp * How do you subclassing a versatile TList? - by Max Kleiner You can use a TList almost for everything, so an own class leads to better design and maintainability so this article shows how and why. http://www.delphi3000.com/articles/article_3229.asp * Modifying Contents of the Taskbar from Delphi - by Igor Kurilov Using ITaskbarList interface. http://www.delphi3000.com/articles/article_3230.asp * Easy Parsing an XML File - by Max Kleiner How do you get the elements from an XML file? Using MS XML DOM parser. http://www.delphi3000.com/articles/article_3231.asp * Using Autohint - by David Knight Using hints without the flybys that cover data and often annoy users. http://www.delphi3000.com/articles/article_3234.asp * Function DBGridToHtmlTable - by Zswang Wangjihu http://www.delphi3000.com/articles/article_3236.asp * Loading resources from DLL files - by Martin Strand http://www.delphi3000.com/articles/article_3238.asp * Getting System Power Information - by Magnus Flysjö Reteriving battery information for notebooks. http://www.delphi3000.com/articles/article_3241.asp * Is font "X" installed? - by Eber Irigoyen http://www.delphi3000.com/articles/article_3242.asp * Get the application associated to an extension - by Eber Irigoyen http://www.delphi3000.com/articles/article_3243.asp * DLL in Dephi to be called from Visual Basic - by Khaled Shagrouni Creating a DLL in Dephi to be called from another language like VB. http://www.delphi3000.com/articles/article_3244.asp * Get the Number of Print Jobs - by Andreas Schmidt Get the number of jobs in the windows spooler for a specific printer. http://www.delphi3000.com/articles/article_3247.asp * MySQL without the commonly required components - by Me Me MySQL the easy way without BDE or ODBC. http://www.delphi3000.com/articles/article_3248.asp * Remove horizontal and/or vertical scrollbar of TDBGrid - G Christophe Get rid of those pesky scrollbars on TDBGrid when you don't need them. http://www.delphi3000.com/articles/article_3254.asp Tutoriais ========= * Kylix Tutorial Series - by Brian Long Ten part tutorial series previously published in Linux Format. http://www.blong.com/articles.htm#KylixTut * Remedial XML: Say HELLO to DOM - by Lamont Adams Get acquainted with W3C's Document Object Model (DOM) in this part of the remedial XML series. A language-neutral look at how you can put this model to work. http://builder.com.com/article.jhtml?id=u00220020522adm01.htm * A Beginner's Guide to Delphi Programming - by Zarko Gajic FREE online Delphi programing course for beginners, now up to Part 3. http://delphi.about.com/library/weekly/aa031202a.htm Outros Links ============ * VCL Scanner 2002 Sweepstakes winners - by Anders Ohlsson Thanks to all who participated in the VCL Scanner 2002 project! http://community.borland.com/article/0,1410,28665,00.html ________________________________________________________________________ VOCÊ PODE NOS AJUDAR Nós precisamos de sua ajuda para manter esse boletim ativo e cada vez maior. Você pode ajudar indicando o boletim a seus amigos e colegas: http://www.latiumsoftware.com/br/pascal/index.php Você também pode votar para nós em um ou todos esses rankings para dar maior visibilidade a nosso site e assim aumentar o número de assinantes do boletim: http://www.sandbrooksoftware.com/cgi-bin/TopSite2/rankem.cgi?id=latium http://news.optimax.com/delphi/links/links.exe/click?id=70C517ECAE6E http://www.programmingpages.com/?r=latiumsoftwarecomenpascal http://www.top219.org/cgi-bin/vote.cgi?delphi&83 http://top100borland.com/in.php?who=20 http://top200.jazarsoft.com/delphi/rank.php3?id=latium http://213.65.224.200/cgi-bin/toplist.cgi/hits?Id=80 São alguns segundos para você que REALMENTE significam muito para nós. Não esqueça que também precisamos de artigos para os boletins e que existe um prêmio para um dos autores em cada número (em inglês). Todos os artigos serão considerados mas nós estamos particularmente interessados em artigos sobre Kylix já que existe pouco material disponível online. * Envie seu artigo em inglês para pascal-newsletter-owner@yahoogroups.com * Envie seu artigo em português para boletim-pascal-owner@yahoogrupos.com.br ________________________________________________________________________ Se você não recebeu o código fonte completo dos exemplos neste número, você pode obtê-los em http://www.latiumsoftware.com/br/pascal/p0036.zip ________________________________________________________________________ Esse boletim é fornecido "COMO ESTÁ" sem garantias de qualquer tipo. Seu uso implica na aceitação dos termos de licença e isenção de garantia que podem ser lidos em http://www.latiumsoftware.com/br/pascal/index.php Os artigos são propriedade e copyright de seus respectivos autores e foram reproduzidos aqui com sua permissão. Você pode redistribuir esse boletim desde que na sua íntegra (incluindo notas de propriedade e copyright), sem alterações e de forma gratuita. ________________________________________________________________________ Página do grupo:.....: http://br.groups.yahoo.com/group/boletim-pascal/ Assinar..............: boletim-pascal-subscribe@yahoogrupos.com.br Cancelar assinatura..: boletim-pascal-unsubscribe@yahoogrupos.com.br Assinar/cancelar.....: http://groups.yahoo.com/group/boletim-pascal/join Problemas com sua assinatura? boletim-pascal-owner@yahoogrupos.com.br ________________________________________________________________________ Boletim Pascal http://www.latiumsoftware.com/br/pascal/index.php Copyright (c) 2002 por Ernesto De Spirito. Todos os direitos reservados. ________________________________________________________________________ |
Os exemplos do código fonte desta edição estão disponíveis para download.
![]() |
Erros? Omissões? Comentários? Por favor contate-nos!






