domingo, 31 de julho de 2011

Migrando aplicativos do Delphi 5 para o 6 e 7


Neste artigo, será demonstrado como solucionar alguns problemas comumente encontrados por desenvolvedores Delphi quando fazem migração de aplicativos e componentes de versões anteriores ao Delphi 6 (mais precisamente o Delphi 5) para as versões 6 e/ou 7. O que funcionar para o Delphi 6 provavelmente funcionará para o Delphi 7, já que as mudanças mais expressivas nas bibliotecas padrões para a criação de componentes foram realizadas no Delphi6, por motivos de compatibilidade.
A Borland realizou diversas mudanças em métodos e classes nas antigas bibliotecas (VCL) em decorrência da necessidade de compatibilizar o máximo possível o Delphi 6 com o Kylix, ou em outras palavras, a biblioteca de componentes VCL (Visual Component Library) com a biblioteca inter-plataforma CLX (Component Library for Cross-Plataform), utilizada mais especificamente no Kylix (apesar da mesma ser utilizada no Delphi também).

Serão listadas a seguir as principais mudanças que conheço e que devem ajudar o leitor a migrar seus aplicativos e componentes para as versões 6 e 7 do Delphi. São estas:

* A implementação de Classes e Métodos da unit "Dsgnintf.pas" foram divididos em duas units (pelo menos até onde conheço): a DesignIntf.pas e a DesignEditors.pas. Ambas estão localizadas em ($Delphi)\Source\ToolsAPI, onde ($Delphi) é o diretório onde o Delphi está instalado. Ao invés de incluir o caminho citado em seu "Enviroment Options\Library\LibraryPath" para utilizar as units, você pode optar por colocar na seção requires (e realmente acho preferível isto se estiver trabalhando com pacotes) o pacote "designide.dcp", localizado na pasta ($Delphi)\Lib. Ele já inclui estas bibliotecas e outras comumente utilizadas além de uma nova interface, a IComponentDesigner, contida em ComponentDesigner.pas.

* A procedure EditProperty da classe TDefaultEditor teve seus parâmetros alterados; no Delphi 5, a mesma era declarada desta forma:

  EditProperty(PropertyEditor: TPropertyEditor; var Continue, FreeEditor: Boolean); virtual;

e agora a mesma é declarada assim:

  procedure EditProperty(const Prop: IProperty; var Continue: Boolean); virtual;

Observe que o parâmetro PropertyEditor do tipo classe TPropertyEditor passou agora a se chamar Prop e ser do tipo interface IProperty e, o parâmetro FreeEditor deixou de existir. Essa nova implementação é realizada na unit "DesignEditors.pas".

* As rotinas de manipulação de objetos ou variáveis do tipo Variant passaram da unit System.pas para uma unit própria, a Variants.pas.

* Interfaces como a IFormDesigner , IDesignerSelection e IdesignerSelection sofreram alterações. Quanto as duas primeiras, as mudanças são respectivamente estas: mudança de nome para "IDesigner" e a adição de uma função GET que retorna um TPersistentequando indicado o índice do seu membro. Exemplo:

Nas versões anteriores ao Delphi 6, se você quisesse usar o TPersistent de um objeto, deveria escrever:

  var p: TPersistent;
  ...
  P := Selections[i] as TPersistent;

Agora basta escrever:

  var p: TPersistent;
  ...
  P := Selections.get[i];

* A função CollectionsEqual implementada na Unit Classes.pas teve seus parâmetros alterados; no Delphi 5, a mesma era declarada desta forma:

  function CollectionsEqual(C1, C2: Tcollection): Boolean;

e agora a mesma é declarada assim:

  function CollectionsEqual(C1, C2: TCollection; Owner1, Owner2: TComponent): Boolean;

* As constantes que estavam na unidade DesignConsts.pas, foram colocadas juntamente com os menus em DesignMenus.pas.

Dicas

Para aproveitar um mesmo código-fonte em diferentes versões do Delphi, você pode utilizar a diretiva de compilação {$IFDEF name}, que especifica que um determinado bloco de código compreendido pela cláusula só será compilado se o parâmetro "name" estiver definido.

Parâmetros de versão

  Delphi3 - VER80;
  Delphi5 - VER130;
  Delphi6 - VER140;
  Delphi7 - Ver150;

Como utilizar

Exemplo1:
No caso de um código que referencie a DsgnIntf.pas e seja utilizado no Delphi 6 ou posterior, você pode fazer o seguinte:

uses
  Windows, Messages, SysUtils, Classes, Graphics,
  {$IFDEF VER130} // se for Delphi5
    DsgnIntf
  {$ELSE}
    {$IFDEF VER140} // se for Delphi6
      DesignIntf, DesignEditors
    {$ELSE}
      {$IFDEF VER150} // se for Delphi7
        DesignIntf, DesignEditors
      {$ENDIF}
    {$ENDIF}
  {$ENDIF}

Observação: No lugar de você colocará o caractere adequado, "," para continuar a declaração de Units ou ";" para fechamento de declaração.

Exemplo 2:
No caso de um código que referencie a System.pas e seja utilizado no Delphi 6 ou posterior, você pode fazer o seguinte:

uses
  Windows, Messages, SysUtils, Classes, Graphics, System,
  {$IFDEF VER140} // se for Delphi6
    Variants
  {$ELSE}
    {$IFDEF VER150} // se for Delphi7
       Variants
    {$ENDIF}
  {$ENDIF}

Bem, desejo que isto possa ajudar todos aqueles que trabalhem com Delphi, seja usuário iniciante, intermediário ou avançado.