Guia de aplicação Delphi de exploração detalhada-CodeSite
Embora o Delphi nos forneça funções de depuração extremamente poderosas, encontrar bugs ainda é uma tarefa árdua. Geralmente, o tempo que gastamos escrevendo e depurando código é praticamente o mesmo, e pode até ser mais. Para reduzir o desperdício desnecessário de tempo e energia, às vezes ainda precisamos da ajuda de ferramentas profissionais de depuração para melhorar a eficiência do bloqueio de bugs. Neste artigo apresentaremos a famosa ferramenta de depuração CodeSite PRo 2.0 (ela ganhou o segundo lugar no Delphi Informant Readers' Choice Award de 2000 como Melhor Ferramenta de Depuração). Seu site oficial é www.raize.com. A principal função do CodeSite é permitir que os desenvolvedores usem código para enviar detalhes de tempo de execução a receptores especiais para análise posterior. Mais precisamente através da classe TCodeSite implementada pelo CodeSite, podemos empacotar e enviar informações de tempo de execução para o CodeSite Dispatcher (distribuidor de mensagens do CodeSite), que pode encaminhar essas mensagens para um ou mais receptores para visualização. O receptor de mensagem padrão é CodeSite Viewer. A eficiência do CodeSite se reflete no fato de ser diferente de uma simples caixa de diálogo que exibe mensagens ou configura pontos de interrupção para verificar variáveis. É mais parecido com a função de log de eventos (Event Log) que vem com o Delphi. é sem dúvida mais poderoso que o Event Log. São muitos e suas mensagens são sustentáveis, ou seja, podem ser salvas, o que facilita a análise retrospectiva. Antes de apresentar o uso específico do CodeSite, vamos primeiro dar uma olhada em seus três componentes. Objeto CodeSite Como mencionado anteriormente, o envio de mensagens CodeSite de um aplicativo em execução é realizado usando uma instância da classe TCodeSite (definida na unidade CSIntf). Podemos simplesmente chamar o método da classe TCodeSite. Expedidor. Por exemplo, você pode usar o método SendMsg do objeto para enviar uma mensagem de string simples. O objeto TCodeSite implementa um grande número de métodos para suportar vários tipos de envio de informações sem qualquer conversão de dados. Por exemplo, o método SendObject do objeto possui dois parâmetros: um é a string da mensagem e o outro é uma referência à instância do objeto. . Este método obterá o objeto Todos os atributos publicados e, em seguida, empacotará as informações desses atributos em mensagens CodeSite. CodeSite Dispatcher Na maioria dos casos, o CodeSite Dispatcher será executado silenciosamente na área da bandeja do sistema. Sua única função é rotear mensagens CodeSite enviadas de vários objetos TCodeSite para seus destinos. Por padrão, as mensagens do CodeSite são enviadas para o CodeSite Viewer. Nem precisamos iniciar o CodeSite Dispatcher porque ele será iniciado automaticamente por objetos como TCodeSite. A classe TCodeSite define uma propriedade DestinationDetails que permite aos desenvolvedores configurar como as mensagens enviadas do CodeSite são roteadas pelo CodeSite Dispatcher para diferentes destinos, como arquivos de log. Mas geralmente não há necessidade de modificar esta propriedade. CodeSite Viewer Embora o CodeSite suporte o envio de mensagens para diferentes destinos, na maioria dos casos o CodeSite Viewer é o principal destino de envio. Mesmo quando enviado para outros destinos, como arquivos de log ou outra máquina, o CodeSite Viewer ainda é a principal ferramenta para visualizar e analisar mensagens. CodeSite Viewer consiste nos seguintes quatro painéis: lista de mensagens, visualizador de mensagens, pilha de chamadas e painel Scratch. A principal área de trabalho do CodeSite Viewer é a lista de mensagens, que é usada para exibir todas as mensagens enviadas ao Viewer ou mensagens carregadas de arquivos de log. Os visualizadores de mensagens são usados para visualizar informações adicionais associadas às mensagens. Por exemplo, se a mensagem atual for enviada pelo método SendObject, o visualizador de mensagens exibirá os valores atuais de todas as propriedades publicadas do objeto. O painel da pilha de chamadas exibe uma visualização da pilha com base nas mensagens csmEnterMethod. Painéis de rascunho são usados para exibir informações não sustentáveis. O painel Scratch é muito útil quando queremos rastrear certas informações, mas não queremos registrá-las no log de mensagens, como quando queremos visualizar um grande número de mensagens repetidas, como a posição atual do mouse. Neste momento podemos usar o método WritePoint do objeto TCodeSite e especificar o parâmetro Line ID para especificar o número de linhas do painel de rascunho usadas para acomodar as informações do mouse. Vamos usar um exemplo simples para demonstrar como enviar uma mensagem para CodeSite Viewer a partir do programa: (1) Crie um novo projeto e depois mude o painel de componentes para a página CodeSite (CodeSite instalará dois componentes no sistema após a instalação TCSGlobalObject e TCSObject). Selecione o componente TCSGlobalObject e coloque-o no formulário. O componente TCSGlobalObject fornece interação em tempo de design com o objeto TCodeSite global (o TCodeSite global é inicializado na unidade CSInft). (2) Adicione um botão e escreva o seguinte código em seu evento OnClick: //CodeSite é o objeto TCodeSite global CodeSite.SendMsg('CodeSite's first message'); Clique no botão após a execução e o CodeSite Dispatcher e o CodeSite Viewer serão executados. Ao mesmo tempo, você verá as mensagens enviadas pelo programa na lista de mensagens do CodeSite Viewer (nota: não precisamos iniciar o CodeSite Dispatcher e o CodeSite Viewer antes de executar o programa, pois o objeto TCodeSite irá iniciá-los automaticamente quando ele precisa enviar mensagens). Os resultados da execução são mostrados na Figura 4.38 abaixo:
(4) Em seguida, pare o programa e adicione o seguinte código no processo de manipulação de eventos OnClick: CodeSite.SendObject('Form1', Form1); (5) Recompile e execute o programa, clique no botão novamente, desta vez você estará; no CodeSite Viewer vi duas mensagens. A mensagem correspondente ao Form1 inclui as informações do objeto do Form1. (6) Para visualizar as informações do objeto associado do Form1, selecione o comando de menu CodeSite Viewer View|Inspector para exibir um novo painel no lado direito da lista de mensagens, no qual são exibidos os atributos publicados do Form1, conforme mostrado em Figura 4.39 abaixo:
(7) Pare o programa novamente e modifique o código no processo OnClick da seguinte forma: CodeSite.EnterMethod('Button1Click'); ;CodeSite .ExitMethod('Button1Click' ); (8) Desta vez ao executarmos o programa e clicarmos no botão, veremos que as mensagens “Primeira mensagem do CodeSite” e “Form1” estão recuadas entre as mensagens “Button1Click”, conforme mostrado na Figura 4.40 abaixo:
Ao adicionar chamadas aos métodos EnterMethod e ExitMethod, podemos gerar um log para registrar quando os métodos são chamados. Depois de examinar os exemplos, descobriremos que a função do CodeSite é muito poderosa. Podemos gerar informações muito detalhadas simplesmente adicionando algumas instruções ao programa e exibi-las em gráficos vívidos por meio do CodeSite Viewer. A seguir, vamos falar sobre a tecnologia avançada de aplicativos do CodeSite. Enviando mensagens para arquivos de log Todo programa terá mais ou menos bugs. Se isso não acontecer neste momento, acontecerá naquele momento. Se não acontecer em pouco tempo, pode acontecer depois de muito tempo. Às vezes isso acontece repetidamente, e às vezes acontece muito acidentalmente. Se uma pessoa lhe disser que os programas que ela escreve funcionam sem problemas a qualquer momento, ela está mentindo. É justamente pela natureza acidental e oculta dos bugs que muitas vezes é difícil para nós repetir os bugs enviados pelos usuários, o que cria um enorme obstáculo para depurarmos o programa e encontrar a causa do problema, e o CodeSite pode enviar mensagens para registrar arquivos. Isso torna mais fácil para os usuários relatarem bugs, pois eles só precisam enviar o arquivo de informações gerado durante o tempo de execução. Da mesma forma, nosso trabalho de depuração do programa se tornará mais fácil. Podemos usar o CodeSite Viewer para analisar intuitivamente a causa e a localização do erro. Para alterar o destino do envio da mensagem, podemos fazer isso definindo a propriedade DestinationDetails do objeto TCodeSite. Este recurso requer que o CodeSite Dispatcher seja instalado na máquina do cliente, que é uma parte distribuível gratuitamente do CodeSite. O processo específico abaixo ainda é baseado no exemplo mencionado anteriormente: (1) Adicione o seguinte código ao evento OnCreate do formulário: CodeSite.DestinationDetails := 'File[Path=C:/FirstLog.csl]' (2 ); compilar e executar o programa. Desta vez, após clicarmos no botão, a mensagem não será mais enviada para o CodeSite Viewer, mas para o arquivo FirstLog.csl na unidade C. (3) Use o CodeSite Viewer para carregar o arquivo FirstLog.csl Desta vez, visualizamos as mensagens CodeSite salvas como antes. (4) Se quisermos enviar mensagens para o CodeSite Viewer e arquivos de log ao mesmo tempo, basta modificar o código anterior para: CodeSite.DestinationDetails := 'Viewer,File[Path=C:/FirstLog.csl]'; Dados customizados Embora a classe TCodeSite forneça um grande número de métodos para processar diferentes tipos de dados, às vezes podemos precisar enviar informações de dados em um determinado formato personalizado. Para tanto, a classe TCodeSite define o método SendCustomData, que suporta o envio de qualquer tipo de dados e formata os dados de acordo com um formatador customizado para que o CodeSite Viewer possa exibir os dados corretamente. Primeiro precisamos criar uma subclasse do objeto TCSFormatter e depois sobrecarregar os métodos FormatData, InspectorType e TypeName do objeto. Em seguida, chame o objeto CSObjectManager do gerenciador de objetos CodeSite para registrar a nova subclasse TCSFormatter. Além disso, também precisamos chamar o método RegisterCustomFormat para registrar um novo tipo de mensagem. A seguir está um exemplo de aplicação prática. Um formatador customizado do tipo de registro TCSEmployeeRecord é implementado na unidade CSEmployee.pas: a interface da unidade CSEmployee usa Windows, Graphics, CSIntf; , na seção Usos adiciona uma referência à unidade CSIntf. A segunda etapa é definir novas constantes de tipo de mensagem CodeSite para cada formatador. Acima, definimos duas constantes. Observe que as constantes devem ser maiores que csmUser, mas não maiores que 32.000. tipo TCSEmployee = registro Sobrenome: string; DatadeContrato: DataDeFérias: NúmeroInteger; Boolean; end; O registro acima é o tipo de dados personalizado que queremos enviar. TCSEmployeeSummaryFormatter = classe (TCSFormatter) função pública InspectorType: substituição de TCSInspector; função TypeName: substituição de string; Acima estão as definições de duas classes de formatadores personalizados. O primeiro formatador formatará o registro TCSEmployee em um formato de texto e o segundo formatador formatará o registro TCSEmployee em um estilo de grade. implementação usa SysUtils {========================================} {= = Métodos TCSEmployeeSummaryFormatter ==} {============================================} função TCSEmployeeSummaryFormatter .InspectorType: TCSInspectorType; início Resultado: = itStockStringList; A primeira etapa na implementação de um formatador personalizado é determinar qual tipo de visualizador integrado será usado para visualizar os dados formatados. Nesse caso, um visualizador de lista de strings é usado. O tipo de visualizador será usado pelo método FormatData. procedimento TCSEmployeeSummaryFormatter.FormatData( var Dados ); var EmpRec: TCSEmployee; começar EmpRec := TCSEmployee( Dados ); ', ' + EmpRec.State + ' ' + EmpRec.ZipCode ); AddLine( '' ); AddLine( 'Telefone: ' + EmpRec.PhoneNumber ); m', [ EmpRec.Salary ] ) ); AddLine( '' ); ' + IntToStr( EmpRec.VacationDays ) ); AddLine( 'Dias de doença: ' + IntToStr( EmpRec.SickDays ) ); if EmpRec.Manager então AddLine( 'Gerente: Sim' ) else AddLine( 'Gerente: Não' ); ; O método FormatData é a parte principal. Observe que o parâmetro Data passado para o método FormatData é um parâmetro de variável não digitado. Isso significa que este parâmetro pode ser de qualquer tipo de dados. Através do processo de registro de formato, podemos garantir que o tipo forçado seja mapeado para um registro de dados personalizado sem erros de conversão. Após converter o tipo de dados, podemos formatar os dados. Aqui usamos o método AddLine da classe base TCSFormatter para adicionar linhas divisórias entre strings para formatação. function TCSEmployeeSummaryFormatter.TypeName: string; begin Result := 'TCSEmployee'; {========================================} {== Métodos TCSEmployeeDetailsFormatter == } {=======================================} função TCSEmployeeDetailsFormatter.InspectorType: TCSInspectorType ; início Resultado := itStockGrid; Para o formatador de detalhes de funcionários, o visualizador de grade nomeado será usado para visualizar os dados: procedimento TCSEmployeeDetailsFormatter.FormatData( var Data ); ; AddNameValuePair( 'Nome', EmpRec.Nome); AddNameValuePair( 'Endereço', EmpRec.Address ); AddNameValuePair( 'Cidade', EmpRec.ZipCode ); EmpRec.PhoneNumber ); 'HireDate', EmpRec.HireDate ); AddNameValuePair( 'Salário', Format( '%m', [ EmpRec.Salary ] ) ); ); AddNameValuePair('Gerente', EmpRec.Manager ); end; Aqui para formatar os dados no visualizador de grade, usamos o método AddNameValuePair. function TCSEmployeeDetailsFormatter.TypeName: string; begin Result := 'TCSEmployee' end; Os dois procedimentos a seguir são usados para encapsular chamadas para o método SendCustomData. =============} {== Métodos de suporte ==} {======================} procedimento CSSendEmployeeSummary ( const Mensagem: string; EmpRec: TCSEmployee ); início CodeSite.SendCustomData( csmEmployeeSummary, Msg, EmpRec ); fim do procedimento CSSendEmployeeDetails( const Msg: string; EmpRec: TCSEmployee ); Por fim, não se esqueça de chamar o método CSObjectManager.RegisterCustomFormatter para registrar o formatador no CodeSite Object Manager. inicialização CSObjectManager.RegisterCustomFormatter( csmEmployeeSummary, TCSEmployeeSummaryFormatter );