Pesquisar

quinta-feira, 11 de março de 2021

O que significa a propriedade Handle que alguns componentes possui?

    Primeiro vamos entender o que é um Handle no Windows.

    Handle é um índice atribuído para cada componente que o SO pode manipula, por exemplo, uma janela, um arquivo, um driver, uma porta seria ou USB, alguns componentes de tecla, absolutamente TUDO que o SO pode manipular possui seu índice (Handle), que nada mais é do que um inteiro de 32 ou 64 bits (dependendo da arquitetura do SO).

    O Handle sozinho nada pode fazer sem a utilização da API do SO.

    Muito bem, agora definido o que é um Handle, vamos definir algumas coisas sobre a VCL.

    Já sabemos o que é a VCL, é a biblioteca de componentes visuais do Delphi. Na hierarquia dos componentes temos a seguinte estrutura:

 

    TObject ->  TPersistent -> TComponent -> TControl

 

    Todos os componentes da VCL possuem TControl em sua herança, então podemos assumir que todos os componentes visuais primordialmente são herdados de TControl.

    Muito bem, neste ponto, o que deve ficar bem claro é que cada componente que precise ser desenhado na tela deve herdar de TControl (o que não nos impede de herdar de algum componente mais a frente da hierarquia, como um TEdit, TButton ou TLabel).

    No entanto, a VCL neste ponto possui dois grandes troncos de herança:

    TGraphicControl e TWinControl

    Como mostra a imagem abaixo:



    Como vocês podem perceber, o tronco TWinControl possui os componentes mais utilizados, TButton, TEdit, TListBox, etc...
    O TWinControl representam os componentes que são criados e podem ser manipulados pelo SO (Windows). Os componentes TButton, TEdit e outros são de criação exclusiva do SO, e como esses componentes podem ser manipulados (criados e destruídos) pelo SO, eles devem possuir um Handle.

    Mas ainda existem componentes que não possuem Handle, como por exemplo o TImage e TLabel, isso ocorre porque a VCL possui o tronco chamado TGraphicControl que são componentes criados especificamente por ela, o SO não tem como interferir no funcionamento (manipulador de eventos nem de destruição e muito menos criação) destes componentes.

    Inclusive, a melhor maneira de entender a utilização do handle no delphi, é entendendo como funciona o sistema de mensageria do Windows.

    Tudo no Windows é notificado através de mensagens, é através de mensagens que um componentes da VCL sabe que foi clicado, que alguma tecla foi pressionada, ou se o componente deve ser ou não redesenhado na tela.

    Por exemplo, se queremos simular um click em um TButton, utilizamos a função da API do windows chamada SendMessage (também podemos utilizar a PostMessage, mas entrarei nisso com mais detalhes em outra postagem).

    Ex: Queremos que determinado componente receba a mensagem de passar para o próximo controle, sem que a gente tecle <Tab> no teclado, podemos enviar uma mensagem pra isso.

    SendMessage(Edit1.handle, WM_NEXTDLGCTL, 0, 0);

    Como vocês perceberam, dizemos ao SO que  do Edti1, ele colocar o foco no próximo componente, isso é bem comum quando queremos trocar o <Tab> por <Enter> em um edit.

    E é neste ponto que vemos a importância do Handle, como se nota na função, em vez de passarmos o componente, passamos apenas o Handle do mesmo e junto com ele, a mensagem de pular para o próximo controle.

    Agora vamos supor que tenhamos que mandar uma mensagem de redesenho para um TLabel. Como vimos anteriormente, este é um componente herdado de TGraphControl, portanto ele não é controlado pelo SO, e sim pela VCL, então como mandamos uma msg pra ele? Simples, todos os componentes TControl (TWinControl e TGraphControl) possui uma função chamada Perform, onde simulamos um envio de uma msg para eles.

    Ex:

        Label.Perform(WM_PAINT, 0, 0);

    Desse modo dizemos a VCL que queremos que o componente deve ser redesenhado em seu DC (Device Context e não os heróis dos filmes :) ).


    Espero ter ajudado um pouco a todos a entender um pouco mais sobre o funcionamento do Handle.


    Abraço a todos!

quarta-feira, 16 de dezembro de 2020

Os Segredos de TStringList - Parte 2

Boa noite meus amigos.

Vamos hoje explorar mais alguns recursos desse objeto, o TStringList.

Como eu havia dito no post Parte 1, o StringList é uma das classes mais versáteis do Delphi, vamos agora conhecer alguns de seus recursos.

LoadFromFile e SaveToFile

Quantas vezes ja necessitamos realizar a leitura de um arquivo qualquer no disco, para verificarmos seu conteúdo ou algo do gênero?
O StringList vem em nosso socorro com um método extremamente fácil de usar. LoadFromFile e SaveToFile.

O quão fácil é utilizar este recurso?

procedure TForm2.btn2Click(Sender: TObject);
var
  lStringList: TStringList;
begin
  lStringList:= TStringList.Create;

  lStringList.LoadFromFile('C:\Temp.txt');

end;

Sim, fácil assim, depois dessa linha, o objeto lStringList ja terá todo o conteúdo do arquivo texto contido em "C:\Temp.txt", e pode ser manipulado como quiser através da propriedade Text do componente.

O mesmo vale para a escrita do conteúdo da StringList para o arquivo.

  lStringList.SaveToFile('C:\Temp.txt');

Mais fácil realmente impossível, apenas com esses 2 métodos ja é possível criar um pequeno bloco de notas.
Lembrando ainda que o componente TMemo ja vem com um descendente deste objeto embutido disfarçado com o nome de "Lines". Então, para popularmos um TMemo com o conteúdo de um arquivo basta simplesmente utilizarmos a propriedade "Lines" do TMemo do seguinte modo:

  Memo1.Lines.LoadFromFile('C:\Temp.txt');

E para salvar o conteúdo:

  Memo1.Lines.SaveToFile('C:\Temp.txt');

Desse modo, com apenas 2 componentes temos um bloco de notas bem rudimentar mas utilizável.

Claro que tanto os métodos LoadFromFile quanto o SaveToFile, são recomendados para arquivos com até o máximo de 10mb de tamanho (claro que depende do PC), caso o contrário essa pode ser uma operação bem demorada. Para arquivos maiores, recomenda-se utilizar as funções de manipulação de arquivos do próprio Delphi (AssignFile, CloseFile, etc...).

Split String

Agora vamos supor que você queira montar uma lista de palavras separadas por vírgula, que não se sabe a quantidade. Como por exemplo uma lista de fields de um dataset para a montagem de um SELEC.

Provavelmente teríamos um código parecido com este:

var
  Count: integer;
  lListaDeCampos: string;
begin

  for Count := 0 to Pred(dsCliente.Fields.Count) do
  lListaDeCampos:= lListaDeCampos + DataSetCliente.Fields[Count].FieldName + ',';

  //Remover último caractere
  lListaDeCampos:= Copy(lListaDeCampos,1,length(lListaDeCampos)-2);
  ShowMessage(lListaDeCampos)
end;

Isso funciona muito bem, porem o StringList possui uma solução bem mais elegante:

var
  Count: integer;
  lListaDeCampos: TStringList;
begin
  lListaDeCampos:= TStringList.create;

  for Count := 0 to Pred(dsCliente.Fields.Count) do
    lListaDeCampos.Add(DataSetCliente.Fields[Count].FieldName);

  ShowMessage(lListaDeCampos.DelimitedText);
end;

Como podem ver, com a utilização da classe TStringList, o código fica bem mais elegante e muito mais legível.

Leituras de Chave - Valor (Semelhante a arquivos INI)

Embora o Delphi possua um excelente mecanismo de leitura e escrita de arquivos INI (classe TIniFile), ainda podemos utilizar o TStringList para realizarmos essa tarefa de forma básica.

Vamos supor que exista um arquivo INI com o seguinte conteúdo:

[EMPLOYEE]
DriverID=IB
Protocol=TCPIP
Database=localhost:C:\examples\database\employee.gdb
User_Name=sysdba
Password=masterkey
CharacterSet=UTF-8
ExtendedMetadata=True


Utilizando o TStringList, após fazermos a carga do arquivo com "LoadFromFile" é muito fácil obtermos qualquer valor utilizando a propriedade "Values" do objeto, onde simplesmente passamos a chave para obtermos o valor.

Ex:

ShowMessage(lStringList.Values['DriverID']); //Retorna "IB"
ShowMessage(lStringList.Values['Protocol']); //Retorna "TCPIP"
ShowMessage(lStringList.Values['User_Name']); //Retorna "sysdba"
... Tenho certeza que ja entenderam... :)

Realmente muito simples não é, podemos inclusive adicionar ou substituir valores ao arquivo:

//Adicionando a chave "Transaction" com o valor "S"
lStringList.Values['Transaction']:= 'S';

O trecho acima é o mesmo que:

lStringList.Add('Transaction=S');

Claro que neste último caso a chave valor será adicionada ao final do arquivo, sem realizarmos a verificação se ela ja existe ou não.
Obviamente, após adicionarmos a chave com qualquer um desses métodos, o arquivo deve ser salvo com o método "SaveToFile" para ser persistido no disco.

Ainda é necessário mencionar que este modo de leitura não considera repetições de chaves, trazendo sempre a primeira ocorrência da chave na lista e ignorando as repetições.
Também vale lembrar que não é possível setorizar as informações, pois o TStringList não possui um mecanismo de busca setorizada (utilização de "SECTIONS" no arquivo, para isto utilize a classe específica de leitura de arquivos INI, a TIniFile).

NOTA SOBRE ESTE TIPO DE UTILIZAÇÃO: Por debaixo dos panos, o TStringList executa a pesquisa de chave percorrendo todos os itens, procurando o separador dentro de cada item e comparando a parte do nome com a chave fornecida. Não é preciso dizer que ele causa um grande impacto no desempenho, então esse mecanismo só deve ser usado em lugares não críticos e raramente repetidos(como na carga do sistema, onde o procedimento sera realizado apenas uma vez durante todo o ciclo de execução da aplicação). Nos casos em que o desempenho é importante, deve-se usar TDictionary <TKey, TValue> de System.Generics.Collections que implementa a pesquisa binária.


Conclusão

Claro que todos estes exemplos são meramente ilustrativo, pois não realizamos a liberação do objeto na memória utilizando o método correto (.free).
Pelo que vimos não nos resta dúvidas sobre a utilização desta classe muito versátil do TStringList.

Obrigado a todos pela atenção e espero ter ajudado.
Grande abraço!!

quinta-feira, 12 de novembro de 2020

Strings no Delphi

    Ao longo da vida do Delphi, em todas a idas e vindas, Borland, Code Gear e Embarcadero, o Delphi já utilizou alguns tipos de strings, vamos explorar brevemente esses tipos.

    Delphi 1 - String é um alias para ShortString (tamanho máximo de até 255);

    Delphi 2 até Delphi 2007 - String é um alias para AnsiString (tamanho máximo de até 2Gb);

    Delphi 2009 até hoje - String é um alias para UnicodeString (virtualmente sem tamanho, porem, por causa da codificação ocupa o dobro do tamanho);

Todas estas variantes de strings ainda estão disponíveis no Delphi 10.4 e podem ser utilizada.

Diferença básica entre os tipos:


ShortString

Nada mais é do que um ponteiro de caracteres, herdado do turbo pascal (Borland), o compilador pré aloca 256 caracteres para este tipo de dados, mesmo que seja utilizado menos que isso. Ou seja, sempre é ocupado 256 bytes;

É possível especificar o tamanho máximo para estas strings, porem esse valor não pode ultrapassar 255;

Ex:

  var

    lTemp1: string[50];  //Pré aloca 51 bytes, 50 para utilização e 1 byte de controle.

    lTemp2: string[256]; //Erro, o tamanho máximo é de 255 mais 1 de controle, então a declaração de uma shortstring de 256 bytes não é possível.

    lTemp3: shortstring; //Pré aloca 256 bytes, 255 para utilização e 1 de controle.

Toda a estrutura de dados do tipo ShortString é armazenado na memória stack, tornado a velocidade de acesso a esse tipo de estrutura extremamente rápido, porem com a atual velocidade dos processadores e acesso a memória, esta velocidade simplesmente não é percebido até mesmo por computadores mais antigos. No entanto, se vc for utilizar alguma estrutura de dados em que seja necessário repetir algumas milhares de vezes uma string, talvez valha a pena avaliar a utilização deste tipo;


AnsiString (Também conhecida como Long String)

    Na versão 2 do Delphi, a Borland introduziu a AnsiString, um tipo melhorado de ShortString, mas com algumas diferenças significativas.

    Agora era possível utilizar strings com o tamanho de até 2Gb de tamanho. Além disso, o Delphi agora era capaz de alocar uma quantidade de memória mais condizente com sua utilização. A alocação dinâmica era possível com este tipo de dado que utilizava um NULL TERMINATOR para identificar o final da string e não apenas um payload de tamanho no início da estrutura de dados.

    Foi introduzido tb um contador de referencia, para que strings iguais não se repetissem. Tornado assim o AnsiString um tipo de dado extremamente versátil de ser utilizado.

Ex:

  var

    lTemp1: AnsiString;

    lTemp2: AnsiString;

  begin 

    lTemp1:= 'Teste';

    lTemp2:= lTemp1; //Neste momento, o contador de referencia para a string é incrementado e a string não é copiáda, mas referenciada em lTemp2;

    //Caso o valor das string 'Teste' seja alterado em qualquer uma das variáveis, o compilador realiza uma cópia da mesma e o contador de referencia será decrementado, isso de forma totalmente transparente ao programador.

  end;

    Por muito tempo esta foi a utilização padrão do delphi, e muitas DLLs foram criadas com este padrão de string.

    O ponteiro de uma string local sempre aponta para a memória de acesso rápido (stack), mas o conteúdo da string, geralmente aponta para a memória mais lenta, a heap.


WideString

    Este tipo de dado é muito semelhante a AnsiString, porem foi criado para manter a compatibilidade com funções que era utilizada com Windows 64.

    Ele se comporta do mesmo modo que o AnsiString, no entanto os caracteres são unicode, ocupando o dobro do tamanho de espaço.


UnicodeString

    É o tipo padrão de string utilizado pelo Delphi desde a sua versão 2009. Para todos os efeitos funciona como a AnsiString, mas sem a limitação dos 2Gb e ainda é unicode. Geralmente utiliza a codificação UTF-16, mas pode ser configurada para utilizar a codificação UTF-8.

    A alteração do tipo string de AnsiString para UnicodeString ocasionou um rebuliço na comunidade, pois várias bibliotecas deixaram de manter a compatibilidade. O melhor exemplo disso é a carga de DLL que utilizava o padrão AnsiString (DLLs criadas em Delphi 7 em sua maioria) em versão mais novas do Delphi (2009 e superior). Claro que a solução era a tipagem correta na chamada dessas DLLs, mas como isso nunca havia ocorrido, muito poucos programadores tiveram essa visão.


Resumo

    AnsiString: string composta por caracteres ASCII. Cada Char possui exatamente 1 bytes. Um ponteiro para uma AnsiString (^AnsiString) equivale a char* em C;

    WideString: existe apenas por compatibilidade com o Windows. Cada Char possui 2 bytes, e deve ser utilizada em funções da Win32 com parâmetros LPWSTR, realizando um cast para PWChar;

    UnicodeString: string unicode. Por padrão UTF-16 (ou pelo menos era quando pesquisei pela última vez), mas pode assumir outras codificações, como UTF-8.

    ShortString: equivale a string antiga do Pascal, com sua limitação de de 255 caracteres.

    String: nas versões mais novas do Delphi (2009 em diante), equivale a UnicodeString. Antigamente equivalia a AnsiString.

    Tanto AnsiString quanto UnicodeString são mais do que um simples "array of Char", sendo que elas possuem informações de página de código e tamanho. Porém, para facilitar o cast destes tipos para PChar e suas variações, estas informações ficam nos endereços anteriores ao retornado pelo operador @.


Conversão

    A conversão entre elas é feita automaticamente. Único cuidado que deve ser tomado, é que dados podem ser perdidos durante a conversão devido ao tipo não suportar alguma característica da string de origem, gerando assim um "Warning" no compilador.

    O compilador ainda pode fazer um cast implícito para o tipo adequado, mas isso também gera um "Warning" no compilador.

    Por exemplo, converter UnicodeString para AnsiString, pode haver perda devido aos caracteres Unicode poderem ocupar mais que 1 byte.

    Conversão de AnsiString (ou UnicodeString) para ShortString, haverá perda de dados se a string de origem for maior que 255 (Length(origem) > 255).


Conclusão

    Não sou um especialista em strings de Delphi, e tentei explicar brevemente como o mecanismo de escrita de strings funciona. Por óbvio que existe muito mais coisa por traz de um tipo complexo como a strings, mas espero ter ajudado minimanete o leitor a resolver possíveis problemas de compatibilidade que podem aparecer na vida do developer.

domingo, 14 de junho de 2020

Criação de Logs em aplicações Delphi e um pouco sobre Seções Crítica (TCriticalSection)

Bom dia a todos...

Tenho observado que alguns desenvolvedores ainda possuem dúvidas na criação de logs em seus aplicativos.

Neste post, objetivo mostrar como é extremamente fácil a criação desse recurso em aplicações delphi.
Embora os exemples sejam referentes a VCL, não existe um motivo prático para que os mesmos não funcionem em FMX (tanto em android, iOS ou qualquer outra tecnologia que a Embarcadero deva disponibilizar).

Bom, mãos a obra!

Primeiramente clone o meu repositório de exemplos la do GitHub (https://github.com/maicodalri/delphi_samples), mais precisamente a pasta "ThreadAndFileTextLog"!

Este exemplo aborta tanto a criação de Logs quando o uso de Threads (provavelmente a minha próxima postagem sera relacionado a elas).

Existem literalmente centenas de modos de escrevermos logs em aplicações, neste exemplo vou abordar a criação de logs em arquivos texto, pois acredito que seja um dos mais simples.

Eu gosto de organizar meus códigos em arquivos e classes estáticas separados, para que possam ser utilizado em outras aplicações, compartilhando o código. Por esse motivo na unit "MyUtils.FileTextLogp.pas" existe uma classe estática chamada  "TFileTextLog "!

Ela é a responsável por escrever o log no arquivo. Um dos benefícios de utilizar classes estáticas é que podemos organizar o código de modo a entender na prática como tudo funciona.

Já que a classe possui apenas 3 métodos, vamos agora comentar cada um deles:

class constructor ClassCreate;

Esse é o construtor estático da classe, observem que no início da declaração existe a palavra reservada "class", que indica é isso é o método estático da classe e não do objeto (como se trata de uma classe estática, não é necessário instanciá-la para usá-la).

Observem também que o nome ClassCreate não precisa ser este, assim como um construtor normal, ele pode ser absolutamente qualquer coisa, poderia ser "class constructor Xurumela" que funcionaria do mesmo modo, mas eu deixo ele como ClassCreate por questão de entendimento e organização.

Lembrando que construtores de classes são executados mesmo antes do "begin" la do ".dpr", ou seja, antes do código da aplicação iniciar. Isso é importante caso necessitemos realizar algum processo para utilizar em nossas classes estáticas.

Neste nosso exemplo, é executado apenas um comnado: 
"TFileTextLog.FCriticalSection:= TCriticalSection.Create;"

A criação de uma seção crítica na nossa variável da classe "TFileTextLog.FCriticalSection". Daqui a pouco explico um pouco mais sobre isso.

class destructor ClassDestroy;

O destrutor é exatamente o contrário do nosso "class create", é o código que deve ser executado após o encerramento da nossa aplicação, para que não haja vazamentos de memória.
De novo, eu poderia ter escolhido qualquer nome, mas deixei o nome de "ClassDestroy" para melhor organização e entendimento.

Novamente, neste trecho apenas liberamos o objeto já criado no "class construtor":
"TFileTextLog.FCriticalSection.Free;"

Outro fato importante referente aos construtores e destrutores de classes é que eles ocorrem antes do "initialization" e "finalization" de todas as units! E também ocorrem na ordem em que são declarados no arquivo do projeto (.dpr).

class procedure WriteLog(const lText: string);

Aqui fica a cereja do bolo! É onde de fato ocorre a gravação das informações seja la onde for mais interessaste para vocês, com eu ja havia dito, neste exemplos vamos criar um log em arquivo texto.

Existem basicamente 2 métodos de Ler/Escrever em arquivos texto no delphi de modo muito fácil, utilizando o objeto StringList ou escrevendo diretamente no arquivo via SO.

Pela velocidade, visto que esse log deve ser rápido e muito leve, optei por não utilizar o objeto StringlList, assumindo para mim mesmo a responsabilidade de travar o arquivo no SO e libera-lo quando terminar de utiliza-lo.

Vamos ao código:

 var  
  lFileLogName: string;  
  lFile: TextFile;  
 begin  

  //Entrado na seção cítica 
  TFileTextLog.FCriticalSection.Enter;  

  try //Bloco protegido

    //Definindo o nome do arquivo que sera gravado, sempre atribuo o arquivo de log
    // o mesmo nome do EXE só que com a extensão LOG
    lFileLogName:= ChangeFileExt(ParamStr(0), '.log');  

    //Vinculo a variável lFile ao nome do arquivo, basicamente eu obtenho um ID (handle)
    // do SO para este arquivo
    AssignFile(lFile, lFileLogName);
   
    //Crio outro bloco protegido para fazer a liberação do arquivo para o SO
    try
      //Verifico se o arquivo ja existe 
    if not FileExists(lFileLogName) then
     Rewrite(lFile) //Se não existe, então cria e abre o arquivo para edição
    else  
     Append(lFile); //Senão apenas abro o arquivo que ja existe para edução

    //Simplesmente escrevo a linha desejada no final do arquivo
    WriteLn(lFile, FormatDateTime('dd/mm/yyyy hh:mm:ss:zzz', Now) + ' => ' + lText);

    finally  

      //Fecho o aquivo, informo ao SO que não sera mais utilizado (desbloqueio ele) 
    CloseFile(lFile);

    end;  

  finally

   //Libero a seção crítica
   TFileTextLog.FCriticalSection.Release;  

  end;  

 end;
Para utilizarmos o método basta escrevermos:

TFileTextLog.WriteLog('Informação que desejamos gravar');

Isso mesmo, sem a necessidade de criarmos objetos, como é uma classe estática, basta eu simplesmente escrever o nome da classe e chamar o métodos.

Um pouco sobre Seções Críticas

Neste exemplo, como puderam perceber, utilizei uma classe nativa do delphi chamada TCriticalSection da unit System.SyncObjs.

Basicamente, uma seção crítica funcionam como um portão onde o processamento só pode entrar no bloco protegido se o processamento anterior já concluiu sua execução.

Neste nosso exemplo, como utilizamos Thread, não ha como garantir que se uma Thread chamar o nosso método WriteLog sem que outra Thread no mesmo momento já esteja escrevendo o Log.

Imagine que quando abrimos o arquivo para edição com o comando "Append" ou "Rewrite", outra Thread também pode tentar realizar o mesmo processo, a segunda Thread recebera um aviso do SO dizendo que o arquivo já esta em uso, e o delphi ira nos reportar uma exceção (Exception).

A função da seção crítica garante que apenas um processo ira ocorrer no bloco protegido por fez, ou seja, o arquivo só sera aberto para escrita se outro processo já o fechou.

Claro, que o exemplo aqui é utilizado com a abertura de um arquivo texto, mas pode ser referente a qualquer acesso a recurso do sistema que não possa ser interrompido, como por exemplo a consulta em um banco de dados, ou a leitura de alguma porta física do equipamento, absolutamente qualquer coisa neste sentido.

Outro ponto importante sobre seções críticas é que SEMPRE o bloco protegido deve estar entre um TRY e FINALLY, pois caso ocorra algum problema não previsto, a seção crítica ficar literalmente pendurada, e nenhum outro processamento terá acesso ao código protegido, na prática isso dará a impressão de que a aplicação ficou travada.

Algo parecido que fiz com a abertura do arquivo, logo a pós a abertura do arquivo, existe um TRY para proteger o código e depois de utilizado existe um FINALLY, garantindo que não importa o que acontecer, o arquivo, sera liberado para o SO (CloseFile).

Espero que os comentários sejam suficientes para que todos entendam o código, qualquer dúvida, por favor não deixem de comentar que eu assim que possível responda.

Espero que essas informações seja úteis a vocês.

sábado, 13 de junho de 2020

Repositório de Exemplos Delphi

Boa noite a todos...

Depois de quase 5 anos da minha última postagem, estou aqui para informar que estou montando um repositório no GitHub de exemplos que eu realmente acho útil...

Desejo pelo menos criar exemplos mensais, os exemplos são bem práticos e objetivos.

Ja deixei la o primeiro exemplo, onde crio threads e criação de logs em arquivo texto.

Em breve devo escrever uma postagem explicando o exemplo.

Abraço a todos!

Meu repositório de exemplos:
https://github.com/maicodalri/delphi_samples

Canal da Aquasoft no YouTube:
https://www.youtube.com/channel/UCwrdLw9wVt3ls9WCgy5Bc2A

terça-feira, 28 de abril de 2015

FixInsight - Ferramenta para análise de código Delphi

Buenas, Delpheiros...

 Fizemos um review da ferramenta  de um desenvolvedor MVP Embardadero, RomanYankovsky.
Vale a pena dar uma olhada nessa ferramenta(FixInsight) para análise de código fonte e integração contínua.

Abraço e até a próxima!.

sexta-feira, 10 de abril de 2015

RADStudio XE8

Lambda, lambda, lambda... delpheiros!!!!

Nova versão da ferramenta disponível(Trial) e recheado de novidades...

Nesse link podemos ver tudo que há de novo no nosso bom e velho Delphi..

Ah, o Delphi "morreu", lembram? E aqui está a prova disso: